Open PhrozenByte opened 8 years ago
I have idea on how to make pages more flexible - in other words, having "custom page types" based on XML schema file (or YAML, maybe?) in content directory without writing specific meta data into every .md file.
This would make Pico more CMS-like and structured, so for example, if someone would like to have "blog" or "products" type of pages, each containing alot of "child pages" (subpages), he should create XML schema file called "blogposts.xml", which contains info/data describing how subpages should behave, like order of pages, pagination count etc. and any pages associated with schema put into subfolder in content directory. This would probably branch content directory structure into several subfolders for specific page type so structure would be something like "default" - for default pages, "posts" - for blog posts or any other page types. Index pages for those page types could also contain page loop/query of all of its child pages - just like blog has, similar to Wordpress but still being simple.
Also, maybe having another XML file for post categories which would contain something like page IDs under specific category section ("Animals", for example) and when category URL is requested, category page would do the loop and display all pages associated with this category page.
I think this would be possible but would require to rewrite core Pico files, since creating Blog plugin alone would not have access to way/order pages are displayed since Pico searches folders recursively for .md files in content directory.
This would increase complexity of Pico but it would be a welcome feature which could possibly draw more people to use Pico for their website, especially those having smaller blog dedicated to specific subject, like personal travel blog, for example.
Thank you for your feedback @Crank1d! :+1:
I did not really understand what data you're suggesting to store in these XML files. Pico leaves page presentation (i.e. how a page in a specific folder (e.g. blog
) looks an behaves) completely up to themes. For example, @smcdougall's NotePaper theme interprets content files differently based on YAML headers (e.g. NotePaper's widget feature or blog articles). NotePaper specifically also allows you to set a Tag
meta header and lists all pages containing a specific tag (so implementing categories shouldn't be a problem either).
As far as I understand your suggestion right, Pico already allows you to do something like this - it just doesn't require you to create a separate XML file, you can simply store that information in the YAML header of the content file.
Something like "Page Blueprints", implemented in GRAV - http://learn.getgrav.org/forms/blueprints
Scheme file would contain custom defined meta data for all its child pages/subpages, so there would be no need to define custom meta from plugin.
Maybe Im wrong, but Pico currently doesnt support "parent-children" relationship of pages?
As far as I understand Grav's documentation right, blueprints are about metadata for plugins and themes, not about pages. Pico has no administration backend. We're indeed working on a editor plugin for Pico 1.1 (see PhrozenByte/pico-admin
), but that's rather a "enhanced" text input field. Much more "administration backend" is in contradiction to Pico's "stupidly simple" goal (what isn't limited to the user-side, but also Pico's sourcecode).
Pico doesn't have a "parent-child" relationship of pages in the narrow sense. When it comes down to "folder-specific meta data defaults": Pico absolutely allows you to do something like this, e.g. by creating a _meta.md
file and adding its meta data to all other pages in this directory by using the onPagesLoaded
event with a very simple plugin. Apart from that, Pico leaves the directory structure completely up to the user and maybe a custom theme that interprets the directory structure to do something special (like listing all pages in categories).
OK, thanks for explanation.
Just a thought... If you wanted to add the feature sooner, it'd probably be easier to make the "static website generator" a manual process for the initial implementation. The automation (presumably the harder part) could be developed in stages afterward.
Maybe you'd want them to be two separate components anyway. A "worker" that builds the static site and an optional "watcher" daemon/process that provides the file tracking and automation. This would also allow users the freedom to decide it they wanted the extra automation or whether they'd rather rebuild manually.
Anyway, just some stray thoughts from having dealt with my odd, manual Jekyll setup.
Even if it had to be rebuilt manually each time, it might get Pico to a state where you'd want to use it for the website sooner. :wink:
Another random thought. Not really big enough for it's own issue.
What about having some kind of performance monitoring in Pico? I'd call it separate from the "static website generator" because it could be useful for regular, dynamic Pico sites.
Basically, I've noticed with Jekyll that whenever it rebuilds the site, it tells me how long it takes. I've noticed that certain actions (like jsonify) take a LOT longer than others. I think it would be interesting for Pico theme and plugin developers to be able to measure the impact of their actions.
It would probably be a toggle or a plugin, since it wouldn't really have a production use.
A detailed breakdown of performance timings could be cool too.
Pico Core.................................10ms
Plugin 'something_low_level.php'..........20ms
Parsedown.................................80ms
Plugin 'pagination.php'...................50ms
Twig using template 'NotePaper'..........200ms
----------------------------------------------
Total Rendering Time.....................360ms
The timings here are of course made up.
Again, just an idea I had for the future. I can make it a new issue if you'd like.
Just a thought... If you wanted to add the feature sooner, it'd probably be easier to make the "static website generator" a manual process for the initial implementation.
Actually it's already possible to use Pico as a static website generator - simply use wget -r
to recursively get a static version of the website. Whether the result is usable or not depends on what plugins have been "installed". The primary target of this feature actually is caching the HTML results to boost performance, using Pico as static website generator is just a side benefit.
The decision to use Jekyll was made before I knew about what power Travis gives us. So, if you want to do a little research whether we can use Pico 1.0 instead... That is something which I would greatly welcome. :wink: :smiley:
Maybe you'd want them to be two separate components anyway. A "worker" that builds the static site and an optional "watcher" daemon/process that provides the file tracking and automation.
I haven't thought about a concrete implementation yet. So, yeah, maybe :wink:
What about having some kind of performance monitoring in Pico?
We'll keep this in mind (I've added it to the list above), but at the moment there are some ToDos which will boost performance significantly (Markdown cache, lazy loading of pages...), so it IMHO doesn't make much sense to publish performance stats when we already know that we can do much better.
The primary target of this feature actually is caching the HTML results to boost performance, using Pico as static website generator is just a side benefit.
Yeah, I'm interested in seeing how it plays out. I've played with Nginx's caching abilities and seen my pages go from 500ms+ down to near instant loading times.
Maybe I should go write a script that wget's into a static folder on demand. :laughing:
For the performance stats, I'm more curious from a theming perspective. It would be interesting to be able to track performance changes between different ideas. If I change the way something works, and all of a sudden it's taking an extra 100ms or more, I'd know that my implementation was poor.
It would actually be kind of interesting to see how NotePaper performs next to a barebones theme. There's probably a way I could send a request to php directly from a shell, then time the response using some command line trickery. I might see what I can do if I'm every working on NotePaper. Far too busy for that at the moment though.
What is happened with the Static HTML Cache? Is this the Pico Cache plugin: https://github.com/glumb/pico_cache?
Allow PHP includes in pages please.
The Static HTML caching feature would be fantastic and probably quite convenient for a Search system to use.
What about moving to a newer version of Twig 1.x or to Twig 2.x?
Just run composer update
in your existing Pico installation (no matter whether you used a composer
-based install or one of Pico's pre-built packages) to update to the latest Twig 1.x release.
But indeed, we're planning to upgrade all of Pico's dependencies to the latest versions, including Twig 2.x, the latest release of Symfony's YAML parser and Parsedown 2.0 :smiley:
Dear Daniel,
I'm trying to create knowledge base on Pico and it cool and great solution, I like it all, except performance. When I add 3840 articles — it's nightmare, 2kb index page could load ~ 1 sec, and dances with nginx and php-fpm doesn't affect. Unfortunately, PicoTooManyPage plugin doesn't support 2.0 branch. Might you have some alpha or beta version of Pico 3.0 that making a lazy page tree?
Unfortunately I can't give you any schedule or even an idea about when this will happen, my time is very limited recently. However, I can't really see any reason why PicoTooManyPages
shouldn't work with Pico 2.0+
I've asked Bigi about PicoTooManyPages. Unfortunately, the plugin isn't adopted to Pico 2.0 and doesn't work. Anyway, waiting for new version :)
That's rather an docs issue on the plugin's side than an actual problem with the plugin :smiley:
Pico tries to maintain compatibility, even with plugins written for Pico 0.X (back to 2013). Just very few plugins actually stopped working. In your case it's simply the fact that Pico 2.0 no longer silently ignores (possibly unintentionally not working) plugins in the plugins/
directory - and stumbles over the plugin's picotmp_dummy
directory. However, that's really easy to fix. Simply create a plugins/PicoTooManyPages/
folder and put all of the plugin's files in there (i.e. giving you plugins/PicoTooManyPages/PicoTooManyPages.php
).
thank you for the advice, i'll try this way and patiency wait for a new version of Pico
Hi, I was trying Pico CMS before and had created a theme and simple deployment shellscript for Pico CMS. During this holidays (Merry Cristmas!) I finally have shared it on Github. Maybe someone will be interested
https://github.com/codeandmedia/pico_deploy - shellscript https://github.com/codeandmedia/pico_mondrian - the theme
I wrote four lines of HTML, for the first time in years, and this notification popped into my inbox. It's apparently the last Pico thread I haven't unsubscribed from. 😒
Is it a sign? Probably not. But either way, @PhrozenByte, if you take a look at this and it meets your standards, I'll volunteer to add it to the Themes page (can't be that hard to remember how... 🤔 ).
Welcome back @mayamcdougall! :confetti_ball: :smiley:
Sure, looks good, go ahead :+1:
Not sure whether this topic is still alive, but I'm going to try 😉 IMHO the 3.0 version should finally use all goods PHP7 gives us and leave support for 5.3.6 version.
Hi @PhrozenByte ,
Thanks for all the good work you are doing on Pico CMS ! I've seen the release of the alpha version of Pico 3, and it's a great news.
But, my major concern is that I need a tag functionnality... I tried to work on a plugin a long time ago (and you saw how ugly was my code, but hey, I'm not a developper and haven't any PHP basics...) ; I see there is a plugin for version 2 but why not make tags a native functionnality in Pico 3 ?
Thanks again !
Tagging is a rather basic functionality and one of the perfect examples of what can (and should) be done with plugins. The most basic tagging functionality can even be realized with pure Twig. So if there's going to be something official it will rather be a plugin. Since time is very limited I'm afraid I can't promise that :unamused:
Anyway, maybe it's a good approach to think a little about what is needed for a Twig-only approach... There should be just some rather small hurdles I assume. We'll see... :smiley:
I mean, if you want to be technical, I came up with a Twig-only tags implementation back when I wrote NotePaper. It's very basic, and I never went back to really improve it, but it might be a good starting point if you're looking to avoid writing a proper plugin.
NotePaper as a whole is kind of unmaintained at the moment. It probably still works fine on the current version of Pico, but just be aware that it hasn't been properly maintained in a bit.
Edit: You can check out the NotePaper Site for an example of the two twig-based tag widgets I wrote.
Thanks a lot for your answers ! I'll check Pico's development from time to time and I'll try to upgrade my website. Thanks again :)
Hi @PhrozenByte, i`m playing around with a new theme for my documentation website. Now it is time to make the menue and i found a lot of ways to do it. Like with the NestedPages, the Category plugins or the pages() function of pico itselfs.
But what will the (best or easiest) way to to make it fitted for pico3?
My need is a menu with all pages in their folders (without a limitation in the depth), highlighting the current page and the way through the folders from the current page to un-collapse them.
You should use Pico's new pages()
Twig function @KoljaL, it already works the same way as the new page discovery will work :rocket:
@PhrozenByte, thanks for the hint. Is there another way for nested menus than the one in this example: https://github.com/picocms/Pico/issues/383#issuecomment-295828130? As I said, I would like to have more levels.
This example isn't even utilizing the pages()
function... See http://picocms.org/in-depth/features/pages-function/
oh, now i know that there is a difference between pages and pages(). But i found only examples for the pages variable, like you wrote in the old themes, and nothing with the pages() function.
{% macro rnav(startPage, currentPage) %}
{% import _self as macros %}
{% for page in pages(startPage) %}
{% if not page.hidden and page.title %}
<li{% if page.id == currentPage.id %} class="current"{% endif %}>
<a href="{{ page.url }}">{{ page.title }}</a>
{% set childNav = macros.rnav(page.id, currentPage) %}
{% if childNav|trim %}<ul>{{ childNav }}</ul>{% endif %}
</li>
{% endif %}
{% endfor %}
{% endmacro %}
{% import _self as macros %}
{% set index = pages["index"] %}
<ul>
<li{% if index.id == current_page.id %} class="current"{% endif %}>
<a href="{{ index.url }}">{{ index.title }}</a>
</li>
{{ macros.rnav(index.id, current_page) }}
</ul>
Thank you for the example. I have already played with it and noticed that folders without "index.md" are not displayed at all. No matter whether they contain other files or subfolders. Is it correct that way?
Correct. If you wanna list them you'll have to use the page tree directly, see https://phrozenbyte.github.io/Pico/in-depth/features/page-tree/
No, it`s okay. I will put index files in every folder and do the rest in CSS. Maybe it is good to have the chance of this content possibility.
Good evening lovely Devs,
Thank you so much for this super simple CMS, I have it running as both my main site and some sites in nextcloud. Would love to send some money if it would help.
I would also like to help test and move v3 forward, I have seen the Alpine Linux 3.16 drop and that drops support for PHP7. My docker image is built on Alpine and so cant bump to 3.16 just yet, what would be most helpful in doing any testing?
FYI: have bumped my image to PHP8.1 and using the v3 alpha build, no errors seen. Buts its a very simple site.
I think it would be nice to integrate ActivityPub into PicoCMS? Maybe offering a plugin?
So far, to write blog that integrate within the fediverse through ActivityPub, there is only https://writefreely.org (no theming possible and versy difficult to install) or thanks to this wordpress plugin https://wordpress.org/plugins/activitypub/ .
This is really basic: moving user plugins/content/themes all under the content directory. I’m a fan of keeping user and system files separate. ATM, it’s pretty loosey-goosey in this regards. It would also assure several things:
o Updates are simpler (whether you hand cart them like I do or use Composer (which I have never managed to get working).
o If you don’t use Composer (which I do not having never had it work), it makes updates even simpler.
o Keeps me from having to figure out what I do and don’t need .gitignore on. Frankly, it’s enough to deal with my own stuff. Just let me go “oh, that directory is magic… don’t touch it”.
i think simplifying this to PicoCMS directory and User Content directory would clean things up significantly.
This issue is intended to collect and discuss ideas about Pico
2.03.04.0, especially on how we can make Pico's plugin system more flexible than ever. The changes are very substantial and far reaching, therefore they can't make it into the soon-to-be-released Pico2.03.0.The changes break BC, therefore they [can't make it into Pico ~~1.12.13.1, but Pico2.03.04.0](http://semver.org/).~~Features planned for Pico 2.0 can be found in #270.Feedback is appreciated! :smiley:General
\picocms\Pico
namespace and use a PSR-4 autoloader. UsePicoDeprecated
to also provide all classes in the root namespace (usingclass_alias()
), otherwise this would break all existing plugins.Pico::run()
into multiple public methods ("phases"), but still call them throughPico::run()
(init, request URL, loading contents, evaluating contents (YAML + Markdown), page discovery, page rendering (Twig)).PicoMarkdownParser
,PicoYamlParser
andPicoTemplateEngine
instead of\Parsedown
,\Symfony\Component\Yaml\Parser
and\Twig_Environment
as type hints and add appropriate wrapper classes for Parsedown, Symfony YAML and Twig, allowing one to extend/replace them completely.PicoDeprecated
, also remove v1.0+ behaviour with a notable performance impactcomposer
, but a pre-bundled releaseAllow theme developers to register meta headers and change Twig's default config (maybe using aImplemented with Pico 2.1config.yml
in the theme's dir?)pico-theme.yml
(e.g. a virtualcontact
page is added to the pages list not requiring acontact.md
with e.g.Template: contact
to exist)assets/image.jpg
) should be supported, toocontent
dir breakouts are stripped, i.e.../page
fromcontent/sub/page.md
ends up ashttps://example.com/pico/page
, whereas../../assets/index.jpg
ends up ashttps://example.com/pico/assets/index.jpg
(instead ofhttps://example.com/assets/index.jpg
)Page management
$page
arrays)ArrayAccess
; not only to maintain BC, but also to make the object's data easier to use (especially for non-experienced developers)ArrayAccess
objects and allow case insensitive keys (i.e. it no longer matters whether a meta value isTitle
ortitle
, one can always access it withTitle
,title
, or eventItLe
)title
,date
,template
andhidden
as page data; everything else (e.g.description
,author
,robots
) gets ordinary YAML metadata and can be accessed viapage.meta
page.id
andpage.url
are available at first; as soon as something else is accessed, the file's contents are read; depending on what has been accessed, Pico processes either the YAML frontmatter or the Markdown contents (i.e.$page['content']
won't be deprecated anymore).PicoPage::addDynamicValue(string $key, callable $callback)
). This also allows plugin developers to implement lazy loading for custom values.$pages
array? Probably not: plugin developers will have to differentiate both cases otherwise, what makes the whole feature a pain in the ass for them. Thus we need a conversion method, otherwise we would break all existing plugins...Traversable
,ArrayAccess
object like the pages array, see above), nothing is loaded by default.content/
(with the second level of lazy loading as elucidated above). Pages in sub-directories are accessible through achildren
key. However, the contents of directories aren't discovered until they are explicitly requested by accessing saidchildren
key.content/
dir and without any sub directory. This should heavily improve performance when a Pico instance is supposed to serve hundreds or thousands of pages.content/index.md
only, then all other pages incontent
(e.g.content/foo.md
) and sorts them alphabetically, then checks for acontent/foo/
directory and discovers all pages in it (e.g.content/foo/bar.md
), etc. and slices the just discovered pages in$pages
variable and force users to use thepages()
functionPicoDeprecated
should implement it as some magic variable to still support lazy loading (is this even possible?)pages()
function should return an object instead of an array with sortable page objects wrapping the requested page objects; the pages list object can then be sorted and set a page's respective previous and next page to the page wrapperPicoDeprecated
?ArrayObject
orArrayIterator
instead of a regular$pages
array. This allows us to convert page arrays to objects as soon as they are added.array_keys()
) won't work anymore... According to that we must pass a regular array to theonPagesLoaded
event for older plugins, otherwise we would pretty likely break many of them.PicoDeprecated
could then iterate through the$pages
array and convert them appropriately.pages()
function to useoffset
andlength
parameters instead ofdepth
,depthOffset
andoffset
; see https://github.com/picocms/Pico/issues/627#issuecomment-1117906063 and earlier commentsdepth
anddepthOffset
, but usePicoDeprecated
to inject the old function for old themeslength
todepth
- it better reflects what it does... But it's not to confuse with the "old"depth
Plugin event system
method_exists
calls are comparatively expensive compared to a simpleforeach
per event.onSinglePluginLoaded
event or a newPicoPluginInterface::getEvents()
method.AbstractPicoPlugin::handleEvent()
anyway, therefore we probably can't implement it without breaking BC one way or the other.\AbstractPicoPlugin
and\picocms\Pico\AbstractPlugin
differ in functionality (i.e. the first mentioned implements thegetEvents()
method in a BC way by examining aReflectionClass
of the plugin, or by letting\PicoPluginInterface
lack thegetEvents()
method entirely).false
on preliminary events (e.g.onContentLoading
) to prevent Pico from performing a specific processing step (Pico::run()
skipsPico::loadFileContent()
). Returningtrue
ornull
works as with Pico 1.0 and changes nothing. The subsequent event is still triggered (onContentLoaded
), but the payload variable ($rawContent
) is empty. The event is triggered with special priority on this plugin (regardless of the regular processing order), so it can set the variable before any other plugin receives the event.false
duringonMetaParsing
andonContentParsing
to load both meta data and the parsed contents from its cache.onContentLoading
(completely skipson404Content…
events) andonContentLoaded
on404ContentLoading
andon404ContentLoaded
onMetaParsing
andonMetaParsed
onContentParsing
(simulatesonContentPrepared
),onContentPrepared
andonContentParsed
onPagesLoading
(onSinglePage…
events will be simulated) andonPagesLoaded
onSinglePageLoading
(new event) andonSinglePageLoaded
onPageRendering
andonPageRendered
false
on theonRequestUrl
oronRequestFile
events to completely skip Pico's processing. The only remaining event to trigger isonOutput
(new event that is only triggered when Pico's processing is skipped) right before Pico returns$output
.false
duringonRequestFile
, bypasses Pico's processing completely and returns the cached contents duringonOutput
.New official plugins
.md
files)Cache: No
meta header to prevent pages from being cachedonConfigLoaded
to allow plugins to change their behavior when caching is requested)_
PHP's development server and) for our website rather than Jekyllwget -r
URLs
sequence meta header to support alternative URLs (like Jekyll's Redirect From plugini18n
)intl
andTwig_Extensions_Extension_Intl
content/catalog.yml
){{ data.catalog }}
).content/catalog.yml
andcontent/catalog.md
exist) is non-recursively merged into the page's meta data (i.e. into{{ pages.catalog.meta }}
). However, the YAML frontmatter takes preference and the data file can still be accessed via{{ data.catalog }}
.The same happens for all pages (non-recursive) in a directory if there's a data file with the same name as the directory (e.g._collection.yml
and_collection/
directory). You can enforce recursion for e.g._collection/subdir/
by creating_collection/subdir.yml
.Not planned anymore
Allow a single plugin to hook into Pico to basically replace YAML/Parsedown/Twig with something different. Rather than hooking into the instantiation of\Symfony\Component\Yaml\Parser
inPico::parseFileMeta()
,Pico::registerParsedown()
and/orPico::registerTwig()
, it should be possible to replace thePico::parseFileMeta()
method, thePico::prepareFileContent()
/Pico::parseFileContent()
methods (+ themarkdown
Twig filter inPicoTwigExtension
) and/or the call ofPico::$twig->render()
. Otherwise the plugin needs to re-implement the internal structures and workings of the YAML parser/Parsedown/Twig, what isn't desirable. I'm currently not sure about how this interacts with the$twig
parameter of theonPageRendering
event (maybe drop the parameter and add a newonTwigRegistered
event?). The plugin needs to be registered explicitly inconfig/config.php
to work.Example (quite a stretch):Instead of parsing Markdown, parse MediaWiki syntax.