This is a BC breaking change!
Manipulating Pico's $plugins array is a really bad idea. We've introduced the Pico::loadPlugin() method to safely load plugins at any time, however, Pico might do unexpected things when loading plugins too late. See the class docs of Pico::loadPlugin() for more details. Nevertheless, this change breaks BC to Pico 1.0. However, I don't know a single plugin that relies on manipulating the $plugins array. If you just want to load a plugin manually, use Pico::loadPlugin() instead.
Add new onPagesDiscovered event passing the unsorted pages array, move the $currentPage, $previousPage and $nextPage arguments from the onPagesLoaded event to the new onCurrentPageDiscovered event, remove the $twig argument from the onPageRendering event and rather trigger the new onTwigRegistered event for this. Also add the new onYamlParserRegistered and onParsedownRegistered events passing the YAML parser resp. the Parsedown instance. Allow plugin's to skip a page by setting the $id argument of the onSinglePageLoading event to NULL.
The vendor directory is the installation path of the `picocms/Pico` package. If `picocms/Pico` is the composer root package (as in pre-bundled releases), it should be identical to `Pico::getRootDir()`. However, if `picocms/Pico` was installed as composer dependency (e.g. by `picocms/pico-composer`), the vendor directory usually corresponds to something like `Pico::getRootDir() . "vendor/picocms/pico"`. The vendor directory is currently only used as a last resort to load Pico's sample contents.
Instead of using `*.config.php` files, use `*.yml` files to configure Pico. YAML is much easier to understand, more user friendly and (at least a bit) more error-tolerant, but still very powerful. Don't break BC by letting `PicoDeprecated` still read `config/config.php`.
Currently Pico::getTwigVariables() always returns the default twig variables and ignores all additions/changes made through the onPageRendering event. The method now returns the "real" variables array used by Twig.
Specifying a custom sort method usually means that all pages are sort by a plugin, so Pico's default alphabetical order is overwritten anyway. Letting Pico sort the pages first and discarding the result is burned CPU time...
Execution order matters: if plugin A depends on plugin B, it usually means that plugin B does stuff which plugin A requires. However, Pico loads plugins in alphabetical order, so events might get fired on plugin A before plugin B.
Hence plugins need to be sorted. Pico sorts plugins using a dependency topology, this means that it moves all plugins, on which a plugin depends, in front of that plugin. The order isn't touched apart from that, so they are still sorted alphabetically, as long as this doesn't interfere with the dependency topology. Circular dependencies are being ignored; their behavior is undefiend. Missing dependencies are being ignored until you try to enable the dependant plugin.
This method bases on [Marc J. Schmidt's Topological Sort library](https://github.com/marcj/topsort.php) in version 1.1.0, licensed under the MIT license. It uses the `ArraySort` implementation ([class `\MJS\TopSort\Implementations\ArraySort`](https://github.com/marcj/topsort.php/blob/1.1.0/src/Implementations/ArraySort.php)).
This method can be used to validate and filter input data and can be called via `Pico::getUrlParameter()` (URL GET parameters) and `Pico::getFormParameter()` (HTTP POST parameters). `Pico::filterVariable()` is basically a wrapper for PHP's `filter_var()` function with various compatibility extensions to allow theme developers to use its functionality in Twig templates. Therefore Pico 1.1 adds the `url_param` (`Pico::getUrlParameter()`) and `form_param` (`Pico::getFormParameter()`) Twig functions.
Resolves#305
\Symfony\Component\Yaml\Parser::parse() returns the unchanged value when a 1-liner string which is no valid YAML is passed. Assume this string to be the page title. Thus the following page will work now:
```
---
This is the title
---
# Example page
{{ meta.title }} is going to be "This is the title" - or "%meta.title%" == "This is the title".
```
This allows one to prevent Pico from removing the last "index" path component. Example use case: Pico's official admin plugin. We must distinguish between "content/sub.md" and "content/sub/index.md", otherwise it wouldn't be possible to edit both pages.
With Pico 1.0 you had to setup URL rewriting (e.g. using `mod_rewrite` on Apache) in a way that rewritten URLs follow the `QUERY_STRING` principles. Starting with version 1.1, Pico additionally supports the `REQUEST_URI` routing method, what allows you to simply rewrite all requests to just `index.php`. Pico then reads the requested page from the `REQUEST_URI` environment variable provided by the webserver. Please note that `QUERY_STRING` takes precedence over `REQUEST_URI`.
Symfony YAML interprets ISO-8601 datetime strings and returns timestamps instead of the string. This behavior conforms to the YAML standard, i.e. this is no bug of Symfony YAML.
Fixes#336. Thanks @csholmq for reporting this.
Resolves#330
After loading the `config/config.php`, Pico proceeds with any existing `config/*.config.php` in alphabetical order. The file order is crucial: Config values which has been set already, cannot be overwritten by a succeeding file. This is also true for arrays, i.e. when specifying `$config['test'] = array('foo' => 'bar')` in `config/a.config.php` and `$config['test'] = array('baz' => 42)` in `config/b.config.php`, `$config['test']['baz']` will be undefined
This allows developers to easily add custom query data to an page URL without the need to check enabled URL rewriting on their own. Since Twigs `link` filter is just an alias for Pico::getPageUrl(), theme designers can do the same with e.g. `{{ "index"|link("foo=bar&baz=42") }}`.
Theme designers, heads up! Don't forget that the result of the `link` filter is never escaped, so the result could contain unescaped ampersands when passing custom query data. You should pass the result to Twigs `escape` filter when using custom query data.
As pointed out by @Lomanic (see https://github.com/picocms/Pico/pull/260#issuecomment-153091890; thank you btw\!) we actually have to explain users how to change the content directory. This runs contrary to our "stupidly simple" claim. So Pico now simply uses the `content` directory when it exists...
I always thought that doing this is pretty unusual... But now it simply breaks BC - please refer to @Lomanic's [comment](https://github.com/picocms/Pico/pull/260#issuecomment-152610857). Using a return statement has no advantages, but increases the probability that something goes wrong (e.g. a clueless user removes the return statement). It was introduced with 23b90e2, but we never released it ([v0.9.1](4cb2b24fae/lib/pico.php (L188-L189))). Removing the return statement shouldn't cause any problems even for users which installed Pico in the meantime. As a result we don't break BC and moreover remove a prior BC break 😃
Why? I'm currently writing the user docs and I really have no idea how to explain this whole process in a non-technical way... It is very likely that a normal user wants to use custom tags and it would be absurd to tell him,that he should learn a programming language to do so. On the other hand, providing a copy-and-paste template makes the whole idea of explicitly registering headers worthless. The only reasonable solution is to remove the need to register headers.
Anyway, I think @PontusHorn is right to say that registering headers makes the whole system more predictable. So plugin developers are still instructed to register their meta headers during . We actually can't check and ensure this, but that's imho the best solution.