commit
e5b0ec6d7b
30 changed files with 3296 additions and 770 deletions
|
@ -4,7 +4,12 @@
|
|||
#RewriteBase /
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . index.php [L]
|
||||
RewriteRule ^(.*)$ index.php?$1 [L,QSA]
|
||||
RewriteRule ^(config|content|content-sample|lib|vendor)/.* - [R=404,L]
|
||||
|
||||
<IfModule mod_env.c>
|
||||
SetEnv PICO_URL_REWRITING 1
|
||||
</IfModule>
|
||||
</IfModule>
|
||||
|
||||
# Prevent file browsing
|
||||
|
|
29
.travis.yml
Normal file
29
.travis.yml
Normal file
|
@ -0,0 +1,29 @@
|
|||
language: php
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7
|
||||
- hhvm
|
||||
- nightly
|
||||
|
||||
script:
|
||||
- find . -type f -name '*.php' -print0 | xargs -0 -I file php -l file > /dev/null
|
||||
|
||||
before_deploy:
|
||||
- composer install
|
||||
- tar -czf "pico-release-$TRAVIS_TAG.tar.gz" .htaccess README.md changelog.txt composer.json composer.lock license.txt config content-sample lib plugins themes vendor index.php
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key: ${GITHUB_OAUTH_TOKEN}
|
||||
file: pico-release-$TRAVIS_TAG.tar.gz
|
||||
skip_cleanup: true
|
||||
on:
|
||||
repo: picocms/Pico
|
||||
tags: true
|
||||
php: 5.3
|
||||
|
||||
sudo: false
|
||||
|
197
CHANGELOG.md
Normal file
197
CHANGELOG.md
Normal file
|
@ -0,0 +1,197 @@
|
|||
Pico Changelog
|
||||
==============
|
||||
|
||||
### Version 1.0.0-beta.1
|
||||
Released: 2015-11-06
|
||||
|
||||
**Note:** This changelog only provides basic information about the enormous
|
||||
changes introduced with Pico 1.0.0-beta.1. Please refer to the
|
||||
UGPRADE section of the docs for details.
|
||||
|
||||
```
|
||||
* [Security] (9e2604a) Prevent content_dir breakouts using malicious URLs
|
||||
* [New] Pico is on its way to its first stable release!
|
||||
* [New] Provide pre-bundled releases
|
||||
* [New] Heavily expanded documentation (inline code docs, user docs, dev docs)
|
||||
* [New] New routing system using the QUERY_STRING method; Pico now works
|
||||
out-of-the-box with any webserver and without URL rewriting; use
|
||||
`%base_url%?sub/page` in markdown files and `{{ "sub/page"|link }}`
|
||||
in Twig templates to declare internal links
|
||||
* [New] Brand new plugin system with dependencies (see `PicoPluginInterface`
|
||||
and `AbstractPicoPlugin`); if you're plugin dev, you really should
|
||||
take a look at the UPGRADE section of the docs!
|
||||
* [New] Introducing the `PicoDeprecated` plugin to maintain full backward
|
||||
compatibility with Pico 0.9 and Pico 0.8
|
||||
* [New] Support YAML-style meta header comments (`---`)
|
||||
* [New] Various new placeholders to use in content files (e.g. `%site_title%`)
|
||||
* [New] Provide access to all meta headers in content files (`%meta.*%`)
|
||||
* [New] Provide access to meta headers in `$page` arrays (`$page['meta']`)
|
||||
* [New] The file extension of content files is now configurable
|
||||
* [New] Add `Pico::setConfig()` method to predefine config variables
|
||||
* [New] Supporting per-directory `404.md` files
|
||||
* [New] #103: Providing access to `sub.md` even when the `sub` directory
|
||||
exists, provided that there is no `sub/index.md`
|
||||
* [New] #249: Support the `.twig` file extension for templates
|
||||
* [New] #268, 269: Now using Travis CI; performing basic code tests and
|
||||
implementing an automatic release process
|
||||
* [Changed] Complete code refactoring
|
||||
* [Changed] Source code now follows PSR code styling
|
||||
* [Changed] Replacing constants (e.g. `ROOT_DIR`) with constructor parameters
|
||||
* [Changed] Paths (e.g. `content_dir`) are now relative to Pico's root dir
|
||||
* [Changed] Adding `Pico::run()` method that performs Pico's processing and
|
||||
returns the rendered contents
|
||||
* [Changed] Renaming all plugin events; adding some new events
|
||||
* [Changed] `Pico_Plugin` is now the fully documented `DummyPlugin`
|
||||
* [Changed] Meta data must start on the first line of the file now
|
||||
* [Changed] Dropping the need to register meta headers for the convenience of
|
||||
users and pure (!) theme devs; plugin devs are still REQUIRED to
|
||||
register their meta headers during `onMetaHeaders`
|
||||
* [Changed] Exclude inaccessible files from pages list
|
||||
* [Changed] With alphabetical order, index files (e.g. `sub/index.md`) are
|
||||
now always placed before their sub pages (e.g. `sub/foo.md`)
|
||||
* [Changed] Pico requires PHP >= 5.3.6 (due to `erusev/parsedown-extra`)
|
||||
* [Changed] Pico now implicitly uses a existing `content` directory without
|
||||
the need to configure this in the `config/config.php` explicitly
|
||||
* [Changed] Composer: Require a v0.7 release of `erusev/parsedown-extra`
|
||||
* [Changed] #93, #158: Pico doesn't parse all content files anymore; moved to
|
||||
`PicoParsePagesContent` plugin, but still impacts performance;
|
||||
Note: This means `$page['content']` isn't available anymore, but
|
||||
usually the new `$page['raw_content']` is suitable as replacement.
|
||||
* [Changed] #116: Parse meta headers using the Symfony YAML component
|
||||
* [Changed] #244: Replace opendir() with scandir()
|
||||
* [Changed] #246: Move `config.php` to `config/` directory
|
||||
* [Changed] #253: Assume HTTPS if page is requested through port 443
|
||||
* [Changed] A vast number of small improvements and changes...
|
||||
* [Fixed] Sorting by date now uses timestamps and works as expected
|
||||
* [Fixed] Fixing `$currentPage`, `$nextPage` and `$previousPage`
|
||||
* [Fixed] #99: Support content filenames with spaces
|
||||
* [Fixed] #140, #241: Use file paths as page identifiers rather than titles
|
||||
* [Fixed] #248: Always set a timezone; adding `$config['timezone']` option
|
||||
* [Fixed] A vast number of small bugs...
|
||||
* [Removed] Removing the default Twig cache dir
|
||||
* [Removed] Removing various empty `index.html` files
|
||||
* [Removed] Moving Pico's excerpt feature to `PicoExcerpt` plugin
|
||||
```
|
||||
|
||||
### Version 0.9
|
||||
Released: 2015-04-28
|
||||
|
||||
```
|
||||
* [New] Default theme is now mobile-friendly
|
||||
* [New] Description meta now available in content areas
|
||||
* [New] Add description to composer.json
|
||||
* [Changed] content folder is now content-sample
|
||||
* [Changed] config.php moved to config.php.template
|
||||
* [Changed] Updated documentation & wiki
|
||||
* [Changed] Removed Composer, Twig files in /vendor, you must run composer
|
||||
install now
|
||||
* [Changed] Localized date format; strftime() instead of date()
|
||||
* [Changed] Added ignore for tmp file extensions in the get_files() method
|
||||
* [Changed] michelf/php-markdown is replaced with erusev/parsedown-extra
|
||||
* [Changed] $config is no global variable anymore
|
||||
* [Fixed] Pico now only removes the 1st comment block in .md files
|
||||
* [Fixed] Issue wherein the alphabetical sorting of pages did not happen
|
||||
```
|
||||
|
||||
### Version 0.8
|
||||
Released: 2013-10-23
|
||||
|
||||
```
|
||||
* [New] Added ability to set template in content meta
|
||||
* [New] Added before_parse_content and after_parse_content hooks
|
||||
* [Changed] content_parsed hook is now deprecated
|
||||
* [Changed] Moved loading the config to nearer the beginning of the class
|
||||
* [Changed] Only append ellipsis in limit_words() when word count exceeds max
|
||||
* [Changed] Made private methods protected for better inheritance
|
||||
* [Fixed] Fixed get_protocol() method to work in more situations
|
||||
```
|
||||
|
||||
### Version 0.7
|
||||
Released: 2013-09-04
|
||||
|
||||
```
|
||||
* [New] Added before_read_file_meta and get_page_data plugin hooks to customize
|
||||
page meta data
|
||||
* [Changed] Make get_files() ignore dotfiles
|
||||
* [Changed] Make get_pages() ignore Emacs and temp files
|
||||
* [Changed] Use composer version of Markdown
|
||||
* [Changed] Other small tweaks
|
||||
* [Fixed] Date warnings and other small bugs
|
||||
```
|
||||
|
||||
### Version 0.6.2
|
||||
Released: 2013-05-07
|
||||
|
||||
```
|
||||
* [Changed] Replaced glob_recursive with get_files
|
||||
```
|
||||
|
||||
### Version 0.6.1
|
||||
Released: 2013-05-07
|
||||
|
||||
```
|
||||
* [New] Added "content" and "excerpt" fields to pages
|
||||
* [New] Added excerpt_length config setting
|
||||
```
|
||||
|
||||
### Version 0.6
|
||||
Released: 2013-05-06
|
||||
|
||||
```
|
||||
* [New] Added plugin functionality
|
||||
* [Changed] Other small cleanup
|
||||
```
|
||||
|
||||
### Version 0.5
|
||||
Released: 2013-05-03
|
||||
|
||||
```
|
||||
* [New] Added ability to order pages by "alpha" or "date" (asc or desc)
|
||||
* [New] Added prev_page, current_page, next_page and is_front_page template vars
|
||||
* [New] Added "Author" and "Date" title meta fields
|
||||
* [Changed] Added "twig_config" to settings
|
||||
* [Changed] Updated documentation
|
||||
* [Fixed] Query string 404 bug
|
||||
```
|
||||
|
||||
### Version 0.4.1
|
||||
Released: 2013-05-01
|
||||
|
||||
```
|
||||
* [New] Added CONTENT_EXT global
|
||||
* [Changed] Use .md files instead of .txt
|
||||
```
|
||||
|
||||
### Version 0.4
|
||||
Released: 2013-05-01
|
||||
|
||||
```
|
||||
* [New] Add get_pages() function for listing content
|
||||
* [New] Added changelog.txt
|
||||
* [Changed] Updated default theme
|
||||
* [Changed] Updated documentation
|
||||
```
|
||||
|
||||
### Version 0.3
|
||||
Released: 2013-04-27
|
||||
|
||||
```
|
||||
* [Fixed] get_config() function
|
||||
```
|
||||
|
||||
### Version 0.2
|
||||
Released: 2013-04-26
|
||||
|
||||
```
|
||||
* [Changed] Updated Twig
|
||||
* [Changed] Better checking for HTTPS
|
||||
* [Fixed] Add 404 header to 404 page
|
||||
* [Fixed] Case sensitive folder bug
|
||||
```
|
||||
|
||||
### Version 0.1
|
||||
Released: 2012-04-04
|
||||
|
||||
```
|
||||
* Initial release
|
||||
```
|
119
CONTRIBUTING.md
Normal file
119
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,119 @@
|
|||
Contributing to Pico
|
||||
====================
|
||||
|
||||
Pico aims to be a high quality Content Management System (CMS) but at the same time wants to give contributors freedom when submitting fixes or improvements.
|
||||
|
||||
As such we want to *encourage* but not obligate you, the contributor, to follow these guidelines. The only exception to this are the guidelines elucidated in the *Prevent `merge-hell`* section.
|
||||
|
||||
Having said that: we really appreciate it when you apply the guidelines in part or wholly as that will save us time which, in turn, we can spend on bugfixes and new features.
|
||||
|
||||
Issues
|
||||
------
|
||||
|
||||
If you want to report an *issue* with Pico's core, please create a new [Issue](https://github.com/picocms/Pico/issues) on GitHub. Concerning problems with plugins or themes, please refer to the website of the developer of this plugin or theme.
|
||||
|
||||
Before creating a [new Issue on GitHub](https://github.com/picocms/Pico/issues/new), please make sure the problem wasn't reported yet using [GitHubs search engine](https://github.com/picocms/Pico/search?type=Issues). Please describe your issue as clear as possible and always include steps to reproduce the problem.
|
||||
|
||||
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.
|
||||
|
||||
### Prevent `merge-hell`
|
||||
|
||||
Please do *not* develop your contribution on the `master` branch of your fork, but create a separate feature branch, that is based off the `master` branch, for each feature that you want to contribute.
|
||||
|
||||
> Not doing so means that if you decide to work on two separate features and place a pull request for one of them, that the changes of the other issue that you are working on is also submitted. Even if it is not completely finished.
|
||||
|
||||
To get more information about the usage of Git, please refer to the [Pro Git book](https://git-scm.com/book) written by Scott Chacon and/or [this help page of GitHub](https://help.github.com/articles/using-pull-requests).
|
||||
|
||||
### Pull Requests
|
||||
|
||||
Please keep in mind that pull requests should be small (i.e. one feature per request), stick to existing coding conventions and documentation should be updated if required. It's encouraged to make commits of logical units and check for unnecessary whitespace before committing (try `git diff --check`). Please reference issue numbers in your commit messages where appropriate.
|
||||
|
||||
### Coding Standards
|
||||
|
||||
Pico uses the [PSR-2 Coding Standard](http://www.php-fig.org/psr/psr-2/) as defined by the [PHP Framework Interoperability Group (PHP-FIG)](http://www.php-fig.org/).
|
||||
|
||||
For historical reasons we don't use formal namespaces. Markdown files in the `content-sample` folder (the inline documentation) must follow a hard limit of 80 characters line length.
|
||||
|
||||
It is recommended to check your code using [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer) using the `PSR2` standard using the following command:
|
||||
|
||||
$ ./bin/phpcs --standard=PSR2 [file(s)]
|
||||
|
||||
With this command you can specify a file or folder to limit which files it will check or omit that argument altogether, in which case the current directory is checked.
|
||||
|
||||
### Keep documentation in sync
|
||||
|
||||
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 the 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.
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
Pico follows [Semantic Versioning 2.0](http://semver.org) and uses version numbers like `MAJOR`.`MINOR`.`PATCH`. We will increment the:
|
||||
|
||||
- `MAJOR` version when we make incompatible API changes,
|
||||
- `MINOR` version when we add functionality in a backwards-compatible manner, and
|
||||
- `PATCH` version when we make backwards-compatible bug fixes.
|
||||
|
||||
For more information please refer to the http://semver.org website.
|
||||
|
||||
Branching
|
||||
---------
|
||||
|
||||
The `master` branch contains the current development version of Pico. It is likely *unstable* and *not ready for production use*. However, the `master` branch always consists of a deployable version of Pico.
|
||||
|
||||
Pico's actual development happens in separate development branches. Development branches are prefixed by:
|
||||
|
||||
- `feature/` for bigger features,
|
||||
- `enhancement/` for smaller improvements, and
|
||||
- `bugfix/` for bug fixes.
|
||||
|
||||
As soon as development reaches a point where feedback is appreciated, a [pull request](https://github.com/picocms/Pico/pulls) is opened. After some time (very soon for bug fixes, and other improvements should have a reasonable feedback phase) the pull request is merged into `master` and the development branch will be deleted.
|
||||
|
||||
Build & Release process
|
||||
-----------------------
|
||||
|
||||
This is work in progress. Please refer to [#268](https://github.com/picocms/Pico/issues/268) for details.
|
||||
|
||||
<!--
|
||||
|
||||
Defined below is a specification to which the Build and Release process of Pico should follow. We use `travis-ci` to automate the process, and each commit to `master` should be releasable.
|
||||
|
||||
#### Commit phase
|
||||
- Commit changes
|
||||
- Create & Push Git tag
|
||||
- Trigger automatic build process...
|
||||
|
||||
Example commit message:
|
||||
|
||||
Pico 1.0.1
|
||||
* [New] ...
|
||||
* [Changed] ...
|
||||
|
||||
*Please submit pull-requests with a properly
|
||||
formatted commit message/SemVer increase to avoid the need for manual amendments.*
|
||||
|
||||
#### Analysis phase
|
||||
- Run through `scrutinizer-ci`?
|
||||
|
||||
#### Packaging phase
|
||||
- Run composer locally
|
||||
- Create a ZIP archive (so vendor/ is included)
|
||||
- Build documentation, output goes to a new folder in the `gh-pages` branch
|
||||
|
||||
#### Release phase
|
||||
- Create new Git release at tag
|
||||
- Upload ZIP archive
|
||||
- Upload documentation to the `gh-pages` branch
|
||||
- Set Symlink for latest documentation (http://picocms.org/docs/latest)
|
||||
- Update release information on GitHub with:
|
||||
- Release title (taken from changelog)
|
||||
- Changelog
|
||||
|
||||
#### Announcements
|
||||
- Where to announce new Pico release?
|
||||
|
||||
-->
|
122
README.md
122
README.md
|
@ -1,58 +1,120 @@
|
|||
# Pico
|
||||
Pico
|
||||
====
|
||||
|
||||
[](https://scrutinizer-ci.com/g/theshka/Pico/build-status/LICENSE)
|
||||
[]()
|
||||
[](https://scrutinizer-ci.com/g/theshka/Pico/build-status/master) [](https://scrutinizer-ci.com/g/theshka/Pico/?branch=master)
|
||||
[](https://github.com/picocms/Pico/blob/master/LICENSE)
|
||||
[](https://github.com/picocms/Pico/releases/latest)
|
||||
[](https://travis-ci.org/picocms/Pico)
|
||||
[](https://scrutinizer-ci.com/g/theshka/Pico/?branch=master)
|
||||
|
||||
Pico is a stupidly simple, blazing fast, flat file CMS. See http://picocms.org/ for more info.
|
||||
|
||||
<!--flippa verify-->
|
||||
[](http://www.iloveopensource.io/projects/524c55dcca7964c617000756)
|
||||
|
||||
Requirements
|
||||
---
|
||||
Requires PHP 5.3+
|
||||
Install
|
||||
-------
|
||||
|
||||
Download
|
||||
---
|
||||
You can install the latest version either by downloading it from <http://picocms.org/> or use Git:
|
||||
You can install Pico either using a pre-bundled release or with composer. Pico is also available on [Packagist.org][] and may be included in other projects via `composer require picocms/pico`. Pico requires PHP 5.3+
|
||||
|
||||
#### Using a pre-bundled release
|
||||
|
||||
Just [download the latest Pico release][LatestRelease] and upload all files to the `httpdocs` directory (e.g. `/var/www/html`) of your server.
|
||||
|
||||
#### Composer
|
||||
|
||||
###### Step 1 - for users
|
||||
[Download the *source code* of Pico's latest release][LatestRelease], upload all files to the `httpdocs` directory (e.g. `/var/www/html`) of your server and navigate to the upload directory using a shell.
|
||||
|
||||
###### Step 1 - for developers
|
||||
Open a shell and navigate to the desired install directory of Pico within the `httpdocs` directory (e.g. `/var/www/html`) of your server. You can now clone Pico's Git repository as follows:
|
||||
```shell
|
||||
git clone https://github.com/picocms/Pico.git
|
||||
$ git clone https://github.com/picocms/Pico.git .
|
||||
```
|
||||
Please note that this gives you the current development version of Pico, what is likely *unstable* and *not ready for production use*!
|
||||
|
||||
###### Step 2
|
||||
Download [composer][] and run it with the `install` option:
|
||||
```shell
|
||||
$ curl -sS https://getcomposer.org/installer | php
|
||||
$ php composer.phar install
|
||||
```
|
||||
|
||||
Install
|
||||
---
|
||||
Download [composer](<https://getcomposer.org/>) and run it with install option.
|
||||
Upgrade
|
||||
-------
|
||||
|
||||
$ curl -sS https://getcomposer.org/installer | php
|
||||
$ php composer.phar install
|
||||
Upgrading Pico is very easy: You just have to replace all of Pico's files - that's it! Nevertheless you should *always* create a backup of your Pico installation before upgrading.
|
||||
|
||||
Pico follows [Semantic Versioning 2.0][SemVer] and uses version numbers like `MAJOR`.`MINOR`.`PATCH`. When we update...
|
||||
|
||||
- the `PATCH` version (e.g. `1.0.0` to `1.0.1`), we made backwards-compatible bug fixes. It's then sufficient to extract [Pico's latest release][LatestRelease] to your existing installation directory and overwriting all files.
|
||||
|
||||
- the `MINOR` version (e.g. `1.0` to `1.1`), we added functionality in a backwards-compatible manner, but anyway recommend you to "install" Pico newly. Backup all of your files, empty your installation directory and install Pico as elucidated above. You can then copy your `config/config.php` and `content` directory without any change. If applicable, you can also copy the folder of your custom theme within the `themes` directory. Provided that you're using plugins, also copy all of your plugins from the `plugins` directory.
|
||||
|
||||
- the `MAJOR` version (e.g. `1.0` to `2.0`), a appropriate upgrade tutorial will be provided.
|
||||
|
||||
Upgrading Pico 0.8 or 0.9 to Pico 1.0 is a special case. The new `PicoDeprecated` plugin ensures backwards compatibility, so you basically can follow the above upgrade instructions as if we updated the `MINOR` version. However, we recommend you to take some further steps to confine the necessity of `PicoDeprecated` as far as possible. For more information about what has changed with Pico 1.0 and a step-by-step upgrade tutorial, please refer to the [upgrade page of our website][HelpUpgrade].
|
||||
|
||||
Run
|
||||
---
|
||||
|
||||
The easiest way to Pico is using [the built-in web server on PHP](<http://php.net/manual/en/features.commandline.webserver.php>).
|
||||
You have nothing to consider specially, simply navigate to your Pico install using your favorite web browser. Pico's default contents will explain how to use your brand new, stupidly simple, blazing fast, flat file CMS.
|
||||
|
||||
$ php -S 0.0.0.0:8080
|
||||
#### You don't have a web server?
|
||||
Starting with PHP 5.4 the easiest way to try Pico is using [the built-in web server of PHP][PHPServer]. Please note that PHPs built-in web server is for development and testing purposes only!
|
||||
|
||||
Pico will be accessible from <http://localhost:8080>.
|
||||
###### Step 1
|
||||
Navigate to Pico's installation directory using a shell.
|
||||
|
||||
###### Step 2
|
||||
Start PHPs built-in web server:
|
||||
```shell
|
||||
$ php -S 127.0.0.1:8080
|
||||
```
|
||||
|
||||
###### Step 3
|
||||
Access Pico from http://localhost:8080.
|
||||
|
||||
Getting Help
|
||||
---
|
||||
You can read the wiki if you are looking for examples and read the inline-docs for more development information.
|
||||
------------
|
||||
|
||||
If you find a bug please report it on the issues page, but remember to include as much detail as possible, and what someone can do to re-create the issue.
|
||||
#### Getting Help as a user
|
||||
If you want to get started using Pico, please refer to our [user docs][HelpUserDocs]. Please read the [upgrade notes][HelpUpgrade] if you want to upgrade from Pico 0.8 or 0.9 to Pico 1.0. You can find officially supported plugins and themes on [our website][OfficialPlugins]. A greater choice of third-party plugins and themes can be found in our [Wiki][] on the [plugins][WikiPlugins] or [themes][WikiThemes] pages respectively. If you want to create your own plugin or theme, please refer to the "Getting Help as a developer" section below.
|
||||
|
||||
Issues with plugins should be reported on the offending plugins homepage, same goes for themes.
|
||||
#### Getting Help as a developer
|
||||
If you're a developer, please refer to the "Contributing" section below and our [contribution guidelines][ContributionGuidelines]. To get you started with creating a plugin or theme, please read the [dev docs on our website][HelpDevDocs].
|
||||
|
||||
#### You still need help or experience a problem with Pico?
|
||||
When the docs can't answer your question or when you're experiencing problems with Pico, please don't hesitate to create a new [Issue][Issues] on GitHub. Concerning problems with plugins or themes, please refer to the website of the developer of this plugin or theme.
|
||||
|
||||
**Before creating a new Issue,** please make sure the problem wasn't reported yet using [GitHubs search engine][IssuesSearch]. Please describe your issue as clear as possible and always include steps to reproduce the problem.
|
||||
|
||||
Contributing
|
||||
---
|
||||
Help make PicoCMS better by checking out the GitHub repository and submitting pull requests.
|
||||
------------
|
||||
|
||||
If you create a plugin please add it to the Wiki.
|
||||
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:
|
||||
|
||||
Plugins + Wiki
|
||||
---
|
||||
Pico can be extended with a wide variety of plugins in order to add extra functionality, speed, or features.
|
||||
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!
|
||||
|
||||
Visit the [Pico Wiki](https://github.com/picocms/Pico/wiki) for docs, plugins, themes, etc...
|
||||
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].
|
||||
|
||||
3. Pico's Core: The supreme discipline is to work on Pico's Core. Your contribution should help *every* Pico user to have a better experience with Pico. If this is the case, fork Pico from https://github.com/picocms/Pico and open a [pull request][PullRequests]. We look forward to your contribution!
|
||||
|
||||
[Packagist.org]: http://packagist.org/packages/picocms/pico
|
||||
[LatestRelease]: https://github.com/picocms/Pico/releases/latest
|
||||
[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
|
||||
[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
|
||||
[Issues]: https://github.com/picocms/Pico/issues
|
||||
[IssuesSearch]: https://github.com/picocms/Pico/search?type=Issues
|
||||
[PullRequests]: https://github.com/picocms/Pico/pulls
|
||||
[ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md
|
||||
[EditInlineDocs]: https://github.com/picocms/Pico/blob/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
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
*** Pico Changelog ***
|
||||
|
||||
2015.04.28 - version 0.9
|
||||
* [New] Default theme is now mobile-friendly
|
||||
* [New] Description meta now available in content areas
|
||||
* [Changed] content folder is now content-sample
|
||||
* [Changed] Updated documentation & wiki
|
||||
* [Changed] Removed Composer, Twig files in /vendor, you must run composer install now
|
||||
* [Changed] Localized date format; strftime() instead of date()
|
||||
* [Changed] Added ignore for tmp file extensions in the get_files() method
|
||||
* [Fixed] Pico now only removes the 1st comment block in .md file
|
||||
* [Fixed] Issue wherein the alphabetical sorting of pages did not happen
|
||||
|
||||
2013.10.23 - version 0.8
|
||||
* [New] Added ability to set template in content meta
|
||||
* [New] Added before_parse_content and after_parse_content hooks
|
||||
* [Changed] content_parsed hook is now depreciated
|
||||
* [Changed] Moved loading the config to nearer the beginning of the class
|
||||
* [Changed] Only append ellipsis in limit_words() when word count exceeds max
|
||||
* [Changed] Made private methods protected for better inheritance
|
||||
* [Fixed] Fixed get_protocol() method to work in more situations
|
||||
|
||||
2013.09.04 - version 0.7
|
||||
* [New] Added before_read_file_meta and get_page_data plugin hooks to customize page meta data
|
||||
* [Changed] Make get_files() ignore dotfiles
|
||||
* [Changed] Make get_pages() ignore Emacs and temp files
|
||||
* [Changed] Use composer version of Markdown
|
||||
* [Changed] Other small tweaks
|
||||
* [Fixed] Date warnings and other small bugs
|
||||
|
||||
2013.05.07 - version 0.6.2
|
||||
* [Changed] Replaced glob_recursive with get_files
|
||||
|
||||
2013.05.07 - version 0.6.1
|
||||
* [New] Added "content" and "excerpt" fields to pages
|
||||
* [New] Added excerpt_length config setting
|
||||
|
||||
2013.05.06 - version 0.6
|
||||
* [New] Added plugin functionality
|
||||
* [Changed] Other small cleanup
|
||||
|
||||
2013.05.03 - version 0.5
|
||||
* [New] Added ability to order pages by "alpha" or "date" (asc or desc)
|
||||
* [New] Added prev_page, current_page, next_page and is_front_page template vars
|
||||
* [New] Added "Author" and "Date" title meta fields
|
||||
* [Changed] Added "twig_config" to settings
|
||||
* [Changed] Updated documentation
|
||||
* [Fixed] Query string 404 bug
|
||||
|
||||
2013.05.01 - version 0.4.1
|
||||
* [New] Added CONTENT_EXT global
|
||||
* [Changed] Use .md files instead of .txt
|
||||
|
||||
2013.05.01 - version 0.4
|
||||
* [New] Add get_pages() function for listing content
|
||||
* [New] Added changelog.txt
|
||||
* [Changed] Updated default theme
|
||||
* [Changed] Updated documentation
|
||||
|
||||
2013.04.27 - version 0.3
|
||||
* [Fixed] get_config() function
|
||||
|
||||
2013.04.26 - version 0.2
|
||||
* [Changed] Updated Twig
|
||||
* [Changed] Better checking for HTTPS
|
||||
* [Fixed] Add 404 header to 404 page
|
||||
* [Fixed] Case sensitive folder bug
|
||||
|
||||
2012.04.04 - version 0.1
|
||||
* Initial release
|
|
@ -12,11 +12,16 @@
|
|||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.3.2",
|
||||
"php": ">=5.3.6",
|
||||
"twig/twig": "1.18.*",
|
||||
"erusev/parsedown-extra": "dev-master@dev"
|
||||
"erusev/parsedown-extra": "0.7.*",
|
||||
"symfony/yaml" : "2.3"
|
||||
},
|
||||
"autoload": {
|
||||
"files": ["lib/pico.php"]
|
||||
"psr-0": {
|
||||
"Pico": "lib/",
|
||||
"PicoPluginInterface": "lib/",
|
||||
"AbstractPicoPlugin": "lib/"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,18 +1,19 @@
|
|||
<?php
|
||||
/**
|
||||
* Pico Configuration
|
||||
* Pico configuration
|
||||
*
|
||||
* This is the configuration file for Pico. It comes loaded with the
|
||||
* default values, which can be found in the get_config() method of
|
||||
* the Pico class (lib/pico.php).
|
||||
*
|
||||
* @author Gilbert Pellegrom
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 0.9
|
||||
* This is the configuration file for {@link Pico}. It comes loaded with the
|
||||
* default values, which can be found in {@link Pico::getConfig()} (see
|
||||
* {@path "lib/Pico.php"}).
|
||||
*
|
||||
* To override any of the default settings below, copy this file to
|
||||
* `config.php`, uncomment the line and make and save your changes.
|
||||
* {@path "config/config.php"}, uncomment the line, then make and
|
||||
* save your changes.
|
||||
*
|
||||
* @author Gilbert Pellegrom
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -20,35 +21,38 @@
|
|||
*/
|
||||
// $config['site_title'] = 'Pico'; // Site title
|
||||
// $config['base_url'] = ''; // Override base URL (e.g. http://example.com)
|
||||
// $config['rewrite_url'] = null; // A boolean indicating forced URL rewriting
|
||||
|
||||
/*
|
||||
* THEME
|
||||
*/
|
||||
// $config['theme'] = 'default'; // Set the theme (defaults to "default")
|
||||
// $config['twig_config'] = array( // Twig settings
|
||||
// 'cache' => false, // To enable Twig caching change this to CACHE_DIR
|
||||
// 'autoescape' => false, // Autoescape Twig vars
|
||||
// 'debug' => false // Enable Twig debug
|
||||
// 'cache' => false, // To enable Twig caching change this to a path to a writable directory
|
||||
// 'autoescape' => false, // Auto-escape Twig vars
|
||||
// 'debug' => false // Enable Twig debug
|
||||
// );
|
||||
|
||||
/*
|
||||
* CONTENT
|
||||
*/
|
||||
// $config['date_format'] = '%D %T'; // Set the PHP date format as described here: http://php.net/manual/en/function.strftime.php
|
||||
// $config['pages_order_by'] = 'alpha'; // Order pages by "alpha" or "date"
|
||||
// $config['pages_order'] = 'asc'; // Order pages "asc" or "desc"
|
||||
// $config['excerpt_length'] = 50; // The pages excerpt length (in words)
|
||||
// $config['content_dir'] = 'content-sample/'; // Content directory
|
||||
// $config['date_format'] = '%D %T'; // Set the PHP date format as described here: http://php.net/manual/en/function.strftime.php
|
||||
// $config['pages_order_by'] = 'alpha'; // Order pages by "alpha" or "date"
|
||||
// $config['pages_order'] = 'asc'; // Order pages "asc" or "desc"
|
||||
// $config['content_dir'] = 'content-sample/'; // Content directory
|
||||
// $config['content_ext'] = '.md'; // File extension of content files to serve
|
||||
|
||||
/*
|
||||
* TIMEZONE
|
||||
*/
|
||||
// date_default_timezone_set('UTC'); // Timezone may be reqired by your php install
|
||||
// $config['timezone'] = 'UTC'; // Timezone may be required by your php install
|
||||
|
||||
/*
|
||||
* PLUGINS
|
||||
*/
|
||||
// $config['DummyPlugin.enabled'] = false; // Force DummyPlugin to be disabled
|
||||
|
||||
/*
|
||||
* CUSTOM
|
||||
*/
|
||||
// $config['custom_setting'] = 'Hello'; // Can be accessed by {{ config.custom_setting }} in a theme
|
||||
|
||||
// Keep this line
|
||||
return $config;
|
||||
// $config['custom_setting'] = 'Hello'; // Can be accessed by {{ config.custom_setting }} in a theme
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/*
|
||||
---
|
||||
Title: Error 404
|
||||
Robots: noindex,nofollow
|
||||
*/
|
||||
---
|
||||
|
||||
Error 404
|
||||
=========
|
||||
|
||||
Woops. Looks like this page doesn't exist.
|
||||
Woops. Looks like this page doesn't exist.
|
||||
|
|
|
@ -1,109 +1,286 @@
|
|||
/*
|
||||
---
|
||||
Title: Welcome
|
||||
Description: This description will go in the meta description tag
|
||||
*/
|
||||
Description: Pico is a stupidly simple, blazing fast, flat file CMS.
|
||||
---
|
||||
|
||||
## Welcome to Pico
|
||||
|
||||
Congratulations, you have successfully installed [Pico](http://picocms.org/). Pico is a stupidly simple, blazing fast, flat file CMS.
|
||||
Congratulations, you have successfully installed [Pico](http://picocms.org/).
|
||||
%meta.description% <!-- replaced by the above Description meta header -->
|
||||
|
||||
### Creating Content
|
||||
## Creating Content
|
||||
|
||||
Pico is a flat file CMS, this means there is no administration backend and 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` and is shown as the main landing page.
|
||||
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`
|
||||
and is shown as the main landing page.
|
||||
|
||||
If you create a folder within the content-sample folder (e.g. `content-sample/sub`) and put an `index.md` inside it, you can access that folder at the URL
|
||||
`http://yoursite.com/sub`. If you want another page within the sub folder, simply create a text file with the corresponding name (e.g. `content-sample/sub/page.md`)
|
||||
and you will be able to access it from the URL `http://yoursite.com/sub/page`. Below we've shown some examples of content-sample locations and their corresponing URL's:
|
||||
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,
|
||||
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:
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr><th>Physical Location</th><th>URL</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td>content-sample/index.md</td><td>/</td></tr>
|
||||
<tr><td>content-sample/sub.md</td><td>/sub</td></tr>
|
||||
<tr><td>content-sample/sub/index.md</td><td>/sub (same as above)</td></tr>
|
||||
<tr><td>content-sample/sub/page.md</td><td>/sub/page</td></tr>
|
||||
<tr><td>content-sample/a/very/long/url.md</td><td>/a/very/long/url</td></tr>
|
||||
</tbody>
|
||||
<table style="width: 100%; max-width: 40em;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 50%;">Physical Location</th>
|
||||
<th style="width: 50%;">URL</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>content-sample/index.md</td>
|
||||
<td><a href="%base_url%">/</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>content-sample/sub.md</td>
|
||||
<td><del>?sub</del> (not accessible, see below)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>content-sample/sub/index.md</td>
|
||||
<td><a href="%base_url%?sub">?sub</a> (same as above)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>content-sample/sub/page.md</td>
|
||||
<td><a href="%base_url%?sub/page">?sub/page</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>content-sample/a/very/long/url.md</td>
|
||||
<td><a href="%base_url%?a/very/long/url">?a/very/long/url</a> (doesn't exist)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
If a file cannot be found, the file `content-sample/404.md` will be shown.
|
||||
If a file cannot be found, the file `content-sample/404.md` will be shown. You
|
||||
can add `404.md` files to any directory, so if you want to use a special error
|
||||
page for your blog, simply create `content-sample/blog/404.md`.
|
||||
|
||||
Instead of adding your own content to the `content-sample` folder, you should
|
||||
create your own `content` directory in Pico's root directory. You can then add
|
||||
and access your contents as described above.
|
||||
|
||||
### Text File Markup
|
||||
|
||||
Text files are marked up using [Markdown](http://daringfireball.net/projects/markdown/syntax). They can also contain regular HTML.
|
||||
Text files are marked up using [Markdown][]. They can also contain regular HTML.
|
||||
|
||||
At the top of text files you can place a block comment and specify certain attributes of the page. For example:
|
||||
At the top of text files you can place a block comment and specify certain
|
||||
attributes of the page. For example:
|
||||
|
||||
/*
|
||||
Title: Welcome
|
||||
Description: This description will go in the meta description tag
|
||||
Author: Joe Bloggs
|
||||
Date: 2013/01/01
|
||||
Robots: noindex,nofollow
|
||||
*/
|
||||
---
|
||||
Title: Welcome
|
||||
Description: This description will go in the meta description tag
|
||||
Author: Joe Bloggs
|
||||
Date: 2013/01/01
|
||||
Robots: noindex,nofollow
|
||||
Template: index
|
||||
---
|
||||
|
||||
These values will be contained in the `{{ meta }}` variable in themes (see below).
|
||||
These values will be contained in the `{{ meta }}` variable in themes
|
||||
(see below).
|
||||
|
||||
There are also certain variables that you can use in your text files:
|
||||
|
||||
* <code>%base_url%</code> - The URL to your Pico site
|
||||
* <code>%site_title%</code> - The title of your Pico site
|
||||
* <code>%base_url%</code> - The URL to your Pico site; internal links
|
||||
can be specified using <code>%base_url%?sub/page</code>
|
||||
* <code>%theme_url%</code> - The URL to the currently used theme
|
||||
* <code>%meta.*%</code> - Access any meta variable of the current page,
|
||||
e.g. <code>%meta.author%</code> is replaced with `Joe Bloggs`
|
||||
|
||||
### Blogging
|
||||
|
||||
Pico is not blogging software - but makes it very easy for you to use it as a
|
||||
blog. You can find many plugins out there implementing typical blogging
|
||||
features like authentication, tagging, pagination and social plugins. See the
|
||||
below Plugins section for details.
|
||||
|
||||
If you want to use Pico as a blogging software, you probably want to do
|
||||
something like the following:
|
||||
1. Put all your blog articles in a separate `blog` folder in your `content`
|
||||
directory. All these articles should have both a `Date` and `Template` meta
|
||||
header, the latter with e.g. `blog-post` as value (see Step 2).
|
||||
2. Create a new Twig template called `blog-post.twig` (this must match the
|
||||
`Template` meta header from Step 1) in your theme directory. This template
|
||||
probably isn't very different from your default `index.twig`, it specifies
|
||||
how your article pages will look like.
|
||||
3. Create a `blog.md` in your `content` folder and set its `Template` meta
|
||||
header to e.g. `blog`. Also create a `blog.twig` in your theme directory.
|
||||
This template will show a list of your articles, so you probably want to
|
||||
do something like this:
|
||||
```
|
||||
{% for page in pages %}
|
||||
{% if page.id starts with "blog/" %}
|
||||
<div class="post">
|
||||
<h3><a href="{{ page.url }}">{{ page.title }}</a></h3>
|
||||
<p class="date">{{ page.date_formatted }}</p>
|
||||
<p class="excerpt">{{ page.description }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
```
|
||||
4. Let Pico sort pages by date by setting `$config['pages_order_by'] = 'date';`
|
||||
in your `config/config.php`. To use a descending order (newest articles
|
||||
first), also add `$config['pages_order'] = 'desc';`. The former won't affect
|
||||
pages without a `Date` meta header, but the latter does. To use ascending
|
||||
order for your page navigation again, add Twigs `reverse` filter to the
|
||||
navigation loop (`{% for page in pages|reverse %}...{% endfor %}`) in your
|
||||
themes `index.twig`.
|
||||
5. Make sure to exclude the blog articles from your page navigation. You can
|
||||
achieve this by adding `{% if not page starts with "blog/" %}...{% endif %}`
|
||||
to the navigation loop.
|
||||
|
||||
## Customization
|
||||
|
||||
Pico is highly customizable in two different ways: On the one hand you can
|
||||
change Pico's appearance by using themes, on the other hand you can add new
|
||||
functionality by using plugins. Doing the former includes changing Pico's HTML,
|
||||
CSS and JavaScript, the latter mostly consists of PHP programming.
|
||||
|
||||
This is all Greek to you? Don't worry, you don't have to spend time on these
|
||||
techie talk - it's very easy to use one of the great themes or plugins others
|
||||
developed and released to the public. Please refer to the next sections for
|
||||
details.
|
||||
|
||||
### Themes
|
||||
|
||||
You can create themes for your Pico installation in the "themes" folder. Check out the default theme for an example of a theme. Pico uses
|
||||
[Twig](http://twig.sensiolabs.org/documentation) for it's templating engine. You can select your theme by setting the `$config['theme']` variable
|
||||
in `config/config.php` to your theme folder.
|
||||
You can create themes for your Pico installation in the `themes` folder. Check
|
||||
out the default theme for an example. Pico uses [Twig][] for template
|
||||
rendering. You can select your theme by setting the `$config['theme']` option
|
||||
in `config/config.php` to the name of your theme folder.
|
||||
|
||||
All themes must include an `index.html` file to define the HTML structure of the theme. Below are the Twig variables that are available to use in your theme:
|
||||
All themes must include an `index.twig` (or `index.html`) file to define the
|
||||
HTML structure of the theme. Below are the Twig variables that are available
|
||||
to use in your theme. Please note that paths (e.g. `{{ base_dir }}`) and URLs
|
||||
(e.g. `{{ base_url }}`) don't have a trailing slash.
|
||||
|
||||
* `{{ config }}` - Conatins the values you set in `config/config.php` (e.g. `{{ config.theme }}` = "default")
|
||||
* `{{ config }}` - Conatins the values you set in `config/config.php`
|
||||
(e.g. `{{ config.theme }}` becomes `default`)
|
||||
* `{{ base_dir }}` - The path to your Pico root directory
|
||||
* `{{ base_url }}` - The URL to your Pico site
|
||||
* `{{ theme_dir }}` - The path to the Pico active theme directory
|
||||
* `{{ theme_url }}` - The URL to the Pico active theme directory
|
||||
* `{{ site_title }}` - Shortcut to the site title (defined in `config/config.php`)
|
||||
* `{{ base_url }}` - The URL to your Pico site; use Twigs `link` filter to
|
||||
specify internal links (e.g. `{{ "sub/page"|link }}`),
|
||||
this guarantees that your link works whether URL rewriting
|
||||
is enabled or not
|
||||
* `{{ theme_dir }}` - The path to the currently active theme
|
||||
* `{{ theme_url }}` - The URL to the currently active theme
|
||||
* `{{ rewrite_url }}` - A boolean flag indicating enabled/disabled URL rewriting
|
||||
* `{{ site_title }}` - Shortcut to the site title (see `config/config.php`)
|
||||
* `{{ meta }}` - Contains the meta values from the current page
|
||||
* `{{ meta.title }}`
|
||||
* `{{ meta.description }}`
|
||||
* `{{ meta.author }}`
|
||||
* `{{ meta.date }}`
|
||||
* `{{ meta.date_formatted }}`
|
||||
* `{{ meta.robots }}`
|
||||
* `{{ content-sample }}` - The content-sample of the current page (after it has been processed through Markdown)
|
||||
* `{{ pages }}` - A collection of all the content-sample in your site
|
||||
* `{{ page.title }}`
|
||||
* `{{ page.url }}`
|
||||
* `{{ page.author }}`
|
||||
* `{{ page.date }}`
|
||||
* `{{ page.date_formatted }}`
|
||||
* `{{ page.content-sample }}`
|
||||
* `{{ page.excerpt }}`
|
||||
* `{{ prev_page }}` - A page object of the previous page (relative to current_page)
|
||||
* `{{ current_page }}` - A page object of the current_page
|
||||
* `{{ next_page }}` - A page object of the next page (relative to current_page)
|
||||
* `{{ meta.title }}`
|
||||
* `{{ meta.description }}`
|
||||
* `{{ meta.author }}`
|
||||
* `{{ meta.date }}`
|
||||
* `{{ meta.date_formatted }}`
|
||||
* `{{ meta.time }}`
|
||||
* `{{ meta.robots }}`
|
||||
* ...
|
||||
* `{{ content }}` - The content of the current page
|
||||
(after it has been processed through Markdown)
|
||||
* `{{ pages }}` - A collection of all the content pages in your site
|
||||
* `{{ page.id }}` - The relative path to the content file (unique ID)
|
||||
* `{{ page.url }}` - The URL to the page
|
||||
* `{{ page.title }}` - The title of the page (YAML header)
|
||||
* `{{ page.description }}` - The description of the page (YAML header)
|
||||
* `{{ page.author }}` - The author of the page (YAML header)
|
||||
* `{{ page.time }}` - The timestamp derived from the `Date` header
|
||||
* `{{ page.date }}` - The date of the page (YAML header)
|
||||
* `{{ page.date_formatted }}` - The formatted date of the page
|
||||
* `{{ page.raw_content }}` - The raw, not yet parsed contents of the page;
|
||||
use Twigs `content` filter to get the parsed
|
||||
contents of a page by passing its unique ID
|
||||
(e.g. `{{ "sub/page"|content }}`)
|
||||
* `{{ page.meta }}`- The meta values of the page
|
||||
* `{{ prev_page }}` - The data of the previous page (relative to `current_page`)
|
||||
* `{{ current_page }}` - The data of the current page
|
||||
* `{{ next_page }}` - The data of the next page (relative to `current_page`)
|
||||
* `{{ is_front_page }}` - A boolean flag for the front page
|
||||
|
||||
Pages can be used like:
|
||||
Pages can be used like the following:
|
||||
|
||||
<pre><ul class="nav">
|
||||
{% for page in pages %}
|
||||
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul></pre>
|
||||
<ul class="nav">
|
||||
{% for page in pages %}
|
||||
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
You can use different templates for different content files by specifying the
|
||||
`Template` meta header. Simply add e.g. `Template: blog-post` to a content file
|
||||
and Pico will use the `blog-post.twig` file in your theme folder to render
|
||||
the page.
|
||||
|
||||
You don't have to create your own theme if Pico's default theme isn't
|
||||
sufficient for you, you can use one of the great themes third-party developers
|
||||
and designers created in the past. As with plugins, you can find themes in
|
||||
[our Wiki][WikiThemes].
|
||||
|
||||
### Plugins
|
||||
|
||||
See [http://pico.dev7studios.com/plugins](http://picocms.org/plugins)
|
||||
#### Plugins for users
|
||||
|
||||
### Config
|
||||
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].
|
||||
|
||||
You can override the default Pico settings (and add your own custom settings) by editing `config/config.php` in the Pico directory.
|
||||
The `config/config.php.template` lists all of the settings and their defaults. To override a setting simply copy
|
||||
`config/config.php.template` to `config/config.php`, uncomment the setting and set your custom value.
|
||||
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.
|
||||
Depending on the plugin you've installed, you may have to go through some more
|
||||
steps (e.g. specifying config variables), the plugin docs or `README` file will
|
||||
explain what to do.
|
||||
|
||||
### Documentation
|
||||
Plugins which were written to work with Pico 1.0 can be enabled and disabled
|
||||
through your `config/config.php`. If you want to e.g. disable the `PicoExcerpt`
|
||||
plugin, add the following line to your `config/config.php`:
|
||||
`$config['PicoExcerpt.enabled'] = false;`. To force the plugin to be enabled
|
||||
replace `false` with `true`.
|
||||
|
||||
For more help have a look at the Pico documentation at [http://picocms.org/docs](http://picocms.org/docs)
|
||||
#### 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
|
||||
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].
|
||||
|
||||
## Config
|
||||
|
||||
You can override the default Pico settings (and add your own custom settings)
|
||||
by editing `config/config.php` in the Pico directory. For a brief overview of
|
||||
the available settings and their defaults see `config/config.php.template`. To
|
||||
override a setting, copy `config/config.php.template` to `config/config.php`,
|
||||
uncomment the setting and set your custom value.
|
||||
|
||||
### URL Rewriting
|
||||
|
||||
Pico's default URLs (e.g. %base_url%/?sub/page) already are very user-friendly.
|
||||
Additionally, Pico offers you a URL rewrite feature to make URLs even more
|
||||
user-friendly (e.g. %base_url%/sub/page).
|
||||
|
||||
If you're using the Apache web server, URL rewriting probably already is
|
||||
enabled - try it yourself, click on the [second URL](%base_url%/sub/page). If
|
||||
you get an error message from your web server, please make sure to enable the
|
||||
[`mod_rewrite` module][ModRewrite]. Assuming the second URL works, but Pico
|
||||
still shows no rewritten URLs, force URL rewriting by setting
|
||||
`$config['rewrite_url'] = true;` in your `config/config.php`.
|
||||
|
||||
If you're using Nginx, you can use the following configuration to enable
|
||||
URL rewriting. Don't forget to adjust the path (`/pico/`; line `1` and `4`)
|
||||
to match your installation directory. You can then enable URL rewriting by
|
||||
setting `$config['rewrite_url'] = true;` in your `config/config.php`.
|
||||
|
||||
location /pico/ {
|
||||
index index.php;
|
||||
try_files $uri $uri/ /pico/?$uri&$args;
|
||||
}
|
||||
|
||||
## Documentation
|
||||
|
||||
For more help have a look at the Pico documentation at http://picocms.org/docs.
|
||||
|
||||
[Markdown]: http://daringfireball.net/projects/markdown/syntax
|
||||
[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
|
||||
[ModRewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
---
|
||||
Title: Sub Page Index
|
||||
*/
|
||||
---
|
||||
|
||||
## This is a Sub Page Index
|
||||
|
||||
This is index.md in the "sub" folder.
|
||||
This is `index.md` in the `sub` folder.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies tristique nulla et mattis. Phasellus id massa eget nisl congue blandit sit amet id ligula. Praesent et nulla eu augue tempus sagittis. Mauris faucibus nibh et nibh cursus in vestibulum sapien egestas. Curabitur ut lectus tortor. Sed ipsum eros, egestas ut eleifend non, elementum vitae eros. Mauris felis diam, pellentesque vel lacinia ac, dictum a nunc. Mauris mattis nunc sed mi sagittis et facilisis tortor volutpat. Etiam tincidunt urna mattis erat placerat placerat ac eu tellus. Ut nec velit id nisl tincidunt vehicula id a metus. Pellentesque erat neque, faucibus id ultricies vel, mattis in ante. Donec lobortis, mauris id congue scelerisque, diam nisl accumsan orci, condimentum porta est magna vel arcu. Curabitur varius ante dui. Vivamus sit amet ante ac diam ullamcorper sodales sed a odio.
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*
|
||||
---
|
||||
Title: Sub Page
|
||||
*/
|
||||
---
|
||||
|
||||
## This is a Sub Page
|
||||
|
||||
This is page.md in the "sub" folder.
|
||||
This is `page.md` in the `sub` folder.
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ultricies tristique nulla et mattis. Phasellus id massa eget nisl congue blandit sit amet id ligula. Praesent et nulla eu augue tempus sagittis. Mauris faucibus nibh et nibh cursus in vestibulum sapien egestas. Curabitur ut lectus tortor. Sed ipsum eros, egestas ut eleifend non, elementum vitae eros. Mauris felis diam, pellentesque vel lacinia ac, dictum a nunc. Mauris mattis nunc sed mi sagittis et facilisis tortor volutpat. Etiam tincidunt urna mattis erat placerat placerat ac eu tellus. Ut nec velit id nisl tincidunt vehicula id a metus. Pellentesque erat neque, faucibus id ultricies vel, mattis in ante. Donec lobortis, mauris id congue scelerisque, diam nisl accumsan orci, condimentum porta est magna vel arcu. Curabitur varius ante dui. Vivamus sit amet ante ac diam ullamcorper sodales sed a odio.
|
||||
|
||||
|
|
24
index.php
24
index.php
|
@ -1,15 +1,17 @@
|
|||
<?php
|
||||
// load dependencies
|
||||
require_once(__DIR__ . '/vendor/autoload.php');
|
||||
|
||||
define('ROOT_DIR', realpath(dirname(__FILE__)) . '/');
|
||||
define('LIB_DIR', ROOT_DIR . 'lib/');
|
||||
define('VENDOR_DIR', ROOT_DIR . 'vendor/');
|
||||
define('PLUGINS_DIR', ROOT_DIR . 'plugins/');
|
||||
define('THEMES_DIR', ROOT_DIR . 'themes/');
|
||||
define('CONFIG_DIR', ROOT_DIR . 'config/');
|
||||
define('CACHE_DIR', LIB_DIR . 'cache/');
|
||||
// instance Pico
|
||||
$pico = new Pico(
|
||||
__DIR__, // root dir
|
||||
'config/', // config dir
|
||||
'plugins/', // plugins dir
|
||||
'themes/' // themes dir
|
||||
);
|
||||
|
||||
define('CONTENT_EXT', '.md');
|
||||
// override configuration?
|
||||
// $pico->setConfig(array());
|
||||
|
||||
require_once(VENDOR_DIR . 'autoload.php');
|
||||
require_once(LIB_DIR . 'pico.php');
|
||||
$pico = new Pico();
|
||||
// run application
|
||||
echo $pico->run();
|
||||
|
|
255
lib/AbstractPicoPlugin.php
Normal file
255
lib/AbstractPicoPlugin.php
Normal file
|
@ -0,0 +1,255 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Abstract class to extend from when implementing a Pico plugin
|
||||
*
|
||||
* @see PicoPluginInterface
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||
{
|
||||
/**
|
||||
* Current instance of Pico
|
||||
*
|
||||
* @see PicoPluginInterface::getPico()
|
||||
* @var Pico
|
||||
*/
|
||||
private $pico;
|
||||
|
||||
/**
|
||||
* Boolean indicating if this plugin is enabled (true) or disabled (false)
|
||||
*
|
||||
* @see PicoPluginInterface::isEnabled()
|
||||
* @see PicoPluginInterface::setEnabled()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $enabled = true;
|
||||
|
||||
/**
|
||||
* Boolean indicating if this plugin was ever enabled/disabled manually
|
||||
*
|
||||
* @see PicoPluginInterface::isStatusChanged()
|
||||
* @var boolean
|
||||
*/
|
||||
protected $statusChanged = false;
|
||||
|
||||
/**
|
||||
* List of plugins which this plugin depends on
|
||||
*
|
||||
* @see AbstractPicoPlugin::checkDependencies()
|
||||
* @see PicoPluginInterface::getDependencies()
|
||||
* @var string[]
|
||||
*/
|
||||
protected $dependsOn = array();
|
||||
|
||||
/**
|
||||
* List of plugin which depend on this plugin
|
||||
*
|
||||
* @see AbstractPicoPlugin::checkDependants()
|
||||
* @see PicoPluginInterface::getDependants()
|
||||
* @var object[]
|
||||
*/
|
||||
private $dependants;
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::__construct()
|
||||
*/
|
||||
public function __construct(Pico $pico)
|
||||
{
|
||||
$this->pico = $pico;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::handleEvent()
|
||||
*/
|
||||
public function handleEvent($eventName, array $params)
|
||||
{
|
||||
// plugins can be enabled/disabled using the config
|
||||
if ($eventName === 'onConfigLoaded') {
|
||||
$pluginEnabled = $this->getConfig(get_called_class() . '.enabled');
|
||||
if ($pluginEnabled !== null) {
|
||||
$this->setEnabled($pluginEnabled);
|
||||
} else {
|
||||
$pluginConfig = $this->getConfig(get_called_class());
|
||||
if (is_array($pluginConfig) && isset($pluginConfig['enabled'])) {
|
||||
$this->setEnabled($pluginConfig['enabled']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) {
|
||||
if (method_exists($this, $eventName)) {
|
||||
call_user_func_array(array($this, $eventName), $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::setEnabled()
|
||||
*/
|
||||
public function setEnabled($enabled, $recursive = true, $auto = false)
|
||||
{
|
||||
$this->statusChanged = (!$this->statusChanged) ? !$auto : true;
|
||||
$this->enabled = (bool) $enabled;
|
||||
|
||||
if ($enabled) {
|
||||
$this->checkDependencies($recursive);
|
||||
} else {
|
||||
$this->checkDependants($recursive);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::isEnabled()
|
||||
*/
|
||||
public function isEnabled()
|
||||
{
|
||||
return $this->enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::isStatusChanged()
|
||||
*/
|
||||
public function isStatusChanged()
|
||||
{
|
||||
return $this->statusChanged;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::getPico()
|
||||
*/
|
||||
public function getPico()
|
||||
{
|
||||
return $this->pico;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes all not satisfiable method calls to Pico
|
||||
*
|
||||
* @see Pico
|
||||
* @param string $methodName name of the method to call
|
||||
* @param array $params parameters to pass
|
||||
* @return mixed return value of the called method
|
||||
*/
|
||||
public function __call($methodName, array $params)
|
||||
{
|
||||
if (method_exists($this->getPico(), $methodName)) {
|
||||
return call_user_func_array(array($this->getPico(), $methodName), $params);
|
||||
}
|
||||
|
||||
throw new BadMethodCallException(
|
||||
'Call to undefined method ' . get_class($this->getPico()) . '::' . $methodName . '() '
|
||||
. 'through ' . get_called_class() . '::__call()'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables all plugins which this plugin depends on
|
||||
*
|
||||
* @see PicoPluginInterface::getDependencies()
|
||||
* @param boolean $recursive enable required plugins automatically
|
||||
* @return void
|
||||
* @throws RuntimeException thrown when a dependency fails
|
||||
*/
|
||||
protected function checkDependencies($recursive)
|
||||
{
|
||||
foreach ($this->getDependencies() as $pluginName) {
|
||||
try {
|
||||
$plugin = $this->getPlugin($pluginName);
|
||||
} catch (RuntimeException $e) {
|
||||
throw new RuntimeException(
|
||||
"Unable to enable plugin '" . get_called_class() . "':"
|
||||
. "Required plugin '" . $pluginName . "' not found"
|
||||
);
|
||||
}
|
||||
|
||||
// plugins which don't implement PicoPluginInterface are always enabled
|
||||
if (is_a($plugin, 'PicoPluginInterface') && !$plugin->isEnabled()) {
|
||||
if ($recursive) {
|
||||
if (!$plugin->isStatusChanged()) {
|
||||
$plugin->setEnabled(true, true, true);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to enable plugin '" . get_called_class() . "':"
|
||||
. "Required plugin '" . $pluginName . "' was disabled manually"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to enable plugin '" . get_called_class() . "':"
|
||||
. "Required plugin '" . $pluginName . "' is disabled"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::getDependencies()
|
||||
*/
|
||||
public function getDependencies()
|
||||
{
|
||||
return (array) $this->dependsOn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables all plugins which depend on this plugin
|
||||
*
|
||||
* @see PicoPluginInterface::getDependants()
|
||||
* @param boolean $recursive disabled dependant plugins automatically
|
||||
* @return void
|
||||
* @throws RuntimeException thrown when a dependency fails
|
||||
*/
|
||||
protected function checkDependants($recursive)
|
||||
{
|
||||
$dependants = $this->getDependants();
|
||||
if (!empty($dependants)) {
|
||||
if ($recursive) {
|
||||
foreach ($this->getDependants() as $pluginName => $plugin) {
|
||||
if ($plugin->isEnabled()) {
|
||||
if (!$plugin->isStatusChanged()) {
|
||||
$plugin->setEnabled(false, true, true);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Unable to disable plugin '" . get_called_class() . "': "
|
||||
. "Required by manually enabled plugin '" . $pluginName . "'"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$dependantsList = 'plugin' . ((count($dependants) > 1) ? 's' : '') . ' ';
|
||||
$dependantsList .= "'" . implode("', '", array_keys($dependants)) . "'";
|
||||
throw new RuntimeException(
|
||||
"Unable to disable plugin '" . get_called_class() . "': "
|
||||
. "Required by " . $dependantsList
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see PicoPluginInterface::getDependants()
|
||||
*/
|
||||
public function getDependants()
|
||||
{
|
||||
if ($this->dependants === null) {
|
||||
$this->dependants = array();
|
||||
foreach ($this->getPlugins() as $pluginName => $plugin) {
|
||||
// only plugins which implement PicoPluginInterface support dependencies
|
||||
if (is_a($plugin, 'PicoPluginInterface')) {
|
||||
$dependencies = $plugin->getDependencies();
|
||||
if (in_array(get_called_class(), $dependencies)) {
|
||||
$this->dependants[$pluginName] = $plugin;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->dependants;
|
||||
}
|
||||
}
|
1276
lib/Pico.php
Normal file
1276
lib/Pico.php
Normal file
File diff suppressed because it is too large
Load diff
102
lib/PicoPluginInterface.php
Normal file
102
lib/PicoPluginInterface.php
Normal file
|
@ -0,0 +1,102 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Common interface for Pico plugins
|
||||
*
|
||||
* For a list of supported events see {@link DummyPlugin}; you can use
|
||||
* {@link DummyPlugin} as template for new plugins. For a list of deprecated
|
||||
* events see {@link PicoDeprecated}.
|
||||
*
|
||||
* You SHOULD NOT use deprecated events when implementing this interface.
|
||||
* Deprecated events are triggered by the {@link PicoDeprecated} plugin, if
|
||||
* plugins which don't implement this interface are loaded. You can take
|
||||
* advantage from this behaviour if you want to do something only when old
|
||||
* plugins are loaded. Consequently the old events are never triggered when
|
||||
* your plugin is implementing this interface and no old plugins are present.
|
||||
*
|
||||
* If you're developing a new plugin, you MUST implement this interface. If
|
||||
* you're the developer of an old plugin, it is STRONGLY RECOMMENDED to use
|
||||
* the events introduced in Pico 1.0 when releasing a new version of your
|
||||
* plugin. If you want to use any of the new events, you MUST implement
|
||||
* this interface and update all other events you use.
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
interface PicoPluginInterface
|
||||
{
|
||||
/**
|
||||
* Constructs a new instance of a Pico plugin
|
||||
*
|
||||
* @param Pico $pico current instance of Pico
|
||||
*/
|
||||
public function __construct(Pico $pico);
|
||||
|
||||
/**
|
||||
* Handles a event that was triggered by Pico
|
||||
*
|
||||
* @param string $eventName name of the triggered event
|
||||
* @param array $params passed parameters
|
||||
* @return void
|
||||
*/
|
||||
public function handleEvent($eventName, array $params);
|
||||
|
||||
/**
|
||||
* Enables or disables this plugin
|
||||
*
|
||||
* @see PicoPluginInterface::isEnabled()
|
||||
* @see PicoPluginInterface::isStatusChanged()
|
||||
* @param boolean $enabled enable (true) or disable (false) this plugin
|
||||
* @param boolean $recursive when true, enable or disable recursively
|
||||
* In other words, if you enable a plugin, all required plugins are
|
||||
* enabled, too. When disabling a plugin, all depending plugins are
|
||||
* disabled likewise. Recursive operations are only performed as long
|
||||
* as a plugin wasn't enabled/disabled manually. This parameter is
|
||||
* optional and defaults to true.
|
||||
* @param boolean $auto enable or disable to fulfill a dependency
|
||||
* This parameter is optional and defaults to false.
|
||||
* @return void
|
||||
* @throws RuntimeException thrown when a dependency fails
|
||||
*/
|
||||
public function setEnabled($enabled, $recursive = true, $auto = false);
|
||||
|
||||
/**
|
||||
* Returns true if this plugin is enabled, false otherwise
|
||||
*
|
||||
* @see PicoPluginInterface::setEnabled()
|
||||
* @return boolean plugin is enabled (true) or disabled (false)
|
||||
*/
|
||||
public function isEnabled();
|
||||
|
||||
/**
|
||||
* Returns true if the plugin was ever enabled/disabled manually
|
||||
*
|
||||
* @see PicoPluginInterface::setEnabled()
|
||||
* @return boolean plugin is in its default state (true), false otherwise
|
||||
*/
|
||||
public function isStatusChanged();
|
||||
|
||||
/**
|
||||
* Returns a list of names of plugins required by this plugin
|
||||
*
|
||||
* @return string[] required plugins
|
||||
*/
|
||||
public function getDependencies();
|
||||
|
||||
/**
|
||||
* Returns a list of plugins which depend on this plugin
|
||||
*
|
||||
* @return object[] dependant plugins
|
||||
*/
|
||||
public function getDependants();
|
||||
|
||||
/**
|
||||
* Returns the plugins instance of Pico
|
||||
*
|
||||
* @see Pico
|
||||
* @return Pico the plugins instance of Pico
|
||||
*/
|
||||
public function getPico();
|
||||
}
|
2
lib/cache/.gitignore
vendored
2
lib/cache/.gitignore
vendored
|
@ -1,2 +0,0 @@
|
|||
*
|
||||
!.gitignore
|
405
lib/pico.php
405
lib/pico.php
|
@ -1,405 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Pico
|
||||
*
|
||||
* @author Gilbert Pellegrom
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 0.8
|
||||
*/
|
||||
class Pico
|
||||
{
|
||||
|
||||
private $config;
|
||||
private $plugins;
|
||||
|
||||
/**
|
||||
* The constructor carries out all the processing in Pico.
|
||||
* Does URL routing, Markdown processing and Twig processing.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
// Load plugins
|
||||
$this->load_plugins();
|
||||
$this->run_hooks('plugins_loaded');
|
||||
|
||||
// Load the settings
|
||||
$settings = $this->get_config();
|
||||
$this->run_hooks('config_loaded', array(&$settings));
|
||||
|
||||
// Get request url and script url
|
||||
$url = '';
|
||||
$request_url = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
|
||||
$script_url = (isset($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : '';
|
||||
|
||||
// Get our url path and trim the / of the left and the right
|
||||
if ($request_url != $script_url) {
|
||||
$url = trim(preg_replace('/' . str_replace('/', '\/', str_replace('index.php', '', $script_url)) . '/', '',
|
||||
$request_url, 1), '/');
|
||||
}
|
||||
$url = preg_replace('/\?.*/', '', $url); // Strip query string
|
||||
$this->run_hooks('request_url', array(&$url));
|
||||
|
||||
// Get the file path
|
||||
if ($url) {
|
||||
$file = $settings['content_dir'] . $url;
|
||||
} else {
|
||||
$file = $settings['content_dir'] . 'index';
|
||||
}
|
||||
|
||||
// Load the file
|
||||
if (is_dir($file)) {
|
||||
$file = $settings['content_dir'] . $url . '/index' . CONTENT_EXT;
|
||||
} else {
|
||||
$file .= CONTENT_EXT;
|
||||
}
|
||||
|
||||
$this->run_hooks('before_load_content', array(&$file));
|
||||
if (file_exists($file)) {
|
||||
$content = file_get_contents($file);
|
||||
} else {
|
||||
$this->run_hooks('before_404_load_content', array(&$file));
|
||||
$content = file_get_contents($settings['content_dir'] . '404' . CONTENT_EXT);
|
||||
header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found');
|
||||
$this->run_hooks('after_404_load_content', array(&$file, &$content));
|
||||
}
|
||||
$this->run_hooks('after_load_content', array(&$file, &$content));
|
||||
|
||||
$meta = $this->read_file_meta($content);
|
||||
$this->run_hooks('file_meta', array(&$meta));
|
||||
|
||||
$this->run_hooks('before_parse_content', array(&$content));
|
||||
$content = $this->parse_content($content);
|
||||
$this->run_hooks('after_parse_content', array(&$content));
|
||||
$this->run_hooks('content_parsed', array(&$content)); // Depreciated @ v0.8
|
||||
|
||||
// Get all the pages
|
||||
$pages = $this->get_pages($settings['base_url'], $settings['pages_order_by'], $settings['pages_order'],
|
||||
$settings['excerpt_length']);
|
||||
$prev_page = array();
|
||||
$current_page = array();
|
||||
$next_page = array();
|
||||
while ($current_page = current($pages)) {
|
||||
if ((isset($meta['title'])) && ($meta['title'] == $current_page['title'])) {
|
||||
break;
|
||||
}
|
||||
next($pages);
|
||||
}
|
||||
$prev_page = next($pages);
|
||||
prev($pages);
|
||||
$next_page = prev($pages);
|
||||
$this->run_hooks('get_pages', array(&$pages, &$current_page, &$prev_page, &$next_page));
|
||||
|
||||
// Load the theme
|
||||
$this->run_hooks('before_twig_register');
|
||||
Twig_Autoloader::register();
|
||||
$loader = new Twig_Loader_Filesystem(THEMES_DIR . $settings['theme']);
|
||||
$twig = new Twig_Environment($loader, $settings['twig_config']);
|
||||
$twig->addExtension(new Twig_Extension_Debug());
|
||||
$twig_vars = array(
|
||||
'config' => $settings,
|
||||
'base_dir' => rtrim(ROOT_DIR, '/'),
|
||||
'base_url' => $settings['base_url'],
|
||||
'theme_dir' => THEMES_DIR . $settings['theme'],
|
||||
'theme_url' => $settings['base_url'] . '/' . basename(THEMES_DIR) . '/' . $settings['theme'],
|
||||
'site_title' => $settings['site_title'],
|
||||
'meta' => $meta,
|
||||
'content' => $content,
|
||||
'pages' => $pages,
|
||||
'prev_page' => $prev_page,
|
||||
'current_page' => $current_page,
|
||||
'next_page' => $next_page,
|
||||
'is_front_page' => $url ? false : true,
|
||||
);
|
||||
|
||||
$template = (isset($meta['template']) && $meta['template']) ? $meta['template'] : 'index';
|
||||
$this->run_hooks('before_render', array(&$twig_vars, &$twig, &$template));
|
||||
$output = $twig->render($template . '.html', $twig_vars);
|
||||
$this->run_hooks('after_render', array(&$output));
|
||||
echo $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load any plugins
|
||||
*/
|
||||
protected function load_plugins()
|
||||
{
|
||||
$this->plugins = array();
|
||||
$plugins = $this->get_files(PLUGINS_DIR, '.php');
|
||||
if (!empty($plugins)) {
|
||||
foreach ($plugins as $plugin) {
|
||||
include_once($plugin);
|
||||
$plugin_name = preg_replace("/\\.[^.\\s]{3}$/", '', basename($plugin));
|
||||
if (class_exists($plugin_name)) {
|
||||
$obj = new $plugin_name;
|
||||
$this->plugins[] = $obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the content using Parsedown-extra
|
||||
*
|
||||
* @param string $content the raw txt content
|
||||
* @return string $content the Markdown formatted content
|
||||
*/
|
||||
protected function parse_content($content)
|
||||
{
|
||||
$content = preg_replace('#/\*.+?\*/#s', '', $content, 1); // Remove first comment (with meta)
|
||||
$content = str_replace('%base_url%', $this->base_url(), $content);
|
||||
$Parsedown = new ParsedownExtra();
|
||||
$content= $Parsedown->text($content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the file meta from the txt file header
|
||||
*
|
||||
* @param string $content the raw txt content
|
||||
* @return array $headers an array of meta values
|
||||
*/
|
||||
protected function read_file_meta($content)
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
$headers = array(
|
||||
'title' => 'Title',
|
||||
'description' => 'Description',
|
||||
'author' => 'Author',
|
||||
'date' => 'Date',
|
||||
'robots' => 'Robots',
|
||||
'template' => 'Template'
|
||||
);
|
||||
|
||||
// Add support for custom headers by hooking into the headers array
|
||||
$this->run_hooks('before_read_file_meta', array(&$headers));
|
||||
|
||||
foreach ($headers as $field => $regex) {
|
||||
if (preg_match('/^[ \t\/*#@]*' . preg_quote($regex, '/') . ':(.*)$/mi', $content, $match) && $match[1]) {
|
||||
$headers[$field] = trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $match[1]));
|
||||
} else {
|
||||
$headers[$field] = '';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($headers['date'])) {
|
||||
$headers['date_formatted'] = utf8_encode(strftime($config['date_format'], strtotime($headers['date'])));
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the config
|
||||
*
|
||||
* @return array $config an array of config values
|
||||
*/
|
||||
protected function get_config()
|
||||
{
|
||||
if (file_exists(CONFIG_DIR . 'config.php')) {
|
||||
$this->config = require(CONFIG_DIR . 'config.php');
|
||||
} else if (file_exists(ROOT_DIR . 'config.php')) {
|
||||
// deprecated
|
||||
$this->config = require(ROOT_DIR . 'config.php');
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'site_title' => 'Pico',
|
||||
'base_url' => $this->base_url(),
|
||||
'theme' => 'default',
|
||||
'date_format' => '%D %T',
|
||||
'twig_config' => array('cache' => false, 'autoescape' => false, 'debug' => false),
|
||||
'pages_order_by' => 'alpha',
|
||||
'pages_order' => 'asc',
|
||||
'excerpt_length' => 50,
|
||||
'content_dir' => 'content-sample/',
|
||||
);
|
||||
|
||||
if (is_array($this->config)) {
|
||||
$this->config = array_merge($defaults, $this->config);
|
||||
} else {
|
||||
$this->config = $defaults;
|
||||
}
|
||||
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of pages
|
||||
*
|
||||
* @param string $base_url the base URL of the site
|
||||
* @param string $order_by order by "alpha" or "date"
|
||||
* @param string $order order "asc" or "desc"
|
||||
* @return array $sorted_pages an array of pages
|
||||
*/
|
||||
protected function get_pages($base_url, $order_by = 'alpha', $order = 'asc', $excerpt_length = 50)
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
$pages = $this->get_files($config['content_dir'], CONTENT_EXT);
|
||||
$sorted_pages = array();
|
||||
$date_id = 0;
|
||||
foreach ($pages as $key => $page) {
|
||||
// Skip 404
|
||||
if (basename($page) == '404' . CONTENT_EXT) {
|
||||
unset($pages[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore Emacs (and Nano) temp files
|
||||
if (in_array(substr($page, -1), array('~', '#'))) {
|
||||
unset($pages[$key]);
|
||||
continue;
|
||||
}
|
||||
// Get title and format $page
|
||||
$page_content = file_get_contents($page);
|
||||
$page_meta = $this->read_file_meta($page_content);
|
||||
$page_content = $this->parse_content($page_content);
|
||||
$url = str_replace($config['content_dir'], $base_url . '/', $page);
|
||||
$url = str_replace('index' . CONTENT_EXT, '', $url);
|
||||
$url = str_replace(CONTENT_EXT, '', $url);
|
||||
$data = array(
|
||||
'title' => isset($page_meta['title']) ? $page_meta['title'] : '',
|
||||
'url' => $url,
|
||||
'author' => isset($page_meta['author']) ? $page_meta['author'] : '',
|
||||
'date' => isset($page_meta['date']) ? $page_meta['date'] : '',
|
||||
'date_formatted' => isset($page_meta['date']) ? utf8_encode(strftime($config['date_format'],
|
||||
strtotime($page_meta['date']))) : '',
|
||||
'content' => $page_content,
|
||||
'excerpt' => $this->limit_words(strip_tags($page_content), $excerpt_length),
|
||||
//this addition allows the 'description' meta to be picked up in content areas... specifically to replace 'excerpt'
|
||||
'description' => isset($page_meta['description']) ? $page_meta['description'] : '',
|
||||
|
||||
);
|
||||
|
||||
// Extend the data provided with each page by hooking into the data array
|
||||
$this->run_hooks('get_page_data', array(&$data, $page_meta));
|
||||
|
||||
if ($order_by == 'date' && isset($page_meta['date'])) {
|
||||
$sorted_pages[$page_meta['date'] . $date_id] = $data;
|
||||
$date_id++;
|
||||
} else {
|
||||
$sorted_pages[$page] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
if ($order == 'desc') {
|
||||
krsort($sorted_pages);
|
||||
} else {
|
||||
ksort($sorted_pages);
|
||||
}
|
||||
|
||||
return $sorted_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes any hooks and runs them
|
||||
*
|
||||
* @param string $hook_id the ID of the hook
|
||||
* @param array $args optional arguments
|
||||
*/
|
||||
protected function run_hooks($hook_id, $args = array())
|
||||
{
|
||||
if (!empty($this->plugins)) {
|
||||
foreach ($this->plugins as $plugin) {
|
||||
if (is_callable(array($plugin, $hook_id))) {
|
||||
call_user_func_array(array($plugin, $hook_id), $args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to work out the base URL
|
||||
*
|
||||
* @return string the base url
|
||||
*/
|
||||
protected function base_url()
|
||||
{
|
||||
$config = $this->config;
|
||||
|
||||
if (isset($config['base_url']) && $config['base_url']) {
|
||||
return $config['base_url'];
|
||||
}
|
||||
|
||||
$url = '';
|
||||
$request_url = (isset($_SERVER['REQUEST_URI'])) ? $_SERVER['REQUEST_URI'] : '';
|
||||
$script_url = (isset($_SERVER['PHP_SELF'])) ? $_SERVER['PHP_SELF'] : '';
|
||||
if ($request_url != $script_url) {
|
||||
$url = trim(preg_replace('/' . str_replace('/', '\/', str_replace('index.php', '', $script_url)) . '/', '',
|
||||
$request_url, 1), '/');
|
||||
}
|
||||
|
||||
$protocol = $this->get_protocol();
|
||||
|
||||
return rtrim(str_replace($url, '', $protocol . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']), '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to guess the server protocol. Used in base_url()
|
||||
*
|
||||
* @return string the current protocol
|
||||
*/
|
||||
protected function get_protocol()
|
||||
{
|
||||
$protocol = 'http';
|
||||
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' && $_SERVER['HTTPS'] != '') {
|
||||
$protocol = 'https';
|
||||
}
|
||||
|
||||
return $protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to recusively get all files in a directory
|
||||
*
|
||||
* @param string $directory start directory
|
||||
* @param string $ext optional limit to file extensions
|
||||
* @return array the matched files
|
||||
*/
|
||||
protected function get_files($directory, $ext = '')
|
||||
{
|
||||
$array_items = array();
|
||||
if ($files = scandir($directory)) {
|
||||
foreach ($files as $file) {
|
||||
if (in_array(substr($file, -1), array('~', '#'))) {
|
||||
continue;
|
||||
}
|
||||
if (preg_match("/^(^\.)/", $file) === 0) {
|
||||
if (is_dir($directory . "/" . $file)) {
|
||||
$array_items = array_merge($array_items, $this->get_files($directory . "/" . $file, $ext));
|
||||
} else {
|
||||
$file = $directory . "/" . $file;
|
||||
if (!$ext || strstr($file, $ext)) {
|
||||
$array_items[] = preg_replace("/\/\//si", "/", $file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $array_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to limit the words in a string
|
||||
*
|
||||
* @param string $string the given string
|
||||
* @param int $word_limit the number of words to limit to
|
||||
* @return string the limited string
|
||||
*/
|
||||
protected function limit_words($string, $word_limit)
|
||||
{
|
||||
$words = explode(' ', $string);
|
||||
$excerpt = trim(implode(' ', array_splice($words, 0, $word_limit)));
|
||||
if (count($words) > $word_limit) {
|
||||
$excerpt .= '…';
|
||||
}
|
||||
|
||||
return $excerpt;
|
||||
}
|
||||
|
||||
}
|
430
plugins/00-PicoDeprecated.php
Normal file
430
plugins/00-PicoDeprecated.php
Normal file
|
@ -0,0 +1,430 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Serve features of Pico deprecated since v1.0
|
||||
*
|
||||
* This plugin exists for backward compatibility and is disabled by default.
|
||||
* It gets automatically enabled when a plugin which doesn't implement
|
||||
* {@link PicoPluginInterface} is loaded. This plugin triggers deprecated
|
||||
* events and automatically enables {@link PicoParsePagesContent} and
|
||||
* {@link PicoExcerpt}. These plugins heavily impact Pico's performance! You
|
||||
* can disable this plugin by calling {@link PicoDeprecated::setEnabled()}.
|
||||
*
|
||||
* The following deprecated events are triggered by this plugin:
|
||||
* <pre>
|
||||
* +---------------------+-----------------------------------------------------------+
|
||||
* | Event | ... triggers the deprecated event |
|
||||
* +---------------------+-----------------------------------------------------------+
|
||||
* | onPluginsLoaded | plugins_loaded() |
|
||||
* | onConfigLoaded | config_loaded($config) |
|
||||
* | onRequestUrl | request_url($url) |
|
||||
* | onContentLoading | before_load_content($file) |
|
||||
* | onContentLoaded | after_load_content($file, $rawContent) |
|
||||
* | on404ContentLoading | before_404_load_content($file) |
|
||||
* | on404ContentLoaded | after_404_load_content($file, $rawContent) |
|
||||
* | onMetaHeaders | before_read_file_meta($headers) |
|
||||
* | onMetaParsed | file_meta($meta) |
|
||||
* | onContentParsing | before_parse_content($rawContent) |
|
||||
* | onContentParsed | after_parse_content($content) |
|
||||
* | onContentParsed | content_parsed($content) |
|
||||
* | onSinglePageLoaded | get_page_data($pages, $meta) |
|
||||
* | onPagesLoaded | get_pages($pages, $currentPage, $previousPage, $nextPage) |
|
||||
* | onTwigRegistration | before_twig_register() |
|
||||
* | onPageRendering | before_render($twigVariables, $twig, $templateName) |
|
||||
* | onPageRendered | after_render($output) |
|
||||
* +---------------------+-----------------------------------------------------------+
|
||||
* </pre>
|
||||
*
|
||||
* 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
|
||||
* all settings previously specified in {@path "config/config.php"}.
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
class PicoDeprecated extends AbstractPicoPlugin
|
||||
{
|
||||
/**
|
||||
* This plugin is disabled by default
|
||||
*
|
||||
* @see AbstractPicoPlugin::$enabled
|
||||
*/
|
||||
protected $enabled = false;
|
||||
|
||||
/**
|
||||
* The requested file
|
||||
*
|
||||
* @see PicoDeprecated::getRequestFile()
|
||||
* @var string|null
|
||||
*/
|
||||
protected $requestFile;
|
||||
|
||||
/**
|
||||
* Enables this plugin on demand and triggers the deprecated event
|
||||
* plugins_loaded()
|
||||
*
|
||||
* @see DummyPlugin::onPluginsLoaded()
|
||||
*/
|
||||
public function onPluginsLoaded(&$plugins)
|
||||
{
|
||||
if (!empty($plugins)) {
|
||||
foreach ($plugins as $plugin) {
|
||||
if (!is_a($plugin, 'PicoPluginInterface')) {
|
||||
// the plugin doesn't implement PicoPluginInterface; it uses deprecated events
|
||||
// enable PicoDeprecated if it hasn't be explicitly enabled/disabled yet
|
||||
if (!$this->isStatusChanged()) {
|
||||
$this->setEnabled(true, true, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no plugins were found, so it actually isn't necessary to call deprecated events
|
||||
// anyway, this plugin also ensures compatibility apart from events used by old plugins,
|
||||
// so enable PicoDeprecated if it hasn't be explicitly enabled/disabled yet
|
||||
if (!$this->isStatusChanged()) {
|
||||
$this->setEnabled(true, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isEnabled()) {
|
||||
$this->triggerEvent('plugins_loaded');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event config_loaded($config)
|
||||
*
|
||||
* This method also defines deprecated constants, reads the `config.php`
|
||||
* in Pico's root dir, enables the plugins {@link PicoParsePagesContent}
|
||||
* and {@link PicoExcerpt} and makes `$config` globally accessible (the
|
||||
* latter was removed with Pico 0.9 and was added again as deprecated
|
||||
* feature with Pico 1.0)
|
||||
*
|
||||
* @see PicoDeprecated::defineConstants()
|
||||
* @see PicoDeprecated::loadRootDirConfig()
|
||||
* @see PicoDeprecated::enablePlugins()
|
||||
* @see DummyPlugin::onConfigLoaded()
|
||||
* @param mixed[] &$realConfig array of config variables
|
||||
* @return void
|
||||
*/
|
||||
public function onConfigLoaded(&$realConfig)
|
||||
{
|
||||
global $config;
|
||||
|
||||
$this->defineConstants();
|
||||
$this->loadRootDirConfig($realConfig);
|
||||
$this->enablePlugins();
|
||||
$config = &$realConfig;
|
||||
|
||||
$this->triggerEvent('config_loaded', array(&$realConfig));
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines deprecated constants
|
||||
*
|
||||
* `ROOT_DIR`, `LIB_DIR`, `PLUGINS_DIR`, `THEMES_DIR` and `CONTENT_EXT`
|
||||
* are deprecated since v1.0, `CONTENT_DIR` existed just in v0.9,
|
||||
* `CONFIG_DIR` just for a short time between v0.9 and v1.0 and
|
||||
* `CACHE_DIR` was dropped with v1.0 without a replacement.
|
||||
*
|
||||
* @see PicoDeprecated::onConfigLoaded()
|
||||
* @return void
|
||||
*/
|
||||
protected function defineConstants()
|
||||
{
|
||||
if (!defined('ROOT_DIR')) {
|
||||
define('ROOT_DIR', $this->getRootDir());
|
||||
}
|
||||
if (!defined('CONFIG_DIR')) {
|
||||
define('CONFIG_DIR', $this->getConfigDir());
|
||||
}
|
||||
if (!defined('LIB_DIR')) {
|
||||
$picoReflector = new ReflectionClass('Pico');
|
||||
define('LIB_DIR', dirname($picoReflector->getFileName() . '/'));
|
||||
}
|
||||
if (!defined('PLUGINS_DIR')) {
|
||||
define('PLUGINS_DIR', $this->getPluginsDir());
|
||||
}
|
||||
if (!defined('THEMES_DIR')) {
|
||||
define('THEMES_DIR', $this->getThemesDir());
|
||||
}
|
||||
if (!defined('CONTENT_DIR')) {
|
||||
define('CONTENT_DIR', $this->getConfig('content_dir'));
|
||||
}
|
||||
if (!defined('CONTENT_EXT')) {
|
||||
define('CONTENT_EXT', $this->getConfig('content_ext'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read config.php in Pico's root dir
|
||||
*
|
||||
* @see PicoDeprecated::onConfigLoaded()
|
||||
* @see Pico::loadConfig()
|
||||
* @param mixed[] &$realConfig array of config variables
|
||||
* @return void
|
||||
*/
|
||||
protected function loadRootDirConfig(&$realConfig)
|
||||
{
|
||||
if (file_exists($this->getRootDir() . 'config.php')) {
|
||||
// config.php in Pico::$rootDir is deprecated; use Pico::$configDir instead
|
||||
$config = null;
|
||||
require($this->getRootDir() . 'config.php');
|
||||
|
||||
if (is_array($config)) {
|
||||
$realConfig = $config + $realConfig;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables the plugins PicoParsePagesContent and PicoExcerpt
|
||||
*
|
||||
* @see PicoParsePagesContent
|
||||
* @see PicoExcerpt
|
||||
* @return void
|
||||
*/
|
||||
protected function enablePlugins()
|
||||
{
|
||||
// enable PicoParsePagesContent and PicoExcerpt
|
||||
// we can't enable them during onPluginsLoaded because we can't know
|
||||
// if the user disabled us (PicoDeprecated) manually in the config
|
||||
$plugins = $this->getPlugins();
|
||||
if (isset($plugins['PicoParsePagesContent'])) {
|
||||
// parse all pages content if this plugin hasn't
|
||||
// be explicitly enabled/disabled yet
|
||||
if (!$plugins['PicoParsePagesContent']->isStatusChanged()) {
|
||||
$plugins['PicoParsePagesContent']->setEnabled(true, true, true);
|
||||
}
|
||||
}
|
||||
if (isset($plugins['PicoExcerpt'])) {
|
||||
// enable excerpt plugin if it hasn't be explicitly enabled/disabled yet
|
||||
if (!$plugins['PicoExcerpt']->isStatusChanged()) {
|
||||
$plugins['PicoExcerpt']->setEnabled(true, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event request_url($url)
|
||||
*
|
||||
* @see DummyPlugin::onRequestUrl()
|
||||
*/
|
||||
public function onRequestUrl(&$url)
|
||||
{
|
||||
$this->triggerEvent('request_url', array(&$url));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets PicoDeprecated::$requestFile to trigger the deprecated
|
||||
* events after_load_content() and after_404_load_content()
|
||||
*
|
||||
* @see PicoDeprecated::onContentLoaded()
|
||||
* @see PicoDeprecated::on404ContentLoaded()
|
||||
* @see DummyPlugin::onRequestFile()
|
||||
*/
|
||||
public function onRequestFile(&$file)
|
||||
{
|
||||
$this->requestFile = &$file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated before_load_content($file)
|
||||
*
|
||||
* @see DummyPlugin::onContentLoading()
|
||||
*/
|
||||
public function onContentLoading(&$file)
|
||||
{
|
||||
$this->triggerEvent('before_load_content', array(&$file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event after_load_content($file, $rawContent)
|
||||
*
|
||||
* @see DummyPlugin::onContentLoaded()
|
||||
*/
|
||||
public function onContentLoaded(&$rawContent)
|
||||
{
|
||||
$this->triggerEvent('after_load_content', array(&$this->requestFile, &$rawContent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated before_404_load_content($file)
|
||||
*
|
||||
* @see DummyPlugin::on404ContentLoading()
|
||||
*/
|
||||
public function on404ContentLoading(&$file)
|
||||
{
|
||||
$this->triggerEvent('before_404_load_content', array(&$file));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event after_404_load_content($file, $rawContent)
|
||||
*
|
||||
* @see DummyPlugin::on404ContentLoaded()
|
||||
*/
|
||||
public function on404ContentLoaded(&$rawContent)
|
||||
{
|
||||
$this->triggerEvent('after_404_load_content', array(&$this->requestFile, &$rawContent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event before_read_file_meta($headers)
|
||||
*
|
||||
* @see DummyPlugin::onMetaHeaders()
|
||||
*/
|
||||
public function onMetaHeaders(&$headers)
|
||||
{
|
||||
$this->triggerEvent('before_read_file_meta', array(&$headers));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event file_meta($meta)
|
||||
*
|
||||
* @see DummyPlugin::onMetaParsed()
|
||||
*/
|
||||
public function onMetaParsed(&$meta)
|
||||
{
|
||||
$this->triggerEvent('file_meta', array(&$meta));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event before_parse_content($rawContent)
|
||||
*
|
||||
* @see DummyPlugin::onContentParsing()
|
||||
*/
|
||||
public function onContentParsing(&$rawContent)
|
||||
{
|
||||
$this->triggerEvent('before_parse_content', array(&$rawContent));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated events after_parse_content($content) and
|
||||
* content_parsed($content)
|
||||
*
|
||||
* @see DummyPlugin::onContentParsed()
|
||||
*/
|
||||
public function onContentParsed(&$content)
|
||||
{
|
||||
$this->triggerEvent('after_parse_content', array(&$content));
|
||||
|
||||
// deprecated since v0.8
|
||||
$this->triggerEvent('content_parsed', array(&$content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event get_page_data($pages, $meta)
|
||||
*
|
||||
* @see DummyPlugin::onSinglePageLoaded()
|
||||
*/
|
||||
public function onSinglePageLoaded(&$pageData)
|
||||
{
|
||||
$this->triggerEvent('get_page_data', array(&$pageData, $pageData['meta']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event
|
||||
* get_pages($pages, $currentPage, $previousPage, $nextPage)
|
||||
*
|
||||
* Please note that the `get_pages()` event gets `$pages` passed without a
|
||||
* array index. The index is rebuild later using either the `id` array key
|
||||
* or is derived from the `url` array key. Duplicates are prevented by
|
||||
* adding `~dup` when necessary.
|
||||
*
|
||||
* @see DummyPlugin::onPagesLoaded()
|
||||
*/
|
||||
public function onPagesLoaded(&$pages, &$currentPage, &$previousPage, &$nextPage)
|
||||
{
|
||||
// remove keys of pages array
|
||||
$plainPages = array();
|
||||
foreach ($pages as &$pageData) {
|
||||
$plainPages[] = &$pageData;
|
||||
}
|
||||
unset($pageData);
|
||||
|
||||
$this->triggerEvent('get_pages', array(&$plainPages, &$currentPage, &$previousPage, &$nextPage));
|
||||
|
||||
// re-index pages array
|
||||
$pages = array();
|
||||
foreach ($plainPages as &$pageData) {
|
||||
if (!isset($pageData['id'])) {
|
||||
$urlPrefixLength = strlen($this->getBaseUrl()) + intval(!$this->isUrlRewritingEnabled());
|
||||
$pageData['id'] = substr($pageData['url'], $urlPrefixLength);
|
||||
}
|
||||
|
||||
// prevent duplicates
|
||||
$id = $pageData['id'];
|
||||
for ($i = 1; isset($pages[$id]); $i++) {
|
||||
$id = $pageData['id'] . '~dup' . $i;
|
||||
}
|
||||
|
||||
$pages[$id] = &$pageData;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event before_twig_register()
|
||||
*
|
||||
* @see DummyPlugin::onTwigRegistration()
|
||||
*/
|
||||
public function onTwigRegistration()
|
||||
{
|
||||
$this->triggerEvent('before_twig_register');
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event before_render($twigVariables, $twig, $templateName)
|
||||
*
|
||||
* Please note that the `before_render()` event gets `$templateName` passed
|
||||
* without its file extension. The file extension is later added again.
|
||||
*
|
||||
* @see DummyPlugin::onPageRendering()
|
||||
*/
|
||||
public function onPageRendering(&$twig, &$twigVariables, &$templateName)
|
||||
{
|
||||
// template name contains file extension since Pico 1.0
|
||||
$fileExtension = '';
|
||||
if (($fileExtensionPos = strrpos($templateName, '.')) !== false) {
|
||||
$fileExtension = substr($templateName, $fileExtensionPos);
|
||||
$templateName = substr($templateName, 0, $fileExtensionPos);
|
||||
}
|
||||
|
||||
$this->triggerEvent('before_render', array(&$twigVariables, &$twig, &$templateName));
|
||||
|
||||
// add original file extension
|
||||
$templateName = $templateName . $fileExtension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the deprecated event after_render($output)
|
||||
*
|
||||
* @see DummyPlugin::onPageRendered()
|
||||
*/
|
||||
public function onPageRendered(&$output)
|
||||
{
|
||||
$this->triggerEvent('after_render', array(&$output));
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a deprecated event on all plugins
|
||||
*
|
||||
* Deprecated events are also triggered on plugins which implement
|
||||
* {@link PicoPluginInterface}. Please note that the methods are called
|
||||
* directly and not through {@link PicoPluginInterface::handleEvent()}.
|
||||
*
|
||||
* @param string $eventName event to trigger
|
||||
* @param array $params parameters to pass
|
||||
* @return void
|
||||
*/
|
||||
protected function triggerEvent($eventName, array $params = array())
|
||||
{
|
||||
foreach ($this->getPlugins() as $plugin) {
|
||||
if (method_exists($plugin, $eventName)) {
|
||||
call_user_func_array(array($plugin, $eventName), $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
plugins/01-PicoParsePagesContent.php
Normal file
40
plugins/01-PicoParsePagesContent.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Parses the contents of all pages
|
||||
*
|
||||
* This plugin exists for backward compatibility and is disabled by default.
|
||||
* It gets automatically enabled when {@link PicoDeprecated} is enabled. You
|
||||
* can avoid this by calling {@link PicoParsePagesContent::setEnabled()}.
|
||||
*
|
||||
* This plugin heavily impacts Pico's performance, you should avoid to enable
|
||||
* it whenever possible! If you must parse the contents of a page, do this
|
||||
* selectively and only for pages you really need to.
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
class PicoParsePagesContent extends AbstractPicoPlugin
|
||||
{
|
||||
/**
|
||||
* This plugin is disabled by default
|
||||
*
|
||||
* @see AbstractPicoPlugin::$enabled
|
||||
*/
|
||||
protected $enabled = false;
|
||||
|
||||
/**
|
||||
* Parses the contents of all pages
|
||||
*
|
||||
* @see DummyPlugin::onSinglePageLoaded()
|
||||
*/
|
||||
public function onSinglePageLoaded(&$pageData)
|
||||
{
|
||||
if (!isset($pageData['content'])) {
|
||||
$pageData['content'] = $this->prepareFileContent($pageData['raw_content'], $pageData['meta']);
|
||||
$pageData['content'] = $this->parseFileContent($pageData['content']);
|
||||
}
|
||||
}
|
||||
}
|
81
plugins/02-PicoExcerpt.php
Normal file
81
plugins/02-PicoExcerpt.php
Normal file
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Creates a excerpt for the contents of each page (as of Pico v0.9 and older)
|
||||
*
|
||||
* This plugin exists for backward compatibility and is disabled by default.
|
||||
* It gets automatically enabled when {@link PicoDeprecated} is enabled. You
|
||||
* can avoid this by calling {@link PicoExcerpt::setEnabled()}.
|
||||
*
|
||||
* This plugin doesn't do its job very well and depends on
|
||||
* {@link PicoParsePagesContent}, what heavily impacts Pico's performance. You
|
||||
* should either use the Description meta header field or write something own.
|
||||
* Best solution seems to be a filter for twig, see e.g.
|
||||
* {@link https://gist.github.com/james2doyle/6629712}.
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
class PicoExcerpt extends AbstractPicoPlugin
|
||||
{
|
||||
/**
|
||||
* This plugin is disabled by default
|
||||
*
|
||||
* @see AbstractPicoPlugin::$enabled
|
||||
*/
|
||||
protected $enabled = false;
|
||||
|
||||
/**
|
||||
* This plugin depends on PicoParsePagesContent
|
||||
*
|
||||
* @see PicoParsePagesContent
|
||||
* @see AbstractPicoPlugin::$dependsOn
|
||||
*/
|
||||
protected $dependsOn = array('PicoParsePagesContent');
|
||||
|
||||
/**
|
||||
* Adds the default excerpt length of 50 words to the config
|
||||
*
|
||||
* @see DummyPlugin::onConfigLoaded()
|
||||
*/
|
||||
public function onConfigLoaded(&$config)
|
||||
{
|
||||
if (!isset($config['excerpt_length'])) {
|
||||
$config['excerpt_length'] = 50;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a excerpt for the contents of each page
|
||||
*
|
||||
* @see PicoExcerpt::createExcerpt()
|
||||
* @see DummyPlugin::onSinglePageLoaded()
|
||||
*/
|
||||
public function onSinglePageLoaded(&$pageData)
|
||||
{
|
||||
if (!isset($pageData['excerpt'])) {
|
||||
$pageData['excerpt'] = $this->createExcerpt(
|
||||
strip_tags($pageData['content']),
|
||||
$this->getConfig('excerpt_length')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a excerpt of a string
|
||||
*
|
||||
* @param string $string the string to create a excerpt from
|
||||
* @param int $wordLimit the maximum number of words the excerpt should be long
|
||||
* @return string excerpt of $string
|
||||
*/
|
||||
protected function createExcerpt($string, $wordLimit)
|
||||
{
|
||||
$words = explode(' ', $string);
|
||||
if (count($words) > $wordLimit) {
|
||||
return trim(implode(' ', array_slice($words, 0, $wordLimit))) . '…';
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
}
|
313
plugins/DummyPlugin.php
Normal file
313
plugins/DummyPlugin.php
Normal file
|
@ -0,0 +1,313 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Pico dummy plugin - a template for plugins
|
||||
*
|
||||
* You're a plugin developer? This template may be helpful :-)
|
||||
* Simply remove the events you don't need and add your own logic.
|
||||
*
|
||||
* @author Daniel Rudolf
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
* @version 1.0
|
||||
*/
|
||||
class DummyPlugin extends AbstractPicoPlugin
|
||||
{
|
||||
/**
|
||||
* This plugin is enabled by default?
|
||||
*
|
||||
* @see AbstractPicoPlugin::$enabled
|
||||
* @var boolean
|
||||
*/
|
||||
protected $enabled = false;
|
||||
|
||||
/**
|
||||
* This plugin depends on ...
|
||||
*
|
||||
* @see AbstractPicoPlugin::$dependsOn
|
||||
* @var string[]
|
||||
*/
|
||||
protected $dependsOn = array();
|
||||
|
||||
/**
|
||||
* Triggered after Pico has loaded all available plugins
|
||||
*
|
||||
* This event is triggered nevertheless the plugin is enabled or not.
|
||||
* It is NOT guaranteed that plugin dependencies are fulfilled!
|
||||
*
|
||||
* @see Pico::getPlugin()
|
||||
* @see Pico::getPlugins()
|
||||
* @param object[] &$plugins loaded plugin instances
|
||||
* @return void
|
||||
*/
|
||||
public function onPluginsLoaded(&$plugins)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has read its configuration
|
||||
*
|
||||
* @see Pico::getConfig()
|
||||
* @param mixed[] &$config array of config variables
|
||||
* @return void
|
||||
*/
|
||||
public function onConfigLoaded(&$config)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has evaluated the request URL
|
||||
*
|
||||
* @see Pico::getRequestUrl()
|
||||
* @param string &$url part of the URL describing the requested contents
|
||||
* @return void
|
||||
*/
|
||||
public function onRequestUrl(&$url)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has discovered the content file to serve
|
||||
*
|
||||
* @see Pico::getBaseUrl()
|
||||
* @see Pico::getRequestFile()
|
||||
* @param string &$file absolute path to the content file to serve
|
||||
* @return void
|
||||
*/
|
||||
public function onRequestFile(&$file)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico reads the contents of the file to serve
|
||||
*
|
||||
* @see Pico::loadFileContent()
|
||||
* @see DummyPlugin::onContentLoaded()
|
||||
* @param string &$file path to the file which contents will be read
|
||||
* @return void
|
||||
*/
|
||||
public function onContentLoading(&$file)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has read the contents of the file to serve
|
||||
*
|
||||
* @see Pico::getRawContent()
|
||||
* @param string &$rawContent raw file contents
|
||||
* @return void
|
||||
*/
|
||||
public function onContentLoaded(&$rawContent)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico reads the contents of a 404 file
|
||||
*
|
||||
* @see Pico::load404Content()
|
||||
* @see DummyPlugin::on404ContentLoaded()
|
||||
* @param string &$file path to the file which contents were requested
|
||||
* @return void
|
||||
*/
|
||||
public function on404ContentLoading(&$file)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has read the contents of the 404 file
|
||||
*
|
||||
* @see Pico::getRawContent()
|
||||
* @param string &$rawContent raw file contents
|
||||
* @return void
|
||||
*/
|
||||
public function on404ContentLoaded(&$rawContent)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when Pico reads its known meta header fields
|
||||
*
|
||||
* @see Pico::getMetaHeaders()
|
||||
* @param string[] &$headers list of known meta header
|
||||
* fields; the array value specifies the YAML key to search for, the
|
||||
* array key is later used to access the found value
|
||||
* @return void
|
||||
*/
|
||||
public function onMetaHeaders(&$headers)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico parses the meta header
|
||||
*
|
||||
* @see Pico::parseFileMeta()
|
||||
* @see DummyPlugin::onMetaParsed()
|
||||
* @param string &$rawContent raw file contents
|
||||
* @param string[] &$headers known meta header fields
|
||||
* @return void
|
||||
*/
|
||||
public function onMetaParsing(&$rawContent, &$headers)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has parsed the meta header
|
||||
*
|
||||
* @see Pico::getFileMeta()
|
||||
* @param string[] &$meta parsed meta data
|
||||
* @return void
|
||||
*/
|
||||
public function onMetaParsed(&$meta)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico parses the pages content
|
||||
*
|
||||
* @see Pico::prepareFileContent()
|
||||
* @see DummyPlugin::prepareFileContent()
|
||||
* @see DummyPlugin::onContentParsed()
|
||||
* @param string &$rawContent raw file contents
|
||||
* @return void
|
||||
*/
|
||||
public function onContentParsing(&$rawContent)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has prepared the raw file contents for parsing
|
||||
*
|
||||
* @see Pico::parseFileContent()
|
||||
* @see DummyPlugin::onContentParsed()
|
||||
* @param string &$content prepared file contents for parsing
|
||||
* @return void
|
||||
*/
|
||||
public function onContentPrepared(&$content)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has parsed the contents of the file to serve
|
||||
*
|
||||
* @see Pico::getFileContent()
|
||||
* @param string &$content parsed contents
|
||||
* @return void
|
||||
*/
|
||||
public function onContentParsed(&$content)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico reads all known pages
|
||||
*
|
||||
* @see Pico::readPages()
|
||||
* @see DummyPlugin::onSinglePageLoaded()
|
||||
* @see DummyPlugin::onPagesLoaded()
|
||||
* @return void
|
||||
*/
|
||||
public function onPagesLoading()
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered when Pico reads a single page from the list of all known pages
|
||||
*
|
||||
* The `$pageData` parameter consists of the following values:
|
||||
* <pre>
|
||||
* +----------------+--------+------------------------------------------+
|
||||
* | 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) |
|
||||
* | description | string | description of the page (YAML header) |
|
||||
* | author | string | author of the page (YAML header) |
|
||||
* | time | string | timestamp derived from the Date header |
|
||||
* | date | string | date of the page (YAML header) |
|
||||
* | 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 |
|
||||
* +----------------+--------+------------------------------------------+
|
||||
* </pre>
|
||||
*
|
||||
* @see DummyPlugin::onPagesLoaded()
|
||||
* @param array &$pageData data of the loaded page
|
||||
* @return void
|
||||
*/
|
||||
public function onSinglePageLoaded(&$pageData)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has read all known pages
|
||||
*
|
||||
* See {@link DummyPlugin::onSinglePageLoaded()} for details about the
|
||||
* structure of the page data.
|
||||
*
|
||||
* @see Pico::getPages()
|
||||
* @see Pico::getCurrentPage()
|
||||
* @see Pico::getPreviousPage()
|
||||
* @see Pico::getNextPage()
|
||||
* @param array &$pages data of all known pages
|
||||
* @param array &$currentPage data of the page being served
|
||||
* @param array &$previousPage data of the previous page
|
||||
* @param array &$nextPage data of the next page
|
||||
* @return void
|
||||
*/
|
||||
public function onPagesLoaded(&$pages, &$currentPage, &$previousPage, &$nextPage)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico registers the twig template engine
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function onTwigRegistration()
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered before Pico renders the page
|
||||
*
|
||||
* @see Pico::getTwig()
|
||||
* @see DummyPlugin::onPageRendered()
|
||||
* @param Twig_Environment &$twig twig template engine
|
||||
* @param mixed[] &$twigVariables template variables
|
||||
* @param string &$templateName file name of the template
|
||||
* @return void
|
||||
*/
|
||||
public function onPageRendering(&$twig, &$twigVariables, &$templateName)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggered after Pico has rendered the page
|
||||
*
|
||||
* @param string &$output contents which will be sent to the user
|
||||
* @return void
|
||||
*/
|
||||
public function onPageRendered(&$output)
|
||||
{
|
||||
// your code
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Example hooks for a Pico plugin
|
||||
*
|
||||
* @author Gilbert Pellegrom
|
||||
* @link http://picocms.org
|
||||
* @license http://opensource.org/licenses/MIT
|
||||
*/
|
||||
class Pico_Plugin
|
||||
{
|
||||
|
||||
public function plugins_loaded()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function config_loaded(&$settings)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function request_url(&$url)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_load_content(&$file)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function after_load_content(&$file, &$content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_404_load_content(&$file)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function after_404_load_content(&$file, &$content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_read_file_meta(&$headers)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function file_meta(&$meta)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_parse_content(&$content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function after_parse_content(&$content)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function get_page_data(&$data, $page_meta)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function get_pages(&$pages, &$current_page, &$prev_page, &$next_page)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_twig_register()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function before_render(&$twig_vars, &$twig, &$template)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function after_render(&$output)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,48 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>{% if meta.title %}{{ meta.title }} | {% endif %}{{ site_title }}</title>
|
||||
{% if meta.description %}
|
||||
<meta name="description" content="{{ meta.description }}">
|
||||
{% endif %}{% if meta.robots %}
|
||||
<meta name="robots" content="{{ meta.robots }}">
|
||||
{% endif %}
|
||||
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,700" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ theme_url }}/style.css" type="text/css" />
|
||||
|
||||
<script src="{{ theme_url }}/scripts/modernizr-2.6.1.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header id="header">
|
||||
<div class="inner clearfix">
|
||||
<h1><a href="{{ base_url }}" id="logo">{{ site_title }}</a></h1>
|
||||
<nav>
|
||||
<a href="#" class="menu-icon"></a>
|
||||
<ul>
|
||||
{% for page in pages %}
|
||||
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="content">
|
||||
<div class="inner">
|
||||
{{ content }}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer id="footer">
|
||||
<div class="inner">
|
||||
<a href="http://picocms.org/">Pico</a> was made by <a href="http://gilbert.pellegrom.me">Gilbert Pellegrom</a>
|
||||
from <a href="http://dev7studios.com">Dev7studios</a>.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
49
themes/default/index.twig
Normal file
49
themes/default/index.twig
Normal file
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en" class="no-js">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
<title>{% if meta.title %}{{ meta.title }} | {% endif %}{{ site_title }}</title>
|
||||
{% if meta.description %}
|
||||
<meta name="description" content="{{ meta.description|striptags }}">
|
||||
{% endif %}{% if meta.robots %}
|
||||
<meta name="robots" content="{{ meta.robots }}">
|
||||
{% endif %}
|
||||
|
||||
<link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans:400,700" type="text/css" />
|
||||
<link rel="stylesheet" href="{{ theme_url }}/style.css" type="text/css" />
|
||||
|
||||
<script src="{{ theme_url }}/scripts/modernizr-2.6.1.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header id="header">
|
||||
<div class="inner clearfix">
|
||||
<h1><a href="{{ "index"|link }}" id="logo">{{ site_title }}</a></h1>
|
||||
<nav>
|
||||
<a href="#" class="menu-icon"></a>
|
||||
<ul>
|
||||
{% for page in pages %}
|
||||
<li><a href="{{ page.url }}">{{ page.title }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section id="content">
|
||||
<div class="inner">
|
||||
{{ content }}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer id="footer">
|
||||
<div class="inner">
|
||||
<a href="http://picocms.org/">Pico</a>
|
||||
was made by <a href="http://gilbert.pellegrom.me">Gilbert Pellegrom</a>
|
||||
from <a href="http://dev7studios.com">Dev7studios</a>.
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Reference in a new issue