diff --git a/.travis.yml b/.travis.yml index 90b27d2..ff01cd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,7 +30,7 @@ before_deploy: - composer install --no-dev --optimize-autoloader - find vendor/ -type d -path 'vendor/*/*/.git' -print0 | xargs -0 rm -rf - mv index.php.dist index.php - - tar -czf "pico-release-$TRAVIS_TAG.tar.gz" README.md LICENSE CONTRIBUTING.md CHANGELOG.md composer.json composer.lock config content-sample lib plugins themes vendor .htaccess index.php + - tar -czf "pico-release-$TRAVIS_TAG.tar.gz" README.md LICENSE.md CONTRIBUTING.md CHANGELOG.md composer.json composer.lock config content-sample lib plugins themes vendor .htaccess index.php deploy: provider: releases diff --git a/CHANGELOG.md b/CHANGELOG.md index a7570d8..eb953c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,20 @@ Released: - ``` * [New] This is Picos first stable release! The Pico Community wants to thank all contributors and users which made this possible! +* [New] Adding `$queryData` parameter to `Pico::getPageUrl()` method * [New] Default Theme: Use Twitter Bootstrap `4.0.0-alpha` + Font Awesome `4.5.0` via MaxCDN * [New] Default Theme: `Blog Example` included! * [New] Default Theme: `blog`, `blog-post` and `blog-post-full` layouts * [New] Default Theme: `blog/` directory in `content-sample` with new demo posts * [New] Default Theme: add `theme_config` to `config/config.php.template` * [New] Default Theme: use new `sort_by` twig filters +* [Changed] Moving `LICENSE` to `LICENSE.md` +* [Changed] Throw `LogicException` instead of `RuntimeException` when calling + `Pico::setConfig()` after processing has started +* [Changed] Default theme now highlights the current page and only lists pages + with a title in the navigation +* [Changed] #292: Ignore YAML parse errors (meta data) in `Pico::readPages()` +* [Fixed] Support empty meta header ``` ### Version 1.0.0-beta.2 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ca6f0d8..67f1618 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -19,7 +19,7 @@ Please describe your issue as clear as possible and always include the *Pico ver Contributing code ----------------- -Once you decide you want to contribute to *Pico's core* (which we really appreciate!) you can fork the project from https://github.com/picocms/Pico. If you're interested in developing a *plugin* or *theme* for Pico, please refer to the [development section](http://picocms.org/plugin-dev.html) of our website. +Once you decide you want to contribute to *Pico's core* (which we really appreciate!) you can fork the project from https://github.com/picocms/Pico. If you're interested in developing a *plugin* or *theme* for Pico, please refer to the [development section](http://picocms.org/development/) of our website. ### Prevent `merge-hell` @@ -49,7 +49,7 @@ With this command you can specify a file or folder to limit which files it will Pico accepts the problems of having redundant documentation on different places (concretely Pico's inline user docs, the `README.md` and the website) for the sake of a better user experience. When updating the docs, please make sure to keep them in sync. -If you update the [`README.md`](https://github.com/picocms/Pico/blob/master/README.md) or [`content-sample/index.md`](https://github.com/picocms/Pico/blob/master/content-sample/index.md), please make sure to update the corresponding files in the [`_docs`](https://github.com/picocms/Pico/tree/gh-pages/_docs/) folder of the `gh-pages` branch (i.e. [Pico's website](http://picocms.org/docs.html)) and vice versa. Unfortunately this involves three (!) different markdown parsers. If you're experiencing problems, use Pico's [`erusev/parsedown-extra`](https://github.com/erusev/parsedown-extra) as a reference. You can try to make the contents compatible to [Redcarpet](https://github.com/vmg/redcarpet) by yourself, otherwise please address the issues in your pull request message and we'll take care of it. +If you update the [`README.md`](https://github.com/picocms/Pico/blob/master/README.md) or [`content-sample/index.md`](https://github.com/picocms/Pico/blob/master/content-sample/index.md), please make sure to update the corresponding files in the [`_docs`](https://github.com/picocms/Pico/tree/gh-pages/_docs/) folder of the `gh-pages` branch (i.e. [Pico's website](http://picocms.org/docs/)) and vice versa. Unfortunately this involves three (!) different markdown parsers. If you're experiencing problems, use Pico's [`erusev/parsedown-extra`](https://github.com/erusev/parsedown-extra) as a reference. You can try to make the contents compatible to [Redcarpet](https://github.com/vmg/redcarpet) by yourself, otherwise please address the issues in your pull request message and we'll take care of it. Versioning ---------- diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md index f43a652..d709413 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Pico ==== -[![License](https://img.shields.io/github/license/picocms/Pico.svg)](https://github.com/picocms/Pico/blob/master/LICENSE) +[![License](https://img.shields.io/github/license/picocms/Pico.svg)](https://github.com/picocms/Pico/blob/master/LICENSE.md) [![Version](https://img.shields.io/github/release/picocms/Pico.svg)](https://github.com/picocms/Pico/releases/latest) [![Build Status](https://img.shields.io/travis/picocms/Pico.svg)](https://travis-ci.org/picocms/Pico) [![Scrutinizer Code Quality](https://img.shields.io/scrutinizer/g/theshka/pico.svg)](https://scrutinizer-ci.com/g/theshka/Pico/?branch=master) @@ -123,7 +123,7 @@ Contributing You want to contribute to Pico? We really appreciate that! You can help make Pico better by [contributing code][PullRequests] or [reporting issues][Issues], but please take note of our [contribution guidelines][ContributionGuidelines]. In general you can contribute in three different areas: -1. Plugins & Themes: You're a plugin developer or theme designer? We love you guys! You can find tons of information about how to develop plugins and themes at http://picocms.org/plugin-dev.html. If you have created a plugin or theme, please add it to our [Wiki][], either on the [plugins][WikiPlugins] or [themes page][WikiThemes]. Doing so, we may select and promote your plugin or theme on [our website][OfficialPlugins] as officially supported! +1. Plugins & Themes: You're a plugin developer or theme designer? We love you guys! You can find tons of information about how to develop plugins and themes at http://picocms.org/development/. If you have created a plugin or theme, please add it to our [Wiki][], either on the [plugins][WikiPlugins] or [themes page][WikiThemes]. Doing so, we may select and promote your plugin or theme on [our website][OfficialPlugins] as officially supported! 2. Documentation: We always appreciate people improving our documentation. You can either improve the [inline user docs][EditInlineDocs] or the more extensive [user docs on our website][EditUserDocs]. You can also improve the [docs for plugin and theme developers][EditDevDocs]. Simply fork Pico from https://github.com/picocms/Pico, change the Markdown files and open a [pull request][PullRequests]. @@ -137,10 +137,10 @@ You want to contribute to Pico? We really appreciate that! You can help make Pic [composer]: https://getcomposer.org/ [SemVer]: http://semver.org [PHPServer]: http://php.net/manual/en/features.commandline.webserver.php -[HelpUpgrade]: http://picocms.org/upgrade.html -[HelpUserDocs]: http://picocms.org/docs.html -[HelpDevDocs]: http://picocms.org/plugin-dev.html -[OfficialPlugins]: http://picocms.org/plugins.html +[HelpUpgrade]: http://picocms.org/upgrade/ +[HelpUserDocs]: http://picocms.org/docs/ +[HelpDevDocs]: http://picocms.org/development/ +[OfficialPlugins]: http://picocms.org/customization/ [Wiki]: https://github.com/picocms/Pico/wiki [WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins [WikiThemes]: https://github.com/picocms/Pico/wiki/Pico-Themes @@ -150,4 +150,4 @@ You want to contribute to Pico? We really appreciate that! You can help make Pic [ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md [EditInlineDocs]: https://github.com/picocms/Pico/edit/master/content-sample/index.md [EditUserDocs]: https://github.com/picocms/Pico/tree/gh-pages/_docs -[EditDevDocs]: https://github.com/picocms/Pico/tree/gh-pages/_plugin-dev +[EditDevDocs]: https://github.com/picocms/Pico/tree/gh-pages/_development diff --git a/_build/generate-phpdoc.sh b/_build/generate-phpdoc.sh index 2408ac2..0728ca6 100755 --- a/_build/generate-phpdoc.sh +++ b/_build/generate-phpdoc.sh @@ -18,7 +18,7 @@ echo # update a separate phpDoc cache if [ "$PHPDOC_CACHE_DIR" != "-" ]; then # parse phpDoc files (i.e. update cache) - printf "\nUpdate phpDoc cache...\n" + printf "Update phpDoc cache...\n" phpdoc project:parse --config "$PHPDOC_CONFIG" \ --target "$PHPDOC_CACHE_DIR" diff --git a/content-sample/index.md b/content-sample/index.md index 9637ea5..b0c4a78 100644 --- a/content-sample/index.md +++ b/content-sample/index.md @@ -10,18 +10,24 @@ Congratulations, you have successfully installed [Pico](http://picocms.org/). ## Creating Content -Pico is a flat file CMS, this means there is no administration backend or -database to deal with. You simply create `.md` files in the `content-sample` -folder and that becomes a page. For example, this file is called `index.md` +Pico is a flat file CMS. This means there is no administration backend or +database to deal with. You simply create `.md` files in the `content` folder +and those files become your pages. For example, this file is called `index.md` and is shown as the main landing page. -If you create a folder within the content folder (e.g. `content-sample/sub`) -and put an `index.md` inside it, you can access that folder at the URL -`http://example.com/pico/?sub`. If you want another page within the sub folder, +When you install Pico, it comes with a `content-sample` folder. Inside this +folder is a sample website that will display until you add your own content. +You should create your own `content` folder in Pico's root directory and place +your files there. No configuration is required, Pico will automatically use the +`content` folder if it exists. + +If you create a folder within the content folder (e.g. `content/sub`) and put +an `index.md` inside it, you can access that folder at the URL +`http://example.com/?sub`. If you want another page within the sub folder, simply create a text file with the corresponding name and you will be able to -access it (e.g. `content-sample/sub/page.md` is accessible from the URL -`http://example.com/pico/?sub/page`). Below we've shown some examples of -locations and their corresponding URLs: +access it (e.g. `content/sub/page.md` is accessible from the URL +`http://example.com/?sub/page`). Below we've shown some examples of locations +and their corresponding URLs:
content-sample/index.md | +content/index.md | / | |
content-sample/sub.md | +content/sub.md | ||
content-sample/sub/index.md | +content/sub/index.md | ?sub (same as above) | |
content-sample/sub/page.md | +content/sub/page.md | ?sub/page | |
content-sample/a/very/long/url.md | -?a/very/long/url (doesn't exist) | +content/a/very/long/url.md | ++ ?a/very/long/url + (doesn't exist) + |
!\[Image Title\](%base_url%/assets/image.png)
+(like images, downloads, etc.). We even deny access to your `content` directory
+by default. If you want to use some assets (e.g. a image) in one of your content
+files, you should create an `assets` folder in Pico's root directory and upload
+your assets there. You can then access them in your markdown using
+%base_url%/assets/
for example:
+!\[Image Title\](%base_url%/assets/image.png)
### Text File Markup
@@ -93,8 +100,8 @@ There are also certain variables that you can use in your text files:
* %base_url%
- The URL to your Pico site; internal links
can be specified using %base_url%?sub/page
* %theme_url%
- The URL to the currently used theme
-* %meta.*%
- Access any meta variable of the current page,
- e.g. %meta.author%
is replaced with `Joe Bloggs`
+* %meta.*%
- Access any meta variable of the current
+ page, e.g. %meta.author%
is replaced with `Joe Bloggs`
### Blogging
@@ -231,9 +238,9 @@ and designers created in the past. As with plugins, you can find themes in
#### Plugins for users
-Officially tested plugins can be found at http://picocms.org/plugins.html, but
-there are many awesome third-party plugins out there! A good start point for
-discovery is [our Wiki][WikiPlugins].
+Officially tested plugins can be found at http://picocms.org/customization/,
+but there are many awesome third-party plugins out there! A good start point
+for discovery is [our Wiki][WikiPlugins].
Pico makes it very easy for you to add new features to your website. Simply
upload the files of the plugin to the `plugins/` directory and you're done.
@@ -250,7 +257,7 @@ replace `false` with `true`.
#### Plugins for developers
You're a plugin developer? We love you guys! You can find tons of information
-about how to develop plugins at http://picocms.org/plugin-dev.html. If you've
+about how to develop plugins at http://picocms.org/development/. If you've
developed a plugin for Pico 0.9 or older, you probably want to upgrade it
to the brand new plugin system introduced with Pico 1.0. Please refer to the
[upgrade section of the docs][PluginUpgrade].
@@ -295,5 +302,5 @@ For more help have a look at the Pico documentation at http://picocms.org/docs.
[Twig]: http://twig.sensiolabs.org/documentation
[WikiThemes]: https://github.com/picocms/Pico/wiki/Pico-Themes
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins
-[PluginUpgrade]: http://picocms.org/plugin-dev.html#upgrade
+[PluginUpgrade]: http://picocms.org/development/#upgrade
[ModRewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
diff --git a/lib/Pico.php b/lib/Pico.php
index 334d792..112745a 100644
--- a/lib/Pico.php
+++ b/lib/Pico.php
@@ -267,7 +267,7 @@ class Pico
* the rendered contents.
*
* @return string rendered Pico contents
- * @throws RuntimeException thrown when a not recoverable error occurs
+ * @throws Exception thrown when a not recoverable error occurs
*/
public function run()
{
@@ -518,12 +518,12 @@ class Pico
* @see Pico::getConfig()
* @param mixed[] $config array with config variables
* @return void
- * @throws RuntimeException thrown if Pico already started processing
+ * @throws LogicException thrown if Pico already started processing
*/
public function setConfig(array $config)
{
if ($this->locked) {
- throw new RuntimeException("You cannot modify Pico's config after processing has started");
+ throw new LogicException("You cannot modify Pico's config after processing has started");
}
$this->config = $config;
@@ -753,16 +753,18 @@ class Pico
* @param string $rawContent the raw file contents
* @param string[] $headers known meta headers
* @return array parsed meta data
+ * @throws \Symfony\Component\Yaml\Exception\ParseException thrown when the
+ * meta data is invalid
*/
public function parseFileMeta($rawContent, array $headers)
{
$meta = array();
$pattern = "/^(\/(\*)|---)[[:blank:]]*(?:\r)?\n"
- . "(.*?)(?:\r)?\n(?(2)\*\/|---)[[:blank:]]*(?:(?:\r)?\n|$)/s";
- if (preg_match($pattern, $rawContent, $rawMetaMatches)) {
+ . "(?:(.*?)(?:\r)?\n)?(?(2)\*\/|---)[[:blank:]]*(?:(?:\r)?\n|$)/s";
+ if (preg_match($pattern, $rawContent, $rawMetaMatches) && isset($rawMetaMatches[3])) {
$yamlParser = new \Symfony\Component\Yaml\Parser();
$meta = $yamlParser->parse($rawMetaMatches[3]);
- $meta = array_change_key_case($meta, CASE_LOWER);
+ $meta = ($meta !== null) ? array_change_key_case($meta, CASE_LOWER) : array();
foreach ($headers as $fieldId => $fieldName) {
$fieldName = strtolower($fieldName);
@@ -840,7 +842,7 @@ class Pico
{
// remove meta header
$metaHeaderPattern = "/^(\/(\*)|---)[[:blank:]]*(?:\r)?\n"
- . "(.*?)(?:\r)?\n(?(2)\*\/|---)[[:blank:]]*(?:(?:\r)?\n|$)/s";
+ . "(?:(.*?)(?:\r)?\n)?(?(2)\*\/|---)[[:blank:]]*(?:(?:\r)?\n|$)/s";
$content = preg_replace($metaHeaderPattern, '', $rawContent, 1);
// replace %site_title%
@@ -909,10 +911,9 @@ class Pico
* Reads the data of all pages known to Pico
*
* The page data will be an array containing the following values:
- * - * +----------------+--------+------------------------------------------+ + * * | Array key | Type | Description | - * +----------------+--------+------------------------------------------+ + * | -------------- | ------ | ---------------------------------------- | * | id | string | relative path to the content file | * | url | string | URL to the page | * | title | string | title of the page (YAML header) | @@ -923,8 +924,6 @@ class Pico * | date_formatted | string | formatted date of the page | * | raw_content | string | raw, not yet parsed contents of the page | * | meta | string | parsed meta data of the page | - * +----------------+--------+------------------------------------------+ - ** * @see Pico::sortPages() * @see Pico::getPages() @@ -952,7 +951,14 @@ class Pico $url = $this->getPageUrl($id); if ($file != $this->requestFile) { $rawContent = file_get_contents($file); - $meta = $this->parseFileMeta($rawContent, $this->getMetaHeaders()); + + $headers = $this->getMetaHeaders(); + try { + $meta = $this->parseFileMeta($rawContent, $headers); + } catch (\Symfony\Component\Yaml\Exception\ParseException $e) { + $meta = $this->parseFileMeta('', $headers); + $meta['YAML_ParseError'] = $e->getMessage(); + } } else { $rawContent = &$this->rawContent; $meta = &$this->meta; @@ -1237,17 +1243,32 @@ class Pico /** * Returns the URL to a given page * - * @param string $page identifier of the page to link to - * @return string URL + * @param string $page identifier of the page to link to + * @param array|string $queryData either an array containing properties to + * create a URL-encoded query string from, or a already encoded string + * @return string URL */ - public function getPageUrl($page) + public function getPageUrl($page, $queryData = null) { + if (is_array($queryData)) { + $queryData = http_build_query($queryData, '', '&'); + } elseif (($queryData !== null) && !is_string($queryData)) { + throw new InvalidArgumentException( + 'Argument 2 passed to ' . get_called_class() . '::getPageUrl() must be of the type array or string, ' + . (is_object($queryData) ? get_class($queryData) : gettype($queryData)) . ' given' + ); + } + if (!empty($queryData)) { + $page = !empty($page) ? $page : 'index'; + $queryData = $this->isUrlRewritingEnabled() ? '?' . $queryData : '&' . $queryData; + } + if (empty($page)) { - return $this->getBaseUrl(); + return $this->getBaseUrl() . $queryData; } elseif (!$this->isUrlRewritingEnabled()) { - return $this->getBaseUrl() . '?' . rawurlencode($page); + return $this->getBaseUrl() . '?' . rawurlencode($page) . $queryData; } else { - return $this->getBaseUrl() . implode('/', array_map('rawurlencode', explode('/', $page))); + return $this->getBaseUrl() . implode('/', array_map('rawurlencode', explode('/', $page))) . $queryData; } } diff --git a/plugins/00-PicoDeprecated.php b/plugins/00-PicoDeprecated.php index 5240160..a9a272d 100644 --- a/plugins/00-PicoDeprecated.php +++ b/plugins/00-PicoDeprecated.php @@ -11,10 +11,9 @@ * can disable this plugin by calling {@link PicoDeprecated::setEnabled()}. * * The following deprecated events are triggered by this plugin: - *
- * +---------------------+-----------------------------------------------------------+ + * * | Event | ... triggers the deprecated event | - * +---------------------+-----------------------------------------------------------+ + * | ------------------- | --------------------------------------------------------- | * | onPluginsLoaded | plugins_loaded() | * | onConfigLoaded | config_loaded($config) | * | onRequestUrl | request_url($url) | @@ -32,8 +31,6 @@ * | onTwigRegistration | before_twig_register() | * | onPageRendering | before_render($twigVariables, $twig, $templateName) | * | onPageRendered | after_render($output) | - * +---------------------+-----------------------------------------------------------+ - ** * Since Pico 1.0 the config is stored in {@path "config/config.php"}. This * plugin tries to read {@path "config.php"} in Pico's root dir and overwrites diff --git a/plugins/DummyPlugin.php b/plugins/DummyPlugin.php index f8ebb01..b1588eb 100644 --- a/plugins/DummyPlugin.php +++ b/plugins/DummyPlugin.php @@ -228,10 +228,9 @@ final class DummyPlugin extends AbstractPicoPlugin * Triggered when Pico reads a single page from the list of all known pages * * The `$pageData` parameter consists of the following values: - *
- * +----------------+--------+------------------------------------------+ + * * | Array key | Type | Description | - * +----------------+--------+------------------------------------------+ + * | -------------- | ------ | ---------------------------------------- | * | id | string | relative path to the content file | * | url | string | URL to the page | * | title | string | title of the page (YAML header) | @@ -242,8 +241,6 @@ final class DummyPlugin extends AbstractPicoPlugin * | date_formatted | string | formatted date of the page | * | raw_content | string | raw, not yet parsed contents of the page | * | meta | string | parsed meta data of the page | - * +----------------+--------+------------------------------------------+ - ** * @see DummyPlugin::onPagesLoaded() * @param array &$pageData data of the loaded page diff --git a/themes/default/style.css b/themes/default/style.css index d26f65a..a8c0030 100644 --- a/themes/default/style.css +++ b/themes/default/style.css @@ -222,9 +222,14 @@ blockquote { margin-bottom: 80px; color: #afe1da; } -#header a { color: #afe1da; } +#header a { + color: #afe1da; +} #header h1 a, -#header a:hover { color: #fff; } +#header a:hover, +#header .active a { + color: #fff; +} #header h1 { font-weight: bold; margin: 0;