Commit graph

236 commits

Author SHA1 Message Date
Daniel Rudolf 2f9f40d76c
Update Pico::VERSION and Pico::VERSION_ID 2018-07-29 13:11:14 +02:00
Daniel Rudolf c7d4d25ab3
Add missing registred meta headers
Use the `Formatted Date` meta header to explicitly set a page's formatted date (i.e. `$meta['date_formatted']`), and `Time` to set `$meta['time']`. Use the `Hidden` meta header to manually hide a page (the page is still accessible, but won't show up in the pages list). Note the difference between `$pageData['hidden']` and `$pageData['meta']['hidden']`.
2018-07-29 12:51:28 +02:00
Daniel Rudolf be86f8fa8c
Update Pico::VERSION 2018-07-01 18:12:34 +02:00
johannes Heimbach c12b50dc1b stop config.yml on loading again 2018-04-29 17:21:27 +02:00
Daniel Rudolf 568166ad07
Check Pico::VERSION constant before deploying a new release 2018-03-29 22:48:24 +02:00
Daniel Rudolf b405edba17
Various small improvements 2018-03-29 22:47:23 +02:00
Daniel Rudolf 190889b77b
Fix sorting of Pico::$nativePlugins
Thanks to PT on our Freenode IRC channel #picocms for reporting this!
2018-03-29 22:45:12 +02:00
Daniel Rudolf 03cc10183c
Fix page tree 2018-01-31 12:29:59 +01:00
Daniel Rudolf 888190f15a
Various small improvements 2018-01-21 23:06:38 +01:00
Daniel Rudolf b129a4fb12
Various small improvements 2017-12-27 21:36:56 +01:00
Daniel Rudolf afd0a4d7a3
Change AbstractPicoPlugin::$enabled's behavior
AbstractPicoPlugin::$enabled now defaults to NULL what leaves the decision whether a plugin should be enabled or disabled by default up to Pico (precisely AbstractPicoPlugin::triggerEvent()). If all dependencies of a plugin are fulfilled, Pico enables the plugin by default. Otherwise the plugin is silently disabled (this was the behavior when AbstractPicoPlugin::$enabled was set to TRUE previously).

If a plugin should never be disabled *silently* (e.g. when dealing with security-relevant stuff like access control, or similar), set AbstractPicoPlugin::$enabled to TRUE. If Pico can't fulfill all the plugin's dependencies, it will throw an RuntimeException.

If a plugin rather does some "crazy stuff" a user should really be aware of before using it, you can set AbstractPicoPlugin::$enabled to FALSE. The user will then have to enable the plugin manually. However, if another plugin depends on this plugin, it might get enabled silently nevertheless.

No matter what, the user can always explicitly enable or disable a plugin in Pico's config.
2017-12-27 21:36:08 +01:00
Daniel Rudolf 37dfe0e6ef
Force themes to use .twig as file extension
We recommend plugin developers to use templates when serving HTML contents (like the UI of PicoAdmin), however, by supporting multiple file extensions for themes, we make it pretty hard to overwrite a plugin's template with a theme. As always, we preserve BC using PicoDeprecated.
2017-11-25 21:52:03 +01:00
Daniel Rudolf 28d2648ba0
Add Pico::buildPageTree()
Pico's page tree is a list of all the tree's branches (no matter the depth). Thus, by iterating a array element, you get the nodes of a given branch. All leaf nodes do represent a page, but inner nodes may or may not represent a page (e.g. if there's a `sub/page.md`, but neither a `sub/index.md` nor a `sub.md`, the inner node `sub`, that is the parent of the `sub/page` node, represents no page itself).

A page's file path describes its node's path in the tree (e.g. the page `sub/page.md` is represented by the `sub/page` node, thus a child of the `sub` node and a element of the `sub` branch). However, the index page of a folder (e.g. `sub/index.md`), is *not* a node of the `sub` branch, but rather of the `/` branch. The page's node is not `sub/index`, but `sub`. If two pages are described by the same node (e.g. if both a `sub/index.md` and a `sub.md` exist), the index page takes precedence. Pico's main index page (i.e. `index.md`) is represented by the tree's root node `/` and a special case: it is the only node of the `` (i.e. the empty string) branch.

A node is represented by an array with the keys `id`, `page` and `children`. The `id` key contains a string with the node's name. If the node represents a page, the `page` key is a reference to the page's data array. If the node is a inner node, the `children` key is a reference to its matching branch (i.e. a list of the node's children). The order of a node's children matches the order in Pico's pages array.

If you want to walk the whole page tree, start with the tree's root node at `$pageTree[""]["/"]`. The root node's `children` key is a reference to the `/` branch at `$pageTree["/"]`, that is a list of the root node's direct child nodes and their siblings.

You MUST NOT iterate the page tree itself (i.e. the list of the tree's branches), its order is undefined and the array will be replaced by a non-iterable data structure with Pico 3.0.
2017-11-18 18:34:57 +01:00
Daniel Rudolf 3846d3b685
Various small improvements 2017-11-18 18:28:02 +01:00
Daniel Rudolf 1cd6e241f0
Prepare v2.0.0-beta.1 2017-11-05 18:28:11 +01:00
Daniel Rudolf e8a19cb2f9
Fix Pico::parseFileMeta() 2017-11-04 20:49:41 +01:00
Daniel Rudolf 61319b011e
Add license/copyright file header; improve phpDoc class docs 2017-10-19 21:55:41 +02:00
Daniel Rudolf d8a649e6f7
Don't lower meta data unsolicited and flip meta headers array
Don't lower unregistered meta headers on the first level unsolicited (e.g. `SomeNotRegisteredKey: foobar` in the YAML Frontmatter should result in `['SomeNotRegisteredKey']`, not `['somenotregisteredkey']`). Furthermore, Pico no longer compares registered meta headers in a case-insensitive manner. However, you can now register multiple search strings that are used to find a registered meta header. This is achieved by flipping the meta headers array: Pico 2.0 uses the array key to search for a meta value and the array value to store the found meta value. Previously it was the other way round (what didn't make much sense...).
2017-10-14 23:12:16 +02:00
Daniel Rudolf 151908fbad
Remove various event params that are a bit out of place 2017-10-14 22:08:11 +02:00
Daniel Rudolf 709416328a
Pico::loadPlugins(): Add plugin blacklist and allow disabling local plugins 2017-10-13 21:02:51 +02:00
Daniel Rudolf 867f81a443
Various small improvements 2017-10-12 16:15:58 +02:00
Daniel Rudolf 9dcb06c258
Pico::sortPlugins(): Fix sorting of non-native plugins 2017-10-12 12:12:37 +02:00
Daniel Rudolf 20297deaec
Pico::loadLocalPlugins(): Don't load plugins case-insensitive
The performance vs. error-proneness trade-off doesn't justify this additional complexity. This is Pico 2.0, we always try to minimize BC-breaking changes, but we're breaking BC anyway by loading plugins from plugins/<plugin name>/<plugin name>.php only...
2017-10-12 12:11:55 +02:00
Daniel Rudolf b6468ca215
Various small improvements 2017-10-08 00:36:29 +02:00
Daniel Rudolf 9a9872fe8e
Add Pico::getPageId() 2017-10-08 00:36:14 +02:00
Daniel Rudolf 7087573aed
Pico::loadPlugins(): Load composer-plugins first and skip conflicting plugins in the plugins/ dir 2017-10-08 00:35:36 +02:00
Daniel Rudolf 32ae70f398
Add $default param to getConfig() method
- Pico::getConfig()
- AbstractPicoPlugin::getPluginCongif()
2017-08-05 00:19:03 +02:00
Daniel Rudolf 8138212a27
Pico::evaluateRequestUrl(): Improve REQUEST_URI handling
Don't 404 "/index.php" requests
2017-08-03 22:17:48 +02:00
Daniel Rudolf b73e197ccb
Refactor YAML frontmatter date parsing
You can now explicitly specify both the `date_formatted` and `time` meta values to overwrite Pico's page date handling. Specifying `time` doesn't make much sense in general, however, specifying `date_formatted` allows you to use `{{ meta.date_formatted }}` on all systems, even those where `strftime()` doesn't work as wished
2017-07-28 12:16:26 +02:00
Daniel Rudolf 3e88c58ce0
Merge branch 'master' into pico-1.1
Conflicts:
	lib/Pico.php
2017-07-18 21:39:39 +02:00
Daniel Rudolf d3c624777f
Improve guessing whether URL rewriting is enabled
Besides searching for the env var 'PICO_URL_REWRITING', also try 'REDIRECT_PICO_URL_REWRITING'.
2017-07-18 21:36:15 +02:00
Daniel Rudolf 53e9eaa5e4
Fix Pico's REQUEST_URI routing method when installed to / 2017-07-18 21:31:14 +02:00
Daniel Rudolf 414f5ac18e
Allow pages to be sorted by arbitrary meta values
This basically works like Pico's `sort_by` Twig filter
2017-07-14 20:37:05 +02:00
Daniel Rudolf 55a0a5bc91
Add Pico::substituteFileContent() method 2017-06-21 14:27:34 +02:00
Daniel Rudolf 05c8d95b3f
Only load Twig_Extension_Debug when Twig's debug mode is enabled 2017-06-20 23:34:07 +02:00
Daniel Rudolf 21051fe08b
Pico::loadComposerPlugins(): Use Pico::getVendorDir() instead of Pico::$vendorDir 2017-06-14 17:43:40 +02:00
Daniel Rudolf 23ad80b98a
Let Pico load plugins from vendor/pico-plugin.php
Split the Pico::loadPlugins() method to Pico::loadLocalPlugins() and Pico::loadComposerPlugins()
2017-06-14 17:10:42 +02:00
Daniel Rudolf b098e22033
Various small improvements 2017-05-14 01:26:38 +02:00
Daniel Rudolf d26da62bf1
Add onSinglePageContent event 2017-05-14 01:26:29 +02:00
Daniel Rudolf 773f4795f7
Remove Pico::registerTwig(), use Pico::getTwig() instead 2017-05-14 01:26:07 +02:00
Daniel Rudolf 80c88f2a7d
Refactor onMetaHeaders event 2017-05-14 01:25:10 +02:00
Daniel Rudolf f4332a247c
Force PicoDeprecated to be first plugin in the plugins array 2017-05-14 01:11:16 +02:00
Daniel Rudolf 624310bbe7
Various small improvements 2017-05-13 18:17:58 +02:00
Daniel Rudolf 191f6edbe9
Don't pass the $plugins argument of the onPluginsLoaded event by reference
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.
2017-05-13 18:17:19 +02:00
Daniel Rudolf 6e28a51080
Refactor onPages… and onPage… core events
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.
2017-05-13 18:08:54 +02:00
Daniel Rudolf 7b222b03e4
Add Pico::API_VERSION 2017-05-10 17:00:48 +02:00
Daniel Rudolf 36b3aef1c7
Fix Pico::loadPlugin() when called before Pico::loadPlugins() 2017-05-07 14:20:44 +02:00
Daniel Rudolf 1d73524e41
Search for content/index.md to determine the content dir to use 2017-05-02 00:22:35 +02:00
Daniel Rudolf f52e3dc890
Add Pico::getVendorDir()
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.
2017-05-01 22:27:57 +02:00
Daniel Rudolf 3f17a2e28e
Merge branch 'master' into pico-1.1
Conflicts:
	content-sample/index.md
	themes/default/font/fontello.eot
	themes/default/font/fontello.svg
	themes/default/font/fontello.ttf
	themes/default/font/fontello.woff
	themes/default/font/fontello.woff2
	themes/default/fontello.css
2017-05-01 20:38:03 +02:00
Daniel Rudolf a2d0d745ff
Fix detection of Windows-based server environments 2017-02-19 23:43:43 +01:00
Daniel Rudolf 882a80a179
Update docs to reflect 9b7523b 2017-02-06 00:01:25 +01:00
Daniel Rudolf d4c65fa523
Allow configuring Parsedown 2017-02-05 21:49:54 +01:00
Daniel Rudolf 5429a3a932
Add Pico::getTwigTemplate() 2017-02-05 20:20:26 +01:00
Daniel Rudolf 9b7523b9e8
Use .yml files to configure Pico
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`.
2017-02-05 16:52:18 +01:00
Daniel Rudolf 0a080c8965
Add lazy init for Symfony YAML, Parsedown and Twig 2017-02-05 15:55:53 +01:00
Daniel Rudolf c56ba02b0b
Reintroduce plugin prefix classifications
This partially reverts commit 9254240
2016-12-12 20:58:38 +01:00
Daniel Rudolf 9254240e44
Load plugins from <plugin name>.php and <plugin name>/<plugin name>.php only 2016-12-12 20:37:17 +01:00
Daniel Rudolf eec1d625c4
Add Pico::getFilesGlob() method 2016-12-12 20:36:46 +01:00
Daniel Rudolf 586d792c32
Update Pico::VERSION_ID constant 2016-12-12 17:09:30 +01:00
Daniel Rudolf 46f5d3d56d
Move Twig link filter and url_param and form_param functions to PicoTwigExtension 2016-12-12 17:08:40 +01:00
Daniel Rudolf 1f35346f53
Improve detection of hidden files to serve 404 contents instead
Follow-up to 9b72b5c316
2016-12-12 16:37:20 +01:00
Daniel Rudolf 8f7e4da53d
Rename Pico 1.1 to Pico 2.0 2016-12-12 15:31:06 +01:00
Daniel Rudolf 2e880d6c7f
Discover the previous and next pages of all pages 2016-12-12 14:49:57 +01:00
Daniel Rudolf 9b72b5c316
Give pages starting with a underscore (_) a special treatment
Follow-up to b493ebdb84
2016-12-12 14:49:05 +01:00
Daniel Rudolf 9a2dd4f078
Mark Twig variables rewrite_url and is_front_page as deprecated 2016-12-06 20:52:27 +01:00
Daniel Rudolf ec3f7fb626
Improve class docs 2016-12-06 20:22:50 +01:00
Daniel Rudolf 5193b77fdf
Reuse YAML parser instance 2016-12-06 20:22:38 +01:00
Daniel Rudolf 5d48aa7040
Let Pico::getTwigVariables() return the "real" array
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.
2016-12-06 20:04:07 +01:00
Daniel Rudolf bc5729629d
Fire onMetaHeaders event only once, cache results of Pico::getMetaHeaders() 2016-12-06 20:01:38 +01:00
Daniel Rudolf 82c6dd9795
Don't sort pages when a unknown sort method is specified
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...
2016-12-06 19:47:37 +01:00
Daniel Rudolf 5cf47e65de
Various small improvements 2016-12-06 19:03:58 +01:00
Daniel Rudolf 7a6e4f8271
Sort all loaded plugins using a plugin dependency topology
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)).
2016-12-06 17:18:59 +01:00
Daniel Rudolf 0a269746eb
Add Pico::is404Content() method 2016-11-26 16:48:10 +01:00
Daniel Rudolf d9393df4fa
Pico::getBaseUrl(): Improve hostname detection with proxies 2016-11-23 23:26:55 +01:00
Daniel Rudolf 38615e444d
Use Pico::loadFileContent() in Pico::readPages() 2016-10-09 02:49:30 +02:00
Daniel Rudolf bea610dbf4
Pico::evaluateRequestUrl(): Replace strpos()+substr() with strstr() 2016-10-05 14:17:10 +02:00
Daniel Rudolf 3ebb51a55e
Improve class docs
Follow-up to 00603f6
2016-10-01 19:01:21 +02:00
Daniel Rudolf 00603f61fc
Add integrated 404 Not Found page
Resolves #299
2016-10-01 18:58:04 +02:00
Daniel Rudolf a74db1ddbb
Add Pico::filterVariable() method
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
2016-09-17 20:10:24 +02:00
Daniel Rudolf 0b4099fdb0
Improve class docs 2016-09-17 20:02:49 +02:00
Daniel Rudolf f73c9622b8
Fix Pico::evaluateRequestUrl(): PHP's built-in webserver doesn't always set QUERY_STRING 2016-09-17 20:02:29 +02:00
Daniel Rudolf 21bd18bcf0
Replace Pico::discoverRequestFile() with public Pico::resolveFilePath()
This allows plugins (e.g. PicoAdmin) to safely resolve file paths without the need of re-implementing the method.
2016-07-20 19:23:19 +02:00
Daniel Rudolf e27be7a80f
Merge branch 'master' into pico-1.1 2016-07-15 03:23:09 +02:00
Daniel Rudolf fb4bdfe1fc
Fix Pico::parseFileMeta() for non-YAML 1-liners
\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".
```
2016-07-15 03:13:58 +02:00
Daniel Rudolf aa1bc077a7
Add $dropIndex parameter to Pico::getPageUrl() method
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.
2016-07-14 00:24:06 +02:00
Daniel Rudolf 848e28b7e6
Declare Pico::getFiles() public
This might be a useful helper method for plugins (e.g. PicoAdmin)
2016-07-14 00:20:22 +02:00
Daniel Rudolf ddf3da0391
Merge branch 'master' into pico-1.1
Conflicts:
	.htaccess
	config/config.php.template
	content-sample/index.md
	lib/Pico.php
2016-06-18 20:23:23 +02:00
Daniel Rudolf eeb43e131f
Pico::prepareFileContent(): Declare $variables variable 2016-06-18 20:19:16 +02:00
Daniel Rudolf 94279c57f8
Improve phpDocs class docs 2016-05-23 15:13:56 +02:00
Daniel Rudolf e01044319a
Build system: Use dynamic phpDoc title 2016-04-24 21:13:47 +02:00
Daniel Rudolf 0e8cd0873d
Merge branch 'master' into pico-1.1
Conflicts:
	.htaccess
2016-04-24 20:23:00 +02:00
Daniel Rudolf 6465c2b0a9
Support REQUEST_URI routing method
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`.
2016-04-24 20:11:05 +02:00
Daniel Rudolf 6234be88b0
Always use on404Content... execution path when serving a 404.md 2016-04-24 04:06:04 +02:00
Daniel Rudolf d19621a908
Improve themes dir guessing; add $config['theme_url'] config 2016-04-24 01:22:43 +02:00
Daniel Rudolf 1b3ef7516d
Drop the "index" part of URLs
Closes #347. Thanks @Robby-
2016-04-23 21:41:09 +02:00
Daniel Rudolf a119122497 Fix coding standard violation 2016-04-22 14:31:14 +02:00
Daniel Rudolf b133f6dae5 Add Pico::VERSION_ID (like PHP_VERSION_ID) 2016-04-22 14:23:46 +02:00
Daniel Rudolf 8dfb1b14c7
Improve HTTPS detection with proxies
Fixes #344. Thanks @Robby-

Implementation details taken from Symfony 3.0.4, method \Symfony\Component\HttpFoundation\Request::isSecure(), see https://github.com/symfony/symfony/blob/v3.0.4/src/Symfony/Component/HttpFoundation/Request.php#L1169-L1192
2016-04-17 02:44:41 +02:00
Daniel Rudolf bbd8ef8847 Fix Date meta header parsing with ISO-8601 datetime strings
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.
2016-03-16 14:27:42 +01:00