Compare commits

..

885 commits
v0.3 ... master

Author SHA1 Message Date
Maya McDougall
09aa825787
Update Twig URL 2022-07-27 15:17:31 -04:00
Maya McDougall
ff5e345e58
Added Temporary PHP 8.0 Notice 2022-02-06 16:34:18 -05:00
Daniel Rudolf
7e3c6a7b3e
Merge pull request #599 from dipohl/patch-1
Update web links in index.md
2021-08-15 13:38:01 +02:00
dipohl
2e425dc8ef
Update index.md
Checked all web links and updated them where necessary especially eliminating some 404 errors.
2021-08-15 11:02:43 +02:00
Daniel Rudolf
09fbaaaf33
IRC: Switch from Freenode to Libera.Chat 2021-08-13 17:19:24 +02:00
Daniel Rudolf
d0f32c0a2b
Create SECURITY.md 2021-06-21 20:45:31 +02:00
Daniel Rudolf
d8470f9f5c
Replace Probot Stale with GitHub Action
Looks like Probot Stale is abandoned... Too bad. 😒
2021-03-09 13:40:16 +01:00
Daniel Rudolf
221625efac
CONTRIBUTING.md: Rename 'type: Question' label to 'type: Support' 2020-11-11 16:10:46 +01:00
Daniel Rudolf
7228129cad
Version 2.1.4
```
* [Changed] Silence PHP errors in Parsedown
* [Fixed] #560: Improve charset guessing for formatted date strings using
          `strftime()` (Pico always uses UTF-8, but `strftime()` might not)
```
2020-08-29 16:15:52 +02:00
Daniel Rudolf
b95cfe0a0e
Update Pico::VERSION and Pico::VERSION_ID 2020-08-29 16:15:37 +02:00
Daniel Rudolf
e4741d0fde
Update CHANGELOG.md 2020-08-29 16:14:52 +02:00
Daniel Rudolf
1916dc5645
Silence PHP notices in upstream Parsedown
Parsedown is a still unresolved issue in whole, this at least ensures that we don't fill up logfiles with useless errors...
2020-08-29 16:07:10 +02:00
Daniel Rudolf
4be1f6ae90
Try to proberly encode formatted date strings returned by strftime()
Fixes #560
2020-08-29 16:04:10 +02:00
Daniel Rudolf
0e2b124b8e
Version 2.1.3
```
* [New] Add `locale` option to `config/config.yml`
* [Changed] Improve Pico docs
```
2020-07-10 18:51:38 +02:00
Daniel Rudolf
590d467347
Update Pico::VERSION and Pico::VERSION_ID 2020-07-10 18:51:32 +02:00
Daniel Rudolf
649feed2f6
Update CHANGELOG.md 2020-07-10 18:50:35 +02:00
Dimitri Merejkowsky
1345d6ac82 More inclusive README
Replace 'you guys' by something more gender neutral.
2020-06-29 21:40:47 +02:00
Daniel Rudolf
60f27dfe85
Merge pull request #546 from asdfuser/master
Add option to set a locale
2020-06-14 19:03:08 +02:00
Daniel Willmann
b2df860546 Add option to set a locale
As mentioned in https://www.php.net/manual/en/function.basename.php both
basename() and dirname() are locale aware.
An incorrect locale can cause the page tree to behave in strange ways.

For example the structure

/über-uns
 |-index.md
 |-impressum.md

could lead to the page impressum not being a child of über-uns.
2020-06-14 17:34:46 +02:00
Daniel Rudolf
1aca13e83d
Version 2.1.2
```
* [Fixed] Fix DummyPlugin declaring API version 3
```
2020-04-10 23:18:00 +02:00
Daniel Rudolf
b892d6bb11
Update Pico::VERSION and Pico::VERSION_ID 2020-04-10 23:17:45 +02:00
Daniel Rudolf
0ddde859e8
Update CHANGELOG.md 2020-04-10 23:17:01 +02:00
Daniel Rudolf
6c746fabb6
Fix DummyPlugin declaring API version 3 2020-04-10 23:14:33 +02:00
Daniel Rudolf
af9c09e440
Add composer.json branch alias for Pico 3.0 2020-03-29 16:04:38 +02:00
Daniel Rudolf
5d6257feac
Update composer.json branch aliases 2020-03-29 14:35:52 +02:00
Daniel Rudolf
b49936fb3a
Version 2.1.1
```
* [Fixed] Require Parsedown 1.8.0-beta-7 and Parsedown Extra 0.8.0-beta-1 due
          to changes in Parsedown and Parsedown Extra breaking BC beyond repair
* [Changed] #523: Check for hidden pages based on page ID instead of full paths
* [Changed] Improve Pico docs
```
2019-12-31 16:33:55 +01:00
Daniel Rudolf
6672fb2277
Update Pico::VERSION and Pico::VERSION_ID 2019-12-31 16:33:45 +01:00
Daniel Rudolf
4c97f69ef8
Update CHANGELOG.md 2019-12-31 16:32:22 +01:00
Daniel Rudolf
8a44584291
Composer: Force Parsedown 1.8.0-beta-7 and Parsedown Extra 0.8.0-beta-1
A few days ago Parsedown released new ("stable") versions of Parsedown and Parsedown Extra: Parsedown 1.7.4 and Parsedown Extra 0.8.1. Parsedown 1.7.4 backports some features of Parsedown 1.8.0-beta-7 and is compatible with Parsedown Extra 0.8.1. However, due to these changes Parsedown Extra 0.8.1 now breaks compatibility with Parsedown 1.8.0-beta-7. Parsedown's release process is messed up beyond repair... Not sure what we're going to do now, this needs some research whether we can downgrade to Parsedown 1.7.4 without breaking things (what would require us to release a new major release, i.e. Pico 3.0). For now we're pinning Parsedown 1.8.0-beta-7 and Parsedown Extra 0.8.0-beta-1 as of Pico 2.1.0.
2019-12-31 16:25:52 +01:00
Daniel Rudolf
447479d973
Test hidden page requests on page ID
Fixes #523
2019-12-31 00:36:22 +01:00
Daniel Rudolf
1d250a2f7c
Travis CI: Switch to PHP 5.3 for branch deployment (just like release deployment) 2019-12-02 19:28:16 +01:00
Daniel Rudolf
86f82b930d
Travis CI: Update to Ubuntu Bionic, add HHVM 3.24 LTS 2019-12-02 19:22:57 +01:00
Daniel Rudolf
95146669f7
README.md: Add instructions for using a Git repo 2019-12-02 18:37:56 +01:00
Daniel Rudolf
ae1225f725
Travis CI: Add PHP 7.4 2019-11-30 16:43:00 +01:00
Daniel Rudolf
2661730ef5
CONTRIBUTING.md: Add `info: Pico CMS for Nextcloud\' label 2019-11-29 15:42:33 +01:00
Daniel Rudolf
41a4da5229
Merge pull request #515 from picocms/pico-2.1
This is **Pico 2.1 - small, but mighty!**

If you want to upgrade to Pico 2.1, simply follow the usual upgrade instructions for minor releases. Installing Pico is as easy as before. You can find more extensive upgrade instructions as well as a complete list of all additions and changes in Pico's [upgrade docs](http://picocms.org/in-depth/upgrade-pico-21/) - even though this is a minor release, it's still a lot of new and improved stuff!

You might also want to give [Pico CMS for Nextcloud `v1.0.0`](https://apps.nextcloud.com/apps/cms_pico) a try - it's now an official part of Pico. You can find more info at [picocms.org](http://picocms.org/plugins/#pico-cms-for-nextcloud)
2019-11-25 01:11:59 +01:00
Daniel Rudolf
232a90bdf8
Version 2.1.0
```
* [Changed] Add Pico's official logo and tagline to `content-sample/_meta.md`
* [Changed] Improve `content-sample/theme.md` to show Pico's official logo and
            the usage of the new image utility classes of Pico's default theme
* [Changed] Improve Pico docs and PHPDoc class docs
```
2019-11-25 00:43:58 +01:00
Daniel Rudolf
a87e40fbf0
Update Pico::VERSION 2019-11-25 00:43:58 +01:00
Daniel Rudolf
e4e249ae27
Update CHANGELOG.md 2019-11-25 00:43:58 +01:00
Daniel Rudolf
636e8d2a8a
Travis CI: Force Composer minimum stability <= beta
Unfortunately we must force Composer minimum stability <= beta due to Parsedown 1.8 currently being in beta. Composer AFAIK can't decide this on a per-dependency basis...
2019-11-25 00:43:53 +01:00
Daniel Rudolf
a5ff37e380
Travis CI: Remove 'sudo' requirement for branch deployment 2019-11-25 00:41:08 +01:00
Daniel Rudolf
b25225bbf4
README.md: Update screenshot 2019-11-24 23:40:51 +01:00
Daniel Rudolf
35bfdf51b7
Sample contents: Add usage of Pico's pages variable 2019-11-24 22:20:48 +01:00
Daniel Rudolf
bd0a257784
Update CHANGELOG.md 2019-11-23 19:45:11 +01:00
Daniel Rudolf
47d533982d
Replace Placeholder logo in content-sample/theme.md by Pico's logo
Also shows the new image utility classes of Pico's default theme

Co-Authored-By: type76 <osmanjaro@gmail.com>
2019-11-23 19:39:16 +01:00
Daniel Rudolf
558840643b
Add Pico's logo and tagline to the sample contents 2019-11-23 19:38:45 +01:00
Daniel Rudolf
cc6a478939
README: Mention requirement of PHP extensions 'dom' and 'mbstring'
Resolves #517
2019-11-18 16:49:08 +01:00
Daniel Rudolf
c02e3fa7a4
Various small improvements 2019-11-18 09:55:36 +01:00
Daniel Rudolf
03d466c117
Fix Pico's sample contents 2019-11-13 00:23:43 +01:00
Daniel Rudolf
c99f3cbbdf
Update @version phpDoc class docs 2019-11-11 19:02:11 +01:00
Daniel Rudolf
3b8d89fa30
composer.json: Adding myself as lead dev 2019-11-11 18:33:22 +01:00
Daniel Rudolf
420ede0daa
composer.json: Remove 'ext-dom' extension
Pico doesn't require 'ext-dom' itself, Parsedown Extra does; Parsedown Extra didn't declare this dependency before, but Parsedown Extra 0.8 finally does.
2019-11-10 17:24:25 +01:00
Daniel Rudolf
a04bc6c6b8
Version 2.1.0-beta.1
```
* [New] Add `assets_dir`, `assets_url` and `plugins_url` config params
* [New] Add `%config.*%` Markdown placeholders for scalar config params and the
        `%assets_url%`, `%themes_url%` and `%plugins_url%` placeholders
* [New] Add `content-sample/theme.md` for theme testing purposes
* [New] Introduce API versioning for themes and support theme-specific configs
        using the new `pico-theme.yml` in a theme's directory; `pico-theme.yml`
        allows a theme to influence Pico's Twig config, to register known meta
        headers and to provide defaults for theme config params
* [New] Add `assets_url`, `themes_url` and `plugins_url` Twig variables
* [New] Add `pages` Twig function to deal with Pico's page tree; this function
        replaces the raw usage of Pico's `pages` array in themes
* [New] Add `url` Twig filter to replace URL placeholders (e.g. `%base_url%`)
        in strings using the new `Pico::substituteUrl()` method
* [New] Add `onThemeLoading` and `onThemeLoaded` events
* [New] Add `debug` config param and the `Pico::isDebugModeEnabled()` method,
        cehcking the `PICO_DEBUG` environment variable, to enable debugging
* [New] Add new `Pico::getNormalizedPath()` method to normalize a path; this
        method should be used to prevent content dir breakouts when dealing
        with paths provided by user input
* [New] Add new `Pico::getUrlFromPath()` method to guess a URL from a file path
* [New] Add new `Pico::getAbsoluteUrl()` method to make a relative URL absolute
* [New] #505: Create pre-built `.zip` release archives
* [Fixed] #461: Proberly handle content files with a UTF-8 BOM
* [Changed] Introduce API version 3
* [Changed] Rename `theme_url` config param to `themes_url`; the `theme_url`
            Twig variable and Markdown placeholder are kept unchanged
* [Changed] Update to Parsedown Extra 0.8 and Parsedown 1.8 (both still beta)
* [Changed] Enable Twig's `autoescape` feature by default; outputting a
            variable now causes Twig to escape HTML markup; Pico's `content`
            variable is a notable exception, as it is marked as being HTML safe
* [Changed] Rename `prev_page` Twig variable to `previous_page`
* [Changed] Mark `markdown` and `content` Twig filters as being HTML safe
* [Changed] Add `$singleLine` param to `markdown` Twig filter as well as the
            `Pico::parseFileContent()` method to parse just a single line of
            Markdown input
* [Changed] Add `AbstractPicoPlugin::configEnabled()` method to check whether
            a plugin should be enabled or disabled based on Pico's config
* [Changed] Deprecate the use of `AbstractPicoPlugin::__call()`, use
            `PicoPluginInterface::getPico()` instead
* [Changed] Update to Twig 1.36 as last version supporting PHP 5.3, use a
            Composer-based installation to use a newer Twig version
* [Changed] Add `$basePath` and `$endSlash` params to `Pico::getAbsolutePath()`
* [Changed] Deprecate `Pico::getBaseThemeUrl()`
* [Changed] Replace various `file_exists` calls with proper `is_file` calls
* [Changed] Refactor release & build system
* [Changed] Improve PHP class docs
* [Changed] Various small improvements
* [Removed] Remove superfluous `base_dir` and `theme_dir` Twig variables
* [Removed] Remove `PicoPluginInterface::__construct()`
```
2019-11-04 01:49:11 +01:00
Daniel Rudolf
29f2e95160
Update Pico::VERSION 2019-11-04 01:49:11 +01:00
Daniel Rudolf
58ec760f04
Update CHANGELOG.md 2019-11-04 01:49:11 +01:00
Daniel Rudolf
db1c6301e6
Build system: Fix release package deployment 2019-11-04 01:49:03 +01:00
Daniel Rudolf
03d475c31c
Update Pico's sample contents to reflect the changes of Pico 2.1 2019-11-04 00:36:05 +01:00
Daniel Rudolf
dec44817a5
Build system: Add $PROJECT_REPO_TAG param to release.sh call 2019-11-03 21:18:28 +01:00
Daniel Rudolf
58f615403e
Refactor Build system
- Separate Travis branch deployment and release deployment stages (also makes `deploy.sh` obsolete)
- Add `clean.sh` and `release.sh` scripts to allow users to create "release" packages locally
- Use `setup/*.sh` scripts to check and install build dependencies (like PHP_CodeSniffer, phpDocumentor and cloc)
- Use `create-release.sh` of `picocms/ci-tools` to create release archives
- Streamline script usage

Use the following to test Pico and to create a "release" package locally:

```sh
cd ~/My-Pico-Workspace/Components/pico

ln -rs ../ci-tools .build/ci-tools

. ./.build/ci-tools/init/local.sh.inc
. ./.build/init.sh.inc

phpcs --standard=.phpcs.xml "$PICO_PROJECT_DIR"

clean.sh
release.sh
```
2019-11-03 20:03:48 +01:00
Daniel Rudolf
7bbd8736d1
Update CHANGELOG.md 2019-10-26 14:09:58 +02:00
Daniel Rudolf
e0415c8c1d
Mark Pico's content Twig variable as being safe
This no longer requires themes to output the `content` variable using `{{ content|raw }}`, theme developers can use `{{ content }}` as before.
2019-10-26 14:02:11 +02:00
Daniel Rudolf
3480a520d9
Build system: Use PHP 5.3 to create pre-built release packages
Otherwise Composer downloads a newer version of Twig which isn't compatible with PHP 5.3. Since we don't pin down specific versions of our dependencies, Composer-based installations might use newer versions of Twig which aren't compatible with PHP 5.3. Raising the PHP requirements requires a new major version, something that will definitly happen with Pico 3.0.
2019-10-26 14:00:45 +02:00
Daniel Rudolf
2a23edde4e
Fix code formatting 2019-10-26 11:34:58 +02:00
Daniel Rudolf
23000af64e
Add $singleLine param to Twig markdown parser
This allows you to parse just a single line of Markdown, i.e. the parsed output won't include a HTML paragraph element.
2019-10-24 13:03:38 +02:00
Daniel Rudolf
be0812fb55
Mark Twig content filter as HTML safe 2019-10-24 12:05:08 +02:00
Daniel Rudolf
cb3bdd149f
Mark Twig markdown filter as HTML safe 2019-10-24 12:02:23 +02:00
Daniel Rudolf
d2573c5df5
Fix $this->config['twig_config'] handling in Pico::loadTheme() 2019-10-20 19:17:42 +02:00
Daniel Rudolf
9c00ac4191
Travis CI: Remove not-yet-released PHP 7.4 2019-10-20 15:54:31 +02:00
Daniel Rudolf
b088555d17
Create .github/FUNDING.yml 2019-10-20 15:52:41 +02:00
Daniel Rudolf
1d5aba46af
Support content files with UTF-8 BOM
Resolves #461
2019-10-20 15:16:40 +02:00
Daniel Rudolf
d95c9d3708
Add content-sample/theme.md
The purpose of `theme.md` is to aid theme development - on this page you'll find basically every format that is possible with Markdown. If you develop a theme, you should make sure that all examples below show decent. The page doesn't show up in the website's menu due to `hidden: true` in the page's YAML header.
2019-10-12 19:54:06 +02:00
Daniel Rudolf
87bcff1654
Various small improvements 2019-10-12 15:54:05 +02:00
Daniel Rudolf
e4e6f0f5f0
Merge branch 'master' into pico-2.1
Conflicts:
	config/config.yml.template
2019-10-12 15:05:02 +02:00
Daniel Rudolf
6ffbbec689
Improve theme API version retrieval 2019-10-12 15:01:16 +02:00
Daniel Rudolf
87ced8c8bd
Improve phpDoc class docs 2019-10-01 13:29:16 +02:00
Daniel Rudolf
7684fc455a
Improve index.php error message for a missing 'vendor/autoload.php' 2019-10-01 13:29:06 +02:00
Daniel Rudolf
92a8a299f8
Travis CI: Add PHP 7.4, improve deployment logging 2019-10-01 13:28:21 +02:00
Daniel Rudolf
681ad27158
🎉 Add Twig pages function
This function should be used most of the time when dealing with Pico's pages array, as it allows one to easily traverse Pico's pages tree (see `Pico::getPageTree()`) to retrieve a subset of Pico's pages array in a very convenient and performant way.
2019-09-22 18:55:35 +02:00
Daniel Rudolf
b27b4f388a
🎉 Add Pico theme API versioning and add pico-theme.yml
- Add pico-theme.yml with a theme's API version, theme-specific default Twig config, registering theme-specific custom meta headers and defaults for Pico's `theme_config` config
- Add new `onThemeLoading(&$theme)` and `onThemeLoaded($theme, $themeApiVersion, &$themeConfig)` events
- Enable Twig autoescaping by default
2019-09-22 18:49:37 +02:00
Robbert
c99e3e639d Fixed typo in config.yml (#510) 2019-09-14 22:18:23 +02:00
Daniel Rudolf
c1113a780c
Fix @deprecated notice for Pico::getBaseThemeUrl() and AbstractPicoPlugin::__call() 2019-09-12 14:00:58 +02:00
Daniel Rudolf
d0b637f686
Build system: Use PHP 5.6 for deployment due to broken phpDocumentor v2.9
phpDocumentor v3.0 (currently in alpha) is broken, too, generating class docs without a single working link
2019-09-12 13:46:22 +02:00
Daniel Rudolf
cd3d3dcec5
Bump API version
Due to ad729a99c4 and 33117be981
2019-09-12 12:45:35 +02:00
Daniel Rudolf
17aba01513
Various small improvements 2019-09-12 12:42:01 +02:00
Daniel Rudolf
fd97c70502
Deprecated AbstractPicoPlugin::__call() in favour of PicoPluginInterface::getPico() 2019-09-12 12:41:47 +02:00
Daniel Rudolf
581a3a0609
Add AbstractPicoPlugin::configEnabled() 2019-09-12 12:38:59 +02:00
Daniel Rudolf
bbccb374de
phpDoc class docs: Use {@inheritDoc} in AbstractPicoPlugin 2019-09-12 12:38:59 +02:00
Daniel Rudolf
d72bc24ab3
Remove PicoPluginInterface::__construct()
It doesn't really matter how the current Pico instance is injected into the plugin unless PicoPluginInterface::getPico() is implemented
2019-09-12 12:38:59 +02:00
Daniel Rudolf
eca06a38a9
phpDoc class docs: Remove superflous @return void 2019-09-12 12:38:59 +02:00
Daniel Rudolf
56659ab95d
Build system: Don't use Composer for dev dependencies
PHP_CodeSniffer and phpDocumentor are external tools which should never affect Pico's environment, thus we rather use PHARs in the future.
2019-09-12 12:38:56 +02:00
TheTechRobo
b1ec1e55e1 Update README.md (#507) 2019-09-03 09:53:45 +02:00
Daniel Rudolf
6e6d80c044
Add Pico::substituteUrl() and url Twig filter
Allows theme developers and users to use URL placeholders like `%base_url%` in meta headers, e.g. to include images.
2019-08-30 16:37:01 +02:00
Daniel Rudolf
715cb83431
Improve class docs of Pico::getBaseThemeUrl() and Pico::getUrlFromPath() 2019-08-29 23:07:16 +02:00
Daniel Rudolf
8d6e9ac31e
Replace file_exists() by is_file() 2019-08-29 23:06:27 +02:00
Daniel Rudolf
641cae849b
Travis CI: Additionally create .zip release archives 2019-08-29 16:42:18 +02:00
Daniel Rudolf
c9a3f84673
Sync config/config.yml.template with Pico::loadConfig() 2019-07-14 16:16:57 +02:00
Daniel Rudolf
8c8c6e33f7
composer.json: Remove 3.0.x-dev alias 2019-07-14 15:36:02 +02:00
Daniel Rudolf
6476d6507d
Re-add deprecated Pico::getBaseThemeUrl() to maintain BC 2019-07-14 15:21:12 +02:00
Daniel Rudolf
ae82c16369
composer.json: Add 2.1.x-dev alias for pico-2.1 branch 2019-07-14 15:20:39 +02:00
Daniel Rudolf
3eab6c58d0
Bump version to 2.1.0-nightly 2019-07-14 15:19:59 +02:00
Daniel Rudolf
f3b5a92247
Fix directory separator in Pico::getUrlFromPath() 2019-07-14 14:56:14 +02:00
Daniel Rudolf
ad729a99c4
Remove base_dir and theme_dir Twig variables
These variables aren't really needed in Twig and can still be accessed using $config
2019-07-14 14:56:14 +02:00
Daniel Rudolf
33117be981
Config: Rename theme_url to themes_url, add plugins_url, assets_url and assets_dir 2019-07-14 14:56:14 +02:00
Daniel Rudolf
38bb0a4ac7
Various small improvements 2019-04-30 15:30:00 +02:00
Daniel Rudolf
bb1b8639bd
Add Pico::getUrlFromPath() and Pico::getAbsoluteUrl(), replacing Pico::getBaseThemeUrl() 2019-04-30 15:26:31 +02:00
Daniel Rudolf
f016c8a937
Add Pico::getNormalizedPath() 2019-04-30 15:22:49 +02:00
Daniel Rudolf
8ce3b0c224
Add debug mode
You can enable Pico's debug mode by setting the PICO_DEBUG environment variable. At the moment this just enables Twig's debug mode.
2019-03-28 20:12:46 +01:00
Daniel Rudolf
edf849725d
Config template: Add more Twig config options 2019-03-28 20:11:46 +01:00
Daniel Rudolf
008ca6f41b
Pico::loadConfig(): Make twig cache path absolute 2019-03-28 19:14:23 +01:00
Daniel Rudolf
c91518a7c8
composer.json: Update Parsedown Extra 0.8 and Parsedown 1.8 version constraints 2019-03-11 23:28:09 +01:00
Daniel Rudolf
787344a526
Rename prev_page Twig variable to previous_page 2019-03-11 23:02:57 +01:00
Daniel Rudolf
34ae8e8812
Support %config.*% Markdown placeholders 2019-03-11 23:02:45 +01:00
Daniel Rudolf
8cb37d38ba
composer.json: Add 3.0.x-dev alias for pico-3.0 branch 2019-03-11 23:02:02 +01:00
Daniel Rudolf
2cf60e25af
Build system: Small improvement 2019-02-21 10:35:54 +01:00
Daniel Rudolf
7c1e889717
Travis CI: Remove hhvm master and nightly, add HHVM 3.30 and 3.27
HHVM 4 no longer supports execution of PHP code. HHVM 3.30 and 3.27 are the only remaining still supported HHVM versions with PHP support. They will reach end-of-life in the course of 2019.
2019-02-21 10:35:11 +01:00
Daniel Rudolf
e697f56d10
Version 2.0.5-beta.1
```
* [New] Add PHP 7.3 tests
* [New] Add `2.0.x-dev` alias for master branch to `composer.json`
* [Changed] Update to Parsedown Extra 0.8 and Parsedown 1.8 (both still beta)
* [Changed] Improve release & build process
```
2019-01-03 13:15:49 +01:00
Daniel Rudolf
38b6aef40a
Update CHANGELOG.md 2019-01-03 13:15:44 +01:00
Daniel Rudolf
6dd6da655f
Build system: Allow pre-release dependencies when creating pre-releases 2019-01-03 13:15:18 +01:00
Daniel Rudolf
feba0b32df
Update Pico::VERSION and Pico::VERSION_ID 2019-01-03 01:34:16 +01:00
Daniel Rudolf
1c904b5215
Update CHANGELOG.md 2019-01-03 01:12:35 +01:00
Daniel Rudolf
a327977696
Update to Parsedown Extra 0.8 and Parsedown 1.8 (both currently in beta) 2019-01-03 01:00:25 +01:00
Daniel Rudolf
d663553c34
composer.json: Add 2.0.x-dev alias for master branch 2019-01-03 00:23:26 +01:00
Daniel Rudolf
5955c8c322
Update CHANGELOG.md 2018-12-31 16:20:28 +01:00
Daniel Rudolf
061a11636f
Travis CI: Add PHP 7.3 2018-12-23 23:43:13 +01:00
Daniel Rudolf
c889f5b475
Add IRC Logger
All credit goes to François Beerten from https://colabti.org and his awesome IRC Logger 2 project (https://colabti.org/ilogger2/IrcLogger2.html)
2018-12-23 23:43:02 +01:00
Daniel Rudolf
bbf4aa4f6b
Version 2.0.4
```
* [Fixed] Proberly handle hostnames with ports in `Pico::getBaseUrl()`
* [Changed] Improve documentation
```
2018-12-17 15:57:47 +01:00
Daniel Rudolf
9924cf8485
Update Pico::VERSION and Pico::VERSION_ID 2018-12-17 15:55:52 +01:00
Daniel Rudolf
8352be3937
Update CHANGELOG.md 2018-12-17 15:54:30 +01:00
M.Martellenghi
84949975b0
Proberly handle hostnames with ports in Pico::getBaseUrl() (#472)
* fixed getting current port from current host

Resolves #472
2018-12-17 15:53:33 +01:00
Daniel Rudolf
cbed65cfdf
User docs: Improve blogging example 2018-12-16 13:46:24 +01:00
Daniel Rudolf
66dbf6b2c8
Update CHANGELOG.md 2018-12-05 21:30:43 +01:00
Daniel Rudolf
8826bf4bfe
Improve install and upgrade instructions 2018-12-05 21:30:32 +01:00
Daniel Rudolf
ea924356a2
Version 2.0.3
```
* [Fixed] Support alternative server ports in `Pico::getBaseUrl()`
* [Changed] Don't require server environment variables to be configured
* [Changed] Improve release & build process
* [Changed] Improve documentation
* [Changed] Improve PHP class docs
* [Changed] Various small improvements
```
2018-12-03 12:34:12 +01:00
Daniel Rudolf
b8106c6c31
Update Pico::VERSION and Pico::VERSION_ID 2018-12-03 12:34:08 +01:00
Daniel Rudolf
c071dfa2d3
Update CHANGELOG.md 2018-12-03 12:33:57 +01:00
Daniel Rudolf
533ad99e57
Build system: Remove tag_name and target_commitish
Fixed in travis-ci/dpl#923 (ref travis-ci/dpl#914)
2018-12-03 12:33:38 +01:00
Daniel Rudolf
df17baac18
Revert "Build system: Use conditional build stages for deploying"
This reverts commit c7862de924.
2018-12-03 12:19:46 +01:00
Daniel Rudolf
c7862de924
Build system: Use conditional build stages for deploying
Thanks @BanzaiMan for this tip
2018-12-03 12:02:55 +01:00
Daniel Rudolf
cde8c8697b
Improve/update/fix phpDoc class docs 2018-12-03 11:52:05 +01:00
Daniel Rudolf
5e4d758acb
Various small code improvements 2018-12-03 11:51:39 +01:00
Daniel Rudolf
24ab96ced9
Sync inline docs 2018-12-03 11:50:28 +01:00
Daniel Rudolf
e172dd20a1
Don't require env variables, proberly handle alt server ports 2018-09-10 01:51:35 +02:00
Daniel Rudolf
bbe7f62043
Version 2.0.2
```
* [Fixed] Support Windows paths (`\` instead of `/`) in `Pico::evaluateRequestUrl()`
```
2018-08-12 13:50:09 +02:00
Daniel Rudolf
c6b81f9eb6
Update CHANGELOG.md 2018-08-12 13:50:05 +02:00
Daniel Rudolf
010a3649b6
Update Pico::VERSION and Pico::VERSION_ID 2018-08-12 13:49:16 +02:00
Bitm@rte
9005edaa25 add support for windows path on evaluateRequestUrl() method (#452)
* add support for windows path on evaluateRequestUrl() method

* update CHANGELOG.md
2018-08-06 23:47:52 +02:00
Daniel Rudolf
ac36863fa7
Version 2.0.1
```
* [Changed] Improve documentation
* [Changed] Add missing "Formatted Date", "Time" and "Hidden" meta headers; use
            the "Hidden" meta header to manually hide a page in the pages list
```
2018-07-29 13:11:21 +02:00
Daniel Rudolf
2f9f40d76c
Update Pico::VERSION and Pico::VERSION_ID 2018-07-29 13:11:14 +02:00
Daniel Rudolf
ca7321f82f
Update CHANGELOG.md 2018-07-29 12:57:21 +02:00
Daniel Rudolf
c7d4d25ab3
Add missing registred meta headers
Use the `Formatted Date` meta header to explicitly set a page's formatted date (i.e. `$meta['date_formatted']`), and `Time` to set `$meta['time']`. Use the `Hidden` meta header to manually hide a page (the page is still accessible, but won't show up in the pages list). Note the difference between `$pageData['hidden']` and `$pageData['meta']['hidden']`.
2018-07-29 12:51:28 +02:00
Daniel Rudolf
a7df4c2115
Build system: Fix GitHub release creation 2018-07-29 12:47:06 +02:00
Daniel Rudolf
dc37a3efda
Sync inline docs 2018-07-29 12:46:37 +02:00
Daniel Rudolf
16f95be865
composer.json: Remove 2.0-dev branch alias 2018-07-03 15:59:01 +02:00
Daniel Rudolf
edef825792
Build system: Don't overwrite config/config.yml.template when creating pre-bundled releases 2018-07-01 20:57:37 +02:00
Daniel Rudolf
834300acb4
Build system: Fix cloc statistics generation 2018-07-01 19:21:14 +02:00
Daniel Rudolf
41badc1829
Version 2.0.0
```
* [New] Add Bountysource
* [Changed] Improve documentation
* [Changed] Improve release & build process
* [Changed] Add `Pico::setConfig()` example to `index.php.dist`
* [Fixed] Don't load `config/config.yml` multiple times
```
2018-07-01 18:12:37 +02:00
Daniel Rudolf
be86f8fa8c
Update Pico::VERSION 2018-07-01 18:12:34 +02:00
Daniel Rudolf
238a98283a
Update CHANGELOG.md 2018-07-01 17:53:09 +02:00
Daniel Rudolf
6a7494a54d
Merge pull request #334 from picocms/pico-1.1
Pico 2.0
2018-07-01 17:45:28 +02:00
Daniel Rudolf
25c32de0ab
Update CHANGELOG.md 2018-07-01 17:23:35 +02:00
Daniel Rudolf
09057db2e0
Add Pico::setConfig() example to index.php.dist 2018-07-01 17:17:15 +02:00
Daniel Rudolf
1ce4a0bc36
Sync user and inline docs 2018-07-01 17:16:29 +02:00
Daniel Rudolf
6d6a39b744
Fix Travis build
See travis-ci/travis-ci#8248
2018-07-01 15:22:40 +02:00
Daniel Rudolf
f994ef191c
Merge branch 'enhancement/bountysource' into pico-1.1
Conflicts:
	README.md
	content-sample/index.md
	themes/default/font/fontello.eot
	themes/default/font/fontello.svg
	themes/default/font/fontello.ttf
	themes/default/font/fontello.woff
	themes/default/font/fontello.woff2
	themes/default/fontello.css
2018-07-01 14:53:18 +02:00
Daniel Rudolf
af237c1d67
Merge pull request #429 from JHeimbach/fix-configloading
stop config.yml on loading again
2018-04-29 17:31:28 +02:00
johannes Heimbach
c12b50dc1b stop config.yml on loading again 2018-04-29 17:21:27 +02:00
Daniel Rudolf
a30dcbc814
Version 2.0.0-beta.3
```
* [Changed] Add `README.md`, `CONTRIBUTING.md` and `CHANGELOG.md` of main repo
            to pre-bundled releases, keep `.gitignore`
* [Changed] Deny access to a possibly existing `composer.phar` in `.htaccess`
* [Changed] Disallow the use of the `callback` filter for the `url_param` and
            `form_param` Twig functions
* [Changed] Improve documentation
* [Fixed] Fix page tree when sorting pages by arbitrary values
* [Fixed] Fix sorting of `Pico::$nativePlugins`
```
2018-04-07 22:14:28 +02:00
Daniel Rudolf
822d58db60
Fix auto-publishing of pre-bundled releases 2018-04-07 22:14:14 +02:00
Daniel Rudolf
25ada4a8df
Update CHANGELOG.md 2018-04-07 21:37:22 +02:00
Daniel Rudolf
93f2162976
Update CHANGELOG.md 2018-03-29 22:48:36 +02:00
Daniel Rudolf
568166ad07
Check Pico::VERSION constant before deploying a new release 2018-03-29 22:48:24 +02:00
Daniel Rudolf
b405edba17
Various small improvements 2018-03-29 22:47:23 +02:00
Daniel Rudolf
190889b77b
Fix sorting of Pico::$nativePlugins
Thanks to PT on our Freenode IRC channel #picocms for reporting this!
2018-03-29 22:45:12 +02:00
Daniel Rudolf
05c2c968c3
Use filter_id() for the url_param and form_param Twig functions
This is a follow-up to 80263a91dc
2018-02-24 16:40:00 +01:00
Daniel Rudolf
80263a91dc
Disallow the use of the callback filter for the url_param and form_param Twig functions 2018-02-24 14:02:59 +01:00
Daniel Rudolf
5f7b455975
Add README.md, CONTRIBUTING.md and CHANGELOG.md to pre-bundled releases 2018-02-24 13:19:04 +01:00
Daniel Rudolf
9c182bd756
Add Lighttpd config to sample contents
Thanks @tony5 for bringing this up and testing!
2018-02-03 18:33:48 +01:00
Daniel Rudolf
03cc10183c
Fix page tree 2018-01-31 12:29:59 +01:00
Daniel Rudolf
a58bfc567e
Improve inline docs 2018-01-28 14:25:13 +01:00
Daniel Rudolf
25bfa289cf
Inline docs: Update nginx rewrite rules to match .htaccess
nginx's rewrite rules don't have to match `picocms/Pico`'s `.htaccess`, but `picocms/pico-composer`'s `.htaccess` - because basically all installations of Pico 2.0 and later use `picocms/pico-composer`'s frame.
2018-01-27 21:08:56 +01:00
Daniel Rudolf
6bb65fb12b
Deny access to composer.phar in .htaccess
This file might be present if users strictly follow our install instructions
 and don't delete it on their own after successfully installing Pico.
2018-01-27 21:03:45 +01:00
Daniel Rudolf
b6bd714e52
README.md: Add Pico 2.0 install/upgrade instructions 2018-01-27 21:03:06 +01:00
Daniel Rudolf
e079946e6f
Build system: Don't delete .gitignore when creating release archives
It doesn't make much sense to remove all .gitignore files just to explain users that they should create those files if they want to manage their website using a Git repository.
2018-01-27 21:02:06 +01:00
Daniel Rudolf
604ee70d27
Version 2.0.0-beta.2
```
* [New] Improve release & build process and move most build tools to the new
        `picocms/ci-tools` repo, allowing them to be used by other projects
* [New] Add page tree; refer to the `Pico::buildPageTree()` method for more
        details; also see the `onPageTreeBuilt` event
* [Changed] Update dependencies: Twig 1.35
* [Changed] ! Improve `.htaccess` and deny access to all dot files by default
* [Changed] ! Throw a `RuntimeException` when non-native plugins are loaded,
            but Pico's `PicoDeprecated` plugin is not loaded
* [Changed] ! Change `AbstractPicoPlugin::$enabled`'s behavior: setting it to
            TRUE now leads to throwing a `RuntimeException` when the plugin's
            dependencies aren't fulfilled; use NULL to maintain old behavior
* [Changed] ! Force themes to use `.twig` as file extension for Twig templates
* [Changed] Improve PHP class docs
* [Changed] Various small improvements
```
2018-01-21 23:31:25 +01:00
Daniel Rudolf
fb7d99d3da
Update CHANGELOG.md 2018-01-21 23:31:06 +01:00
Daniel Rudolf
c697ec2e5c
Update CHANGELOG.md for Pico v2.0.0-beta.1 and upcoming v2.0.0-beta.2 2018-01-21 23:07:10 +01:00
Daniel Rudolf
888190f15a
Various small improvements 2018-01-21 23:06:38 +01:00
Daniel Rudolf
b129a4fb12
Various small improvements 2017-12-27 21:36:56 +01:00
Daniel Rudolf
afd0a4d7a3
Change AbstractPicoPlugin::$enabled's behavior
AbstractPicoPlugin::$enabled now defaults to NULL what leaves the decision whether a plugin should be enabled or disabled by default up to Pico (precisely AbstractPicoPlugin::triggerEvent()). If all dependencies of a plugin are fulfilled, Pico enables the plugin by default. Otherwise the plugin is silently disabled (this was the behavior when AbstractPicoPlugin::$enabled was set to TRUE previously).

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

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

No matter what, the user can always explicitly enable or disable a plugin in Pico's config.
2017-12-27 21:36:08 +01:00
Daniel Rudolf
1ce1780a86
Build system: Fix release deployment 2017-12-24 14:21:32 +01:00
Daniel Rudolf
e517eac396
Improve .htaccess regex
Deny access to all dot files and dirs by default (except .well-known)

Update nginx rules accordingly and pass denied requests to Pico rather than letting nginx send a 404 response
2017-12-24 13:58:42 +01:00
Daniel Rudolf
a1dcf54683
Add .github/PULL_REQUEST_TEMPLATE.md 2017-12-02 17:55:29 +01:00
Daniel Rudolf
68b71103e9
Merge branch 'master' into pico-1.1
Conflicts:
	.gitattributes
	CONTRIBUTING.md
2017-12-02 17:48:34 +01:00
Daniel Rudolf
722de2a1e5
Build system: Refactor scripts to use picocms/ci-tools 2017-12-02 17:21:03 +01:00
Daniel Rudolf
0c83f360a8
Build system: Move _build/tools directory to a separate repo
See https://github.com/picocms/ci-tools
2017-12-02 17:03:25 +01:00
Daniel Rudolf
d2055d0e28
Update CONTRIBUTING.md 2017-11-28 18:23:48 +01:00
Daniel Rudolf
6dd41abf7a
Add '/.github export-ignore' to .gitattributes 2017-11-28 17:20:22 +01:00
Daniel Rudolf
9834e839ef
Update CONTRIBUTING.md 2017-11-28 17:18:18 +01:00
Daniel Rudolf
4c7de5b97e
Add .github/stale.yml
After resolving a issue, we usually keep it open for about a week to give users some more time for feedback and further questions. This is especially true for issues with the `type: Notice`, `type: Question`, `type: Discussion` and `type: Invalid` labels. After 7 days with no interaction, [Probot](https://probot.github.io/)'s [Stale](https://probot.github.io/apps/stale/) bot (@probot-stale) adds the `info: Stale` label to the issue to ask the participants whether the issue has been resolved. If no more activity occurs, the issue will be automatically closed by @probot-stale 2 days later.
2017-11-28 17:12:00 +01:00
Daniel Rudolf
37dfe0e6ef
Force themes to use .twig as file extension
We recommend plugin developers to use templates when serving HTML contents (like the UI of PicoAdmin), however, by supporting multiple file extensions for themes, we make it pretty hard to overwrite a plugin's template with a theme. As always, we preserve BC using PicoDeprecated.
2017-11-25 21:52:03 +01:00
Daniel Rudolf
a192a42de5
Travis CI: Add PHP 7.2 2017-11-25 21:47:20 +01:00
Daniel Rudolf
28d2648ba0
Add Pico::buildPageTree()
Pico's page tree is a list of all the tree's branches (no matter the depth). Thus, by iterating a array element, you get the nodes of a given branch. All leaf nodes do represent a page, but inner nodes may or may not represent a page (e.g. if there's a `sub/page.md`, but neither a `sub/index.md` nor a `sub.md`, the inner node `sub`, that is the parent of the `sub/page` node, represents no page itself).

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

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

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

You MUST NOT iterate the page tree itself (i.e. the list of the tree's branches), its order is undefined and the array will be replaced by a non-iterable data structure with Pico 3.0.
2017-11-18 18:34:57 +01:00
Daniel Rudolf
3846d3b685
Various small improvements 2017-11-18 18:28:02 +01:00
Daniel Rudolf
f5f38a7b0b
DummyPlugin: Improve phpDoc class docs 2017-11-18 18:27:20 +01:00
Daniel Rudolf
22aa688bf4
Version 2.0.0-beta.1 2017-11-05 18:28:25 +01:00
Daniel Rudolf
1cd6e241f0
Prepare v2.0.0-beta.1 2017-11-05 18:28:11 +01:00
Daniel Rudolf
66bb17a419
Build system: Make sure to create release archive in $TRAVIS_BUILD_DIR 2017-11-05 18:28:01 +01:00
Daniel Rudolf
46a6ff183d
Don't ignore index.php.dist when exporting Git repo
We need this file to create Pico's pre-built release archives
2017-11-05 18:02:17 +01:00
Daniel Rudolf
619ae9d0d0
Add Developer Certificate of Origin to CONTRIBUTING.md 2017-11-05 14:08:56 +01:00
Daniel Rudolf
4fb0b408e2
Build system: Improve and fix deployment 2017-11-05 02:36:50 +01:00
Daniel Rudolf
6e88e7ffbb
Build system: Disable Travis IRC notifications 2017-11-04 23:52:20 +01:00
Daniel Rudolf
1afc495584
Build system: Remove cloc release statistics 2017-11-04 22:49:02 +01:00
Daniel Rudolf
da0d4c3054
Build system: Add tools/github-commit.sh 2017-11-04 22:47:47 +01:00
Daniel Rudolf
ae99e0c2cd
Merge branch 'master' into pico-1.1
Conflicts:
	lib/Pico.php
2017-11-04 21:12:00 +01:00
Daniel Rudolf
e8a19cb2f9
Fix Pico::parseFileMeta() 2017-11-04 20:49:41 +01:00
Daniel Rudolf
cc47043570
Update README.md screenshot 2017-11-04 18:41:17 +01:00
Daniel Rudolf
2a30c4664f
Build system: Add config/config.yml.template to release archives 2017-11-04 18:41:05 +01:00
Daniel Rudolf
dfed9cc51f
Build system: Create GitHub releases as draft 2017-10-28 22:53:25 +02:00
Daniel Rudolf
c71169adbe
Update CONTRIBUTING.md 2017-10-28 22:52:47 +02:00
Daniel Rudolf
0532fef5fe
Update composer dependencies 2017-10-28 22:52:18 +02:00
Daniel Rudolf
1dee2c1cf6
Build system: Use 'picocms/pico-composer' to create release archives 2017-10-22 21:27:19 +02:00
Daniel Rudolf
448fff4702
Build system: Add version parser, handle pre-releases differently 2017-10-22 21:24:28 +02:00
Daniel Rudolf
498961b0c6
Build system: Various small improvements 2017-10-22 21:22:11 +02:00
Daniel Rudolf
81ebc4c33e
Build system: Move helper scripts to _build/tools dir 2017-10-22 21:15:29 +02:00
Daniel Rudolf
63616b5888
Add license/copyright file headers to index.php and index.php.dist 2017-10-19 22:26:43 +02:00
Daniel Rudolf
61319b011e
Add license/copyright file header; improve phpDoc class docs 2017-10-19 21:55:41 +02:00
Daniel Rudolf
d8a649e6f7
Don't lower meta data unsolicited and flip meta headers array
Don't lower unregistered meta headers on the first level unsolicited (e.g. `SomeNotRegisteredKey: foobar` in the YAML Frontmatter should result in `['SomeNotRegisteredKey']`, not `['somenotregisteredkey']`). Furthermore, Pico no longer compares registered meta headers in a case-insensitive manner. However, you can now register multiple search strings that are used to find a registered meta header. This is achieved by flipping the meta headers array: Pico 2.0 uses the array key to search for a meta value and the array value to store the found meta value. Previously it was the other way round (what didn't make much sense...).
2017-10-14 23:12:16 +02:00
Daniel Rudolf
151908fbad
Remove various event params that are a bit out of place 2017-10-14 22:08:11 +02:00
Daniel Rudolf
a231abc4c1
Remove picocms/pico-deprecated and picocms/pico-theme dependencies
In the future we'll use picocms/pico-composer to create Pico's release packages (and picocms/pico-composer depends on picocms/pico-deprecated and picocms/pico-theme by default). Installing picocms/pico-deprecated and picocms/pico-theme is no longer required, but rather suggested. You simply don't need them in any case. You need picocms/pico-deprecated only if you're using old plugins, and picocms/pico-theme is obsolete when using a 3rd-party theme.
2017-10-13 22:06:02 +02:00
Daniel Rudolf
709416328a
Pico::loadPlugins(): Add plugin blacklist and allow disabling local plugins 2017-10-13 21:02:51 +02:00
Daniel Rudolf
867f81a443
Various small improvements 2017-10-12 16:15:58 +02:00
Daniel Rudolf
0318cc25d7
Build system: Add cloc statistics to release deployment 2017-10-12 15:14:21 +02:00
Daniel Rudolf
ee013f98ee
Build system: Fix _build/create-release-archive.sh 2017-10-12 15:06:22 +02:00
Daniel Rudolf
9dcb06c258
Pico::sortPlugins(): Fix sorting of non-native plugins 2017-10-12 12:12:37 +02:00
Daniel Rudolf
20297deaec
Pico::loadLocalPlugins(): Don't load plugins case-insensitive
The performance vs. error-proneness trade-off doesn't justify this additional complexity. This is Pico 2.0, we always try to minimize BC-breaking changes, but we're breaking BC anyway by loading plugins from plugins/<plugin name>/<plugin name>.php only...
2017-10-12 12:11:55 +02:00
Daniel Rudolf
b6468ca215
Various small improvements 2017-10-08 00:36:29 +02:00
Daniel Rudolf
9a9872fe8e
Add Pico::getPageId() 2017-10-08 00:36:14 +02:00
Daniel Rudolf
7087573aed
Pico::loadPlugins(): Load composer-plugins first and skip conflicting plugins in the plugins/ dir 2017-10-08 00:35:36 +02:00
Daniel Rudolf
fc76d37dbc
Improve class docs 2017-08-05 02:49:58 +02:00
Daniel Rudolf
32ae70f398
Add $default param to getConfig() method
- Pico::getConfig()
- AbstractPicoPlugin::getPluginCongif()
2017-08-05 00:19:03 +02:00
Daniel Rudolf
8138212a27
Pico::evaluateRequestUrl(): Improve REQUEST_URI handling
Don't 404 "/index.php" requests
2017-08-03 22:17:48 +02:00
Daniel Rudolf
b73e197ccb
Refactor YAML frontmatter date parsing
You can now explicitly specify both the `date_formatted` and `time` meta values to overwrite Pico's page date handling. Specifying `time` doesn't make much sense in general, however, specifying `date_formatted` allows you to use `{{ meta.date_formatted }}` on all systems, even those where `strftime()` doesn't work as wished
2017-07-28 12:16:26 +02:00
Daniel Rudolf
0b7e03b660
Version 1.0.6
```
* [Changed] Improve documentation
* [Changed] Improve handling of Pico's Twig config (`$config['twig_config']`)
* [Changed] Improve PHP platform requirement checks
```
2017-07-25 15:02:25 +02:00
Daniel Rudolf
be0828bf2a
Update CHANGELOG.md 2017-07-25 15:02:20 +02:00
Daniel Rudolf
13b167e23a
Pico::loadConfig(): Improve Twig config parsing
Thanks @refeaime for reporting this
2017-07-25 14:43:21 +02:00
Daniel Rudolf
3e88c58ce0
Merge branch 'master' into pico-1.1
Conflicts:
	lib/Pico.php
2017-07-18 21:39:39 +02:00
Daniel Rudolf
d3c624777f
Improve guessing whether URL rewriting is enabled
Besides searching for the env var 'PICO_URL_REWRITING', also try 'REDIRECT_PICO_URL_REWRITING'.
2017-07-18 21:36:15 +02:00
Daniel Rudolf
53e9eaa5e4
Fix Pico's REQUEST_URI routing method when installed to / 2017-07-18 21:31:14 +02:00
Daniel Rudolf
de74e7d867
Improve class docs 2017-07-14 20:50:38 +02:00
Daniel Rudolf
414f5ac18e
Allow pages to be sorted by arbitrary meta values
This basically works like Pico's `sort_by` Twig filter
2017-07-14 20:37:05 +02:00
Daniel Rudolf
b626782b87
Use Pico::substituteFileContent() for Twig's "markdown" filter 2017-06-21 14:27:50 +02:00
Daniel Rudolf
55a0a5bc91
Add Pico::substituteFileContent() method 2017-06-21 14:27:34 +02:00
Daniel Rudolf
df532e45bb
Travis CI: Use Build Stages
See https://docs.travis-ci.com/user/build-stages
2017-06-21 02:26:44 +02:00
Daniel Rudolf
05c8d95b3f
Only load Twig_Extension_Debug when Twig's debug mode is enabled 2017-06-20 23:34:07 +02:00
Daniel Rudolf
4cd993c50a
Fix PHP Syntax Error 2017-06-20 18:02:32 +02:00
Daniel Rudolf
fd78ec38c7
Various small improvements 2017-06-20 17:32:09 +02:00
Daniel Rudolf
793fcdb4e1
Add "remove" fallback to Twig's "sort_by" filter 2017-06-20 17:31:49 +02:00
Daniel Rudolf
21051fe08b
Pico::loadComposerPlugins(): Use Pico::getVendorDir() instead of Pico::$vendorDir 2017-06-14 17:43:40 +02:00
Daniel Rudolf
23ad80b98a
Let Pico load plugins from vendor/pico-plugin.php
Split the Pico::loadPlugins() method to Pico::loadLocalPlugins() and Pico::loadComposerPlugins()
2017-06-14 17:10:42 +02:00
Daniel Rudolf
91771e67af
Update .htaccess 2017-06-14 12:03:30 +02:00
Daniel Rudolf
66cc087b6e
Travis CI: Explicitly set root package version for branches
Due to the fact that Travis uses a shallow clone of Pico's Git repo, composer has no chance to detect on which branch it currently is. This was no big deal with Pico 1.0, however, Pico 2.0 depends on picocms/pico-deprecated and picocms/pico-theme. We use composer's `self.version` version constraint to sync the version numbers of these separate Git repos. Thus composer must know Pico's current version to resolve these dependencies. We try to guess the current version either using known branch aliases in Pico's `composer.json`, or using the `Pico::VERSION` constant (see `_build/install.sh`).
2017-06-14 02:11:32 +02:00
Daniel Rudolf
989d080eb8
README.md: Explicitly use master branch for Travis badge 2017-06-12 21:49:57 +02:00
Daniel Rudolf
31310429fb
Merge branch 'master' into pico-1.1 2017-06-12 20:21:28 +02:00
Daniel Rudolf
66916f62bc
Travis CI: Upgrade to Ubuntu Trusty for HHVM support
However, Ubuntu Trusty doesn't support PHP 5.3, so we'll have to continue using Ubuntu Precise for PHP 5.3
2017-06-12 20:11:04 +02:00
Daniel Rudolf
cd2cc60ef6
Sync versions of pico-deprecated and pico-theme with Pico
... by using composer's special version constraint "self.version"
2017-06-12 19:36:49 +02:00
Daniel Rudolf
f0b42cf364
Add explicit dependencies to the PHP extensions "dom" and "mbstring"
Pico doesn't require the PHP extensions itself, but erusev/parsedown-extra does. The explicit composer.json requirements are necessary until erusev/parsedown-extra#85 gets merged. Both extensions aren't part of Ubuntu's default LAMP setup anymore.
2017-05-26 21:52:38 +02:00
Daniel Rudolf
3d16c8df16 Merge pull request #384 from picocms/enhancement/contributing2
CONTRIBUTING.md: Create "Labelling of Issues & Pull-Requests" section (2)
2017-05-17 23:51:11 +02:00
Daniel Rudolf
2fb7125985
Add "Labeling of Issues & Pull Requests" section to CONTRIBUTING.md 2017-05-14 15:01:11 +02:00
Daniel Rudolf
b098e22033
Various small improvements 2017-05-14 01:26:38 +02:00
Daniel Rudolf
d26da62bf1
Add onSinglePageContent event 2017-05-14 01:26:29 +02:00
Daniel Rudolf
773f4795f7
Remove Pico::registerTwig(), use Pico::getTwig() instead 2017-05-14 01:26:07 +02:00
Daniel Rudolf
80c88f2a7d
Refactor onMetaHeaders event 2017-05-14 01:25:10 +02:00
Daniel Rudolf
f4332a247c
Force PicoDeprecated to be first plugin in the plugins array 2017-05-14 01:11:16 +02:00
Daniel Rudolf
624310bbe7
Various small improvements 2017-05-13 18:17:58 +02:00
Daniel Rudolf
191f6edbe9
Don't pass the $plugins argument of the onPluginsLoaded event by reference
This is a BC breaking change!

Manipulating Pico's $plugins array is a really bad idea. We've introduced the Pico::loadPlugin() method to safely load plugins at any time, however, Pico might do unexpected things when loading plugins too late. See the class docs of Pico::loadPlugin() for more details. Nevertheless, this change breaks BC to Pico 1.0. However, I don't know a single plugin that relies on manipulating the $plugins array. If you just want to load a plugin manually, use Pico::loadPlugin() instead.
2017-05-13 18:17:19 +02:00
Daniel Rudolf
6e28a51080
Refactor onPages… and onPage… core events
Add new onPagesDiscovered event passing the unsorted pages array, move the $currentPage, $previousPage and $nextPage arguments from the onPagesLoaded event to the new onCurrentPageDiscovered event, remove the $twig argument from the onPageRendering event and rather trigger the new onTwigRegistered event for this. Also add the new onYamlParserRegistered and onParsedownRegistered events passing the YAML parser resp. the Parsedown instance. Allow plugin's to skip a page by setting the $id argument of the onSinglePageLoading event to NULL.
2017-05-13 18:08:54 +02:00
Daniel Rudolf
7b222b03e4
Add Pico::API_VERSION 2017-05-10 17:00:48 +02:00
Daniel Rudolf
36b3aef1c7
Fix Pico::loadPlugin() when called before Pico::loadPlugins() 2017-05-07 14:20:44 +02:00
Daniel Rudolf
e8e60f49e5
Update DummyPlugin 2017-05-07 14:15:24 +02:00
Daniel Rudolf
6574d482cc
Update .gitattributes 2017-05-06 20:34:26 +02:00
Daniel Rudolf
8a11a65c9f
Create distinct _build/.gitignore 2017-05-06 19:34:58 +02:00
Daniel Rudolf
aaf52dd36c
Create empty assets/ dir
Thanks @smcdougall, see 3f98896165 (commitcomment-22043296)
2017-05-06 19:28:33 +02:00
Daniel Rudolf
a8956b72bc
Version 1.0.5
```
* [Changed] Improve documentation
* [Fixed] Improve hostname detection with proxies
* [Fixed] Fix detection of Windows-based server environments
* [Removed] Remove Twitter links
```
2017-05-02 00:47:22 +02:00
Daniel Rudolf
4d1f92a1f2
Update CONTRIBUTING.md 2017-05-02 00:35:48 +02:00
Daniel Rudolf
3f98896165
Create empty content/ dir 2017-05-02 00:26:23 +02:00
Daniel Rudolf
1d73524e41
Search for content/index.md to determine the content dir to use 2017-05-02 00:22:35 +02:00
Daniel Rudolf
bba93752cb
Use dev dependencies for pico-deprecated and pico-theme 2017-05-01 23:46:10 +02:00
Daniel Rudolf
a114821466
Add 2.0-dev branch alias to composer.json 2017-05-01 23:34:57 +02:00
Daniel Rudolf
f52e3dc890
Add Pico::getVendorDir()
The vendor directory is the installation path of the `picocms/Pico` package. If `picocms/Pico` is the composer root package (as in pre-bundled releases), it should be identical to `Pico::getRootDir()`. However, if `picocms/Pico` was installed as composer dependency (e.g. by `picocms/pico-composer`), the vendor directory usually corresponds to something like `Pico::getRootDir() . "vendor/picocms/pico"`. The vendor directory is currently only used as a last resort to load Pico's sample contents.
2017-05-01 22:27:57 +02:00
Daniel Rudolf
cbb8ece579
Move PicoDeprecated plugin and default theme to separate repos
See https://github.com/picocms/pico-theme for Pico's default theme and https://github.com/picocms/pico-deprecated for the PicoDeprecated plugin.
2017-05-01 22:12:18 +02:00
Daniel Rudolf
a39bc38620
Update keywords in composer.json; Use screenshot from website in README.md 2017-05-01 20:39:11 +02:00
Daniel Rudolf
3f17a2e28e
Merge branch 'master' into pico-1.1
Conflicts:
	content-sample/index.md
	themes/default/font/fontello.eot
	themes/default/font/fontello.svg
	themes/default/font/fontello.ttf
	themes/default/font/fontello.woff
	themes/default/font/fontello.woff2
	themes/default/fontello.css
2017-05-01 20:38:03 +02:00
Daniel Rudolf
82a342ba44
Various small improvements 2017-05-01 15:12:13 +02:00
Daniel Rudolf
c69dca0f8c
Remove Twitter links
Our Twitter account is basically abandoned. Our key asset never was a hardly to subdue flood of words anyway 😆
2017-03-17 00:45:34 +01:00
Daniel Rudolf
a2d0d745ff
Fix detection of Windows-based server environments 2017-02-19 23:43:43 +01:00
Daniel Rudolf
25468dc334
Update CHANGELOG.md 2017-02-19 23:43:02 +01:00
Daniel Rudolf
921b95181b
Add Bountysource to README.md 2017-02-19 23:41:42 +01:00
Daniel Rudolf
56fffe9ac2
Add Bountysource to default contents and README.md 2017-02-19 23:41:33 +01:00
Daniel Rudolf
882a80a179
Update docs to reflect 9b7523b 2017-02-06 00:01:25 +01:00
Daniel Rudolf
d4c65fa523
Allow configuring Parsedown 2017-02-05 21:49:54 +01:00
Daniel Rudolf
5429a3a932
Add Pico::getTwigTemplate() 2017-02-05 20:20:26 +01:00
Daniel Rudolf
9b7523b9e8
Use .yml files to configure Pico
Instead of using `*.config.php` files, use `*.yml` files to configure Pico. YAML is much easier to understand, more user friendly and (at least a bit) more error-tolerant, but still very powerful. Don't break BC by letting `PicoDeprecated` still read `config/config.php`.
2017-02-05 16:52:18 +01:00
Daniel Rudolf
0a080c8965
Add lazy init for Symfony YAML, Parsedown and Twig 2017-02-05 15:55:53 +01:00
Daniel Rudolf
c56ba02b0b
Reintroduce plugin prefix classifications
This partially reverts commit 9254240
2016-12-12 20:58:38 +01:00
Daniel Rudolf
9254240e44
Load plugins from <plugin name>.php and <plugin name>/<plugin name>.php only 2016-12-12 20:37:17 +01:00
Daniel Rudolf
eec1d625c4
Add Pico::getFilesGlob() method 2016-12-12 20:36:46 +01:00
Daniel Rudolf
586d792c32
Update Pico::VERSION_ID constant 2016-12-12 17:09:30 +01:00
Daniel Rudolf
46f5d3d56d
Move Twig link filter and url_param and form_param functions to PicoTwigExtension 2016-12-12 17:08:40 +01:00
Daniel Rudolf
1f35346f53
Improve detection of hidden files to serve 404 contents instead
Follow-up to 9b72b5c316
2016-12-12 16:37:20 +01:00
Daniel Rudolf
8f7e4da53d
Rename Pico 1.1 to Pico 2.0 2016-12-12 15:31:06 +01:00
Daniel Rudolf
2e880d6c7f
Discover the previous and next pages of all pages 2016-12-12 14:49:57 +01:00
Daniel Rudolf
9b72b5c316
Give pages starting with a underscore (_) a special treatment
Follow-up to b493ebdb84
2016-12-12 14:49:05 +01:00
Daniel Rudolf
9a2dd4f078
Mark Twig variables rewrite_url and is_front_page as deprecated 2016-12-06 20:52:27 +01:00
Daniel Rudolf
ec3f7fb626
Improve class docs 2016-12-06 20:22:50 +01:00
Daniel Rudolf
5193b77fdf
Reuse YAML parser instance 2016-12-06 20:22:38 +01:00
Daniel Rudolf
5d48aa7040
Let Pico::getTwigVariables() return the "real" array
Currently Pico::getTwigVariables() always returns the default twig variables and ignores all additions/changes made through the onPageRendering event. The method now returns the "real" variables array used by Twig.
2016-12-06 20:04:07 +01:00
Daniel Rudolf
bc5729629d
Fire onMetaHeaders event only once, cache results of Pico::getMetaHeaders() 2016-12-06 20:01:38 +01:00
Daniel Rudolf
82c6dd9795
Don't sort pages when a unknown sort method is specified
Specifying a custom sort method usually means that all pages are sort by a plugin, so Pico's default alphabetical order is overwritten anyway. Letting Pico sort the pages first and discarding the result is burned CPU time...
2016-12-06 19:47:37 +01:00
Daniel Rudolf
b493ebdb84
Default theme: Navigation: Hide pages starting with a underscore (_) 2016-12-06 19:37:23 +01:00
Daniel Rudolf
b712650678
Default theme: Navigation: Show top-level pages only 2016-12-06 19:36:52 +01:00
Daniel Rudolf
ea2146b2db
Remove default plugins PicoParsePagesContent and PicoExcerpt
As previously announced (see [Upgrade to Pico 1.0 page](http://picocms.org/in-depth/upgrade/)) we'll remove the default plugins `PicoParsePagesContent` and `PicoExcerpt` with the next Pico milestone. Needless to say, that you can still install both plugins without any problem - we'll add them to Pico's official [Plugins collection](http://picocms.org/plugins/) by then. Please note that the disadvantages of these plugins are still critical and we strongly advise to not use them. Please refer to the [Upgrade to Pico 1.0 page](http://picocms.org/in-depth/upgrade/) for details.
2016-12-06 19:31:29 +01:00
Daniel Rudolf
5cf47e65de
Various small improvements 2016-12-06 19:03:58 +01:00
Daniel Rudolf
7a6e4f8271
Sort all loaded plugins using a plugin dependency topology
Execution order matters: if plugin A depends on plugin B, it usually means that plugin B does stuff which plugin A requires. However, Pico loads plugins in alphabetical order, so events might get fired on plugin A before plugin B.

Hence plugins need to be sorted. Pico sorts plugins using a dependency topology, this means that it moves all plugins, on which a plugin depends, in front of that plugin. The order isn't touched apart from that, so they are still sorted alphabetically, as long as this doesn't interfere with the dependency topology. Circular dependencies are being ignored; their behavior is undefiend. Missing dependencies are being ignored until you try to enable the dependant plugin.

This method bases on [Marc J. Schmidt's Topological Sort library](https://github.com/marcj/topsort.php) in version 1.1.0, licensed under the MIT license. It uses the `ArraySort` implementation ([class `\MJS\TopSort\Implementations\ArraySort`](https://github.com/marcj/topsort.php/blob/1.1.0/src/Implementations/ArraySort.php)).
2016-12-06 17:18:59 +01:00
Daniel Rudolf
0a269746eb
Add Pico::is404Content() method 2016-11-26 16:48:10 +01:00
Daniel Rudolf
d9393df4fa
Pico::getBaseUrl(): Improve hostname detection with proxies 2016-11-23 23:26:55 +01:00
Daniel Rudolf
d6a094216b
Merge branch 'master' into pico-1.1
Conflicts:
	_build/deploy-phpdoc-branch.sh
	themes/default/index.twig
	themes/default/style.css
2016-11-02 23:02:20 +01:00
Daniel Rudolf
381b339b9f
Build system: Fix _build/github-clone.sh 2016-11-02 22:40:05 +01:00
Daniel Rudolf
fad5d869ee
Improve build system; add _build/github-clone.sh 2016-11-02 22:23:41 +01:00
Daniel Rudolf
a9eee00950
Fix references to the picocms.github.io repo 2016-11-02 22:00:38 +01:00
Daniel Rudolf
6a68df2866
Update CHANGELOG.md 2016-11-02 03:12:09 +01:00
Daniel Rudolf
0f4257233a
Sync docs 2016-11-02 03:12:02 +01:00
Daniel Rudolf
19bc3412ad
.travis.yml: Enable HHVM nightly builds 2016-10-11 18:21:14 +02:00
Daniel Rudolf
da3d5a7e6f
.travis.yml: Enable Travis IRC notifications 2016-10-09 13:14:56 +02:00
Daniel Rudolf
6e891585ab
.travis.yml: Add PHP 7.1 to Travis CI 2016-10-09 02:52:36 +02:00
Daniel Rudolf
38615e444d
Use Pico::loadFileContent() in Pico::readPages() 2016-10-09 02:49:30 +02:00
Daniel Rudolf
bea610dbf4
Pico::evaluateRequestUrl(): Replace strpos()+substr() with strstr() 2016-10-05 14:17:10 +02:00
Daniel Rudolf
ac3f9b6742
Version 1.0.4
```
* [New] Add Pico's social icons to default theme
* [Changed] Improve documentation
* [Changed] Add CSS flexbox rules to default theme
* [Fixed] Fix handling of non-YAML 1-line front matters
* [Fixed] Fix responsiveness in default theme
```
2016-10-04 13:16:02 +02:00
Daniel Rudolf
53ebf0e39d
Update CHANGELOG.md 2016-10-04 13:15:50 +02:00
Daniel Rudolf
c44657ec4e
Update README.md: State that PHP 5.3.6+ is required
Resolves #372, thanks @Prolegomenes for reporting this
2016-10-04 13:11:21 +02:00
Daniel Rudolf
3ebb51a55e
Improve class docs
Follow-up to 00603f6
2016-10-01 19:01:21 +02:00
Daniel Rudolf
00603f61fc
Add integrated 404 Not Found page
Resolves #299
2016-10-01 18:58:04 +02:00
Daniel Rudolf
a74db1ddbb
Add Pico::filterVariable() method
This method can be used to validate and filter input data and can be called via `Pico::getUrlParameter()` (URL GET parameters) and `Pico::getFormParameter()` (HTTP POST parameters). `Pico::filterVariable()` is basically a wrapper for PHP's `filter_var()` function with various compatibility extensions to allow theme developers to use its functionality in Twig templates. Therefore Pico 1.1 adds the `url_param` (`Pico::getUrlParameter()`) and `form_param` (`Pico::getFormParameter()`) Twig functions.

Resolves #305
2016-09-17 20:10:24 +02:00
Daniel Rudolf
0b4099fdb0
Improve class docs 2016-09-17 20:02:49 +02:00
Daniel Rudolf
f73c9622b8
Fix Pico::evaluateRequestUrl(): PHP's built-in webserver doesn't always set QUERY_STRING 2016-09-17 20:02:29 +02:00
Daniel Rudolf
f8e6d4fbd1
Update CHANGELOG.md 2016-09-17 16:51:00 +02:00
Daniel Rudolf
cdba66b951
Inline docs: Use Twig's array literal rather than the split filter for sort_by 2016-09-17 16:50:36 +02:00
Daniel Rudolf
dedb09d3e9
iloveopensource.io is out of service
Don't know what happened and don't know whether Pico's new owner is using it anyway...
2016-09-02 22:54:24 +02:00
Daniel Rudolf
998ce379e1
Update _build/create-release-archive.sh 2016-08-24 21:50:03 +02:00
Daniel Rudolf
08fd7465bc
Update CHANGELOG.md 2016-08-24 21:41:54 +02:00
Daniel Rudolf
f7dc9cb47c
Default theme: Add flexbox CSS rules
I was sure that I've added that some time ago... Strange... Thanks to IRC user tony1
2016-08-24 21:37:29 +02:00
Daniel Rudolf
f9f998af65
Default theme: Fix default container width 2016-08-03 18:35:41 +02:00
Daniel Rudolf
73a0b40f72
Default theme: Fix hr element theming in IE8+ 2016-08-03 17:56:11 +02:00
Daniel Rudolf
65a37f1464
Default theme: Add basic support for IE8
Forms still look broken and I definitly will *NOT* fix that. We don't support IE8 officially!

+ some minor improvements
2016-08-03 17:16:34 +02:00
Daniel Rudolf
51e8f31692
Default theme: Improve form theming 2016-08-03 02:01:44 +02:00
Daniel Rudolf
eef41698f1
Default theme: Add basic form themeing 2016-08-03 01:01:20 +02:00
Daniel Rudolf
d143105279
Default theme (JavaScript): Fix coding standard 2016-08-02 23:42:48 +02:00
Daniel Rudolf
518d9b5aef
Default theme: Fix rem unit 2016-08-02 22:49:53 +02:00
Daniel Rudolf
432710c400
Default theme: Improve compatibility with older browsers
Namely (it could hardly be different...) Internet Explorer - even IE11 still causes trouble. The default theme now supports IE9+, even older browsers will present broken markup. The sliding animation works with IE10+ (however, it is still usable, there's just no nice animation).

Furthermore this commit heavily improves the sliding process by allowing to abort the animation. I've updated Pico's screenshot in the , too.
2016-08-02 21:50:48 +02:00
Daniel Rudolf
6a13915f15
Refactor default theme 2016-08-02 02:31:20 +02:00
Daniel Rudolf
39d4a7c2ae
Hotfix for responsiveness of default theme
I'll completely refactor the default theme for Pico 1.1... The CSS is just broken.
2016-08-01 16:51:22 +02:00
Daniel Rudolf
2dada502b5
Update README.md
As suggested by @smcdougall (https://github.com/picocms/Pico/pull/352#issuecomment-235573290)
2016-07-27 15:10:10 +02:00
Daniel Rudolf
827be2cb9c
Build System: Refactor source code and release archive creation
Resolves #313
2016-07-24 23:35:10 +02:00
Daniel Rudolf
1bf157049a
README.md: Link to about page instead of landing page 2016-07-24 20:15:35 +02:00
Daniel Rudolf
21bd18bcf0
Replace Pico::discoverRequestFile() with public Pico::resolveFilePath()
This allows plugins (e.g. PicoAdmin) to safely resolve file paths without the need of re-implementing the method.
2016-07-20 19:23:19 +02:00
Daniel Rudolf
e27be7a80f
Merge branch 'master' into pico-1.1 2016-07-15 03:23:09 +02:00
Daniel Rudolf
fb4bdfe1fc
Fix Pico::parseFileMeta() for non-YAML 1-liners
\Symfony\Component\Yaml\Parser::parse() returns the unchanged value when a 1-liner string which is no valid YAML is passed. Assume this string to be the page title. Thus the following page will work now:

```
---
This is the title
---

# Example page

{{ meta.title }} is going to be "This is the title" - or "%meta.title%" == "This is the title".
```
2016-07-15 03:13:58 +02:00
Daniel Rudolf
aa1bc077a7
Add $dropIndex parameter to Pico::getPageUrl() method
This allows one to prevent Pico from removing the last "index" path component. Example use case: Pico's official admin plugin. We must distinguish between "content/sub.md" and "content/sub/index.md", otherwise it wouldn't be possible to edit both pages.
2016-07-14 00:24:06 +02:00
Daniel Rudolf
848e28b7e6
Declare Pico::getFiles() public
This might be a useful helper method for plugins (e.g. PicoAdmin)
2016-07-14 00:20:22 +02:00
Daniel Rudolf
bf1663cc1c
Add Pico's social icons to default theme 2016-07-06 01:26:29 +02:00
Daniel Rudolf
81dddc94cf
Revert "Update composer.json: Use Symfony YAML 3.1 and later"
Symfony YAML >= 3.0 requires PHP >= 5.5.9 and we're currently not planning to raise Pico's PHP requirement.

This reverts commit f251bc83ec.
2016-06-20 22:46:57 +02:00
Daniel Rudolf
f251bc83ec
Update composer.json: Use Symfony YAML 3.1 and later 2016-06-20 22:38:24 +02:00
Daniel Rudolf
ddf3da0391
Merge branch 'master' into pico-1.1
Conflicts:
	.htaccess
	config/config.php.template
	content-sample/index.md
	lib/Pico.php
2016-06-18 20:23:23 +02:00
Daniel Rudolf
eeb43e131f
Pico::prepareFileContent(): Declare $variables variable 2016-06-18 20:19:16 +02:00
Daniel Rudolf
94279c57f8
Improve phpDocs class docs 2016-05-23 15:13:56 +02:00
Daniel Rudolf
79bb543c46
Version 1.0.3
```
* [Changed] Improve documentation
* [Changed] Heavily extend nginx configuration docs
* [Changed] Add CSS rules for definition lists to default theme
* [Changed] Always use `on404Content...` execution path when serving a `404.md`
* [Changed] Deny access to `.git` directory, `CHANGELOG.md`, `composer.json`
            and `composer.lock` (`.htaccess` file)
* [Changed] Use Pico's `404.md` to deny access to `.git`, `config`, `content`,
*           `content-sample`, `lib` and `vendor` dirs (`.htaccess` file)
* [Fixed] #342: Fix responsiveness in default theme
* [Fixed] #344: Improve HTTPS detection with proxies
* [Fixed] #346: Force HTTPS to load Google Fonts in default theme
```
2016-05-11 23:33:04 +02:00
Daniel Rudolf
d17f0a8a8f
Update CHANGELOG.md 2016-05-11 23:32:26 +02:00
Daniel Rudolf
b2a7c7623d
Sync docs 2016-05-11 23:28:26 +02:00
Daniel Rudolf
e32a46d6cf
Sync docs 2016-05-06 23:17:17 +02:00
Daniel Rudolf
86b2839660
Update .htaccess
Thanks @smcdougall, see ee5b4f0d56 (commitcomment-17304977)
2016-04-29 18:02:19 +02:00
Daniel Rudolf
0f8deda6a3
Update .htaccess
Sync with Pico 1.0.3; see ee5b4f0
2016-04-27 21:07:59 +02:00
Daniel Rudolf
ee5b4f0d56
.htaccess: Deny access to CHANGELOG.md, composer.json, composer.lock
See discussion in #343
2016-04-27 21:02:20 +02:00
Daniel Rudolf
749114df61
Build system: Update phpDoc list formatting 2016-04-27 19:00:44 +02:00
Daniel Rudolf
79a14799bb
Build system: Add phpDoc list 2016-04-27 16:49:38 +02:00
Daniel Rudolf
4c0366fa49
Build system: Move generate-version.sh 2016-04-27 16:49:10 +02:00
Daniel Rudolf
4d3eace1af
README.md: Update upgrade URL 2016-04-27 16:47:13 +02:00
Daniel Rudolf
e01044319a
Build system: Use dynamic phpDoc title 2016-04-24 21:13:47 +02:00
Daniel Rudolf
6c4f69c107
Update inline user docs to reflect 6465c2b0a9 2016-04-24 20:49:06 +02:00
Daniel Rudolf
0e8cd0873d
Merge branch 'master' into pico-1.1
Conflicts:
	.htaccess
2016-04-24 20:23:00 +02:00
Daniel Rudolf
6465c2b0a9
Support REQUEST_URI routing method
With Pico 1.0 you had to setup URL rewriting (e.g. using `mod_rewrite` on Apache) in a way that rewritten URLs follow the `QUERY_STRING` principles. Starting with version 1.1, Pico additionally supports the `REQUEST_URI` routing method, what allows you to simply rewrite all requests to just `index.php`. Pico then reads the requested page from the `REQUEST_URI` environment variable provided by the webserver. Please note that `QUERY_STRING` takes precedence over `REQUEST_URI`.
2016-04-24 20:11:05 +02:00
Daniel Rudolf
31e55ca24a
.htaccess: Pass full URL to Pico when requesting content, lib... dirs
This allows Pico to e.g. serve content/config.md when http://example.com/pico/config/ is requested
2016-04-24 04:14:58 +02:00
Daniel Rudolf
8b1539640d
Update CHANGELOG.md 2016-04-24 04:06:47 +02:00
Daniel Rudolf
49cb6c144a
Use Pico's 404.md to deny access to lib, content... dirs 2016-04-24 04:06:40 +02:00
Daniel Rudolf
6234be88b0
Always use on404Content... execution path when serving a 404.md 2016-04-24 04:06:04 +02:00
Daniel Rudolf
3a36dbd934
Build system: Add automatic version file updates for picocms.org 2016-04-24 03:25:55 +02:00
Daniel Rudolf
d19621a908
Improve themes dir guessing; add $config['theme_url'] config 2016-04-24 01:22:43 +02:00
Daniel Rudolf
1b3ef7516d
Drop the "index" part of URLs
Closes #347. Thanks @Robby-
2016-04-23 21:41:09 +02:00
Daniel Rudolf
a119122497 Fix coding standard violation 2016-04-22 14:31:14 +02:00
Daniel Rudolf
b133f6dae5 Add Pico::VERSION_ID (like PHP_VERSION_ID) 2016-04-22 14:23:46 +02:00
Daniel Rudolf
4140ad48ac Update CHANGELOG.md 2016-04-21 19:19:03 +02:00
Daniel Rudolf
4e215fe522 Default theme: Force HTTPS to load Google Fonts
See https://github.com/picocms/Pico/pull/346#issuecomment-213000364 (via #346 / d6accc2), thanks @smcdougall
2016-04-21 19:18:15 +02:00
Daniel Rudolf
2d728d56af Update CHANGELOG.md 2016-04-21 14:16:14 +02:00
Daniel Rudolf
32be061cd6 Merge pull request #346 from ghuron/patch-1
Use http or https depending on page access
2016-04-21 14:14:41 +02:00
ghuron
d6accc23ee Use http or https depending on page access 2016-04-21 14:58:47 +03:00
Daniel Rudolf
8dfb1b14c7
Improve HTTPS detection with proxies
Fixes #344. Thanks @Robby-

Implementation details taken from Symfony 3.0.4, method \Symfony\Component\HttpFoundation\Request::isSecure(), see https://github.com/symfony/symfony/blob/v3.0.4/src/Symfony/Component/HttpFoundation/Request.php#L1169-L1192
2016-04-17 02:44:41 +02:00
Daniel Rudolf
27d32430ee Update CHANGELOG.md 2016-04-16 13:57:18 +02:00
Daniel Rudolf
2678473e09 Merge pull request #342 from ErickMR19/patch-1
Update style.css
2016-04-16 13:55:47 +02:00
Erick Madrigal Ríos
0e632bdaa1 Update style.css
Responsive design is currently broken when the width is between 768px and 850px, because the width of inner class is set fixed at 850px
2016-04-16 01:14:19 -06:00
Daniel Rudolf
d8f9166918
Fix nginx configuration example
Thanks Robby (via IRC)
2016-04-15 17:25:20 +02:00
Daniel Rudolf
6557f5684d Update CHANGELOG.md 2016-04-04 13:48:29 +02:00
Daniel Rudolf
3fbcea7837 Default theme: Add definition list styling
Resolves #339. Thanks @Marcussacapuces91
2016-04-04 13:46:19 +02:00
Daniel Rudolf
2d2491e36f Update CHANGELOG.md 2016-03-24 17:42:40 +01:00
Daniel Rudolf
b31c93acf6 Inline docs: Fix blogging tutorial
Fixes #338. Thank you @marctilman
2016-03-24 17:41:26 +01:00
Daniel Rudolf
46781c7c7b Version 1.0.2
```
* [Changed] Various small improvements and changes...
* [Fixed] Check dependencies when a plugin is enabled by default
* [Fixed] Allow `Pico::$requestFile` to point to somewhere outside `content_dir`
* [Fixed] #336: Fix `Date` meta header parsing with ISO-8601 datetime strings
```
2016-03-16 14:36:08 +01:00
Daniel Rudolf
92b72104da Update CHANGELOG.md 2016-03-16 14:35:41 +01:00
Daniel Rudolf
5534e401f7 Update CHANGELOG.md 2016-03-16 14:30:45 +01:00
Daniel Rudolf
bbd8ef8847 Fix Date meta header parsing with ISO-8601 datetime strings
Symfony YAML interprets ISO-8601 datetime strings and returns timestamps instead of the string. This behavior conforms to the YAML standard, i.e. this is no bug of Symfony YAML.

Fixes #336. Thanks @csholmq for reporting this.
2016-03-16 14:27:42 +01:00
Daniel Rudolf
0a4e7443d2 Fix class doc typos 2016-03-16 13:33:52 +01:00
Daniel Rudolf
d56d3f8c8c Revert "Default theme: Move elements into Twig blocks"
This reverts commit a3fa373119.

At first glance this adds flexibility, but at the moment it is impossible with Twig to ensure the existance of a block. As a result, custom themes may break the plugin. A custom theme should overwrite a plugin's template explicitly.
2016-03-12 00:18:49 +01:00
Daniel Rudolf
3d11b8a979 Replace is_a() function calls with instanceof operator 2016-03-11 19:07:45 +01:00
Daniel Rudolf
dc621b24cd Improve class docs of Pico::loadConfig() 2016-03-06 21:00:00 +01:00
Daniel Rudolf
988a23fd02 Modular config: Load config from any config/*.config.php
Resolves #330

After loading the `config/config.php`, Pico proceeds with any existing `config/*.config.php` in alphabetical order. The file order is crucial: Config values which has been set already, cannot be overwritten by a succeeding file. This is also true for arrays, i.e. when specifying `$config['test'] = array('foo' => 'bar')` in `config/a.config.php` and `$config['test'] = array('baz' => 42)` in `config/b.config.php`, `$config['test']['baz']` will be undefined
2016-03-06 20:55:46 +01:00
Daniel Rudolf
cd74b681f5 Fix scope isolated config includes 2016-03-06 20:47:25 +01:00
Daniel Rudolf
75d5081bfb Use scope isolated includes for plugins & config 2016-03-06 20:06:24 +01:00
Daniel Rudolf
5bb1c325ff Add onSinglePageLoading event; allow skipping pages in onSinglePageLoaded 2016-03-06 00:54:36 +01:00
Daniel Rudolf
245cd15770 Refactor Pico::prepareFileContent() for better performance 2016-03-06 00:49:45 +01:00
Daniel Rudolf
479926eeb4 Add Pico::VERSION constant 2016-03-06 00:38:51 +01:00
Daniel Rudolf
43705d0f76 Minor code refactoring 2016-03-06 00:29:40 +01:00
Daniel Rudolf
0d40259c06 Merge branch 'master' into pico-1.1 2016-03-03 00:34:41 +01:00
Daniel Rudolf
8426a53f63 Allow Pico::$requestFile to point to somewhere outside content_dir
Bugfix; Refactoring Pico::load404Content() and Pico::discoverCurrentPage()
2016-03-03 00:04:31 +01:00
Daniel Rudolf
2a3e2fa576 Fix typos in class docs/exception messages 2016-03-02 22:10:49 +01:00
Daniel Rudolf
1709b920d1 Add AbstractPicoPlugin::getPluginConfig() method 2016-03-02 21:46:35 +01:00
Daniel Rudolf
a3fa373119 Default theme: Move elements into Twig blocks
Allows plugins to extend the default template
2016-03-02 21:44:38 +01:00
Daniel Rudolf
86614a3ab4 Default theme: Use flexbox to grow content div 2016-03-02 21:40:58 +01:00
Daniel Rudolf
a8f0fd1f33 Merge branch 'master' into pico-1.1 2016-02-29 21:00:14 +01:00
Daniel Rudolf
a2aa46fd0e Don't let dependant plugins automatically enable plugins which should be disabled by default
Follow-up to f10440b and c0a7fdc
2016-02-29 20:58:42 +01:00
Daniel Rudolf
c0a7fdc801 Don't always check dependants of a disabled plugin
This isn't necessary because dependant plugins will check their dependencies on their own. Follow-up to f10440b
2016-02-29 20:41:41 +01:00
Daniel Rudolf
98b1f87281 CONTRIBUTING.md: Update markdown parsers 2016-02-29 20:20:02 +01:00
Daniel Rudolf
5a9c02f7bf Allow plugins to trigger events
You MUST NOT trigger events of Pico's core through a plugin!
2016-02-29 19:51:06 +01:00
Daniel Rudolf
56b2ed6c7d Allow manual plugin loading 2016-02-29 19:50:35 +01:00
Daniel Rudolf
4f487b7ccf AbstractPicoPlugin: Fix typos in exception message 2016-02-29 19:47:02 +01:00
Daniel Rudolf
f10440b996 Check dependencies when a plugin is enabled by default 2016-02-29 19:44:25 +01:00
Daniel Rudolf
996d946eb7 Version 1.0.1
```
* [Changed] Improve documentation
* [Changed] Replace `version_compare()` with `PHP_VERSION_ID` in
            `index.php.dist` (available since PHP 5.2.7)
* [Fixed] Suppress PHP warning when using `date_default_timezone_get()`
* [Fixed] #329: Force Apache's `MultiViews` feature to be disabled
```
2016-02-27 19:25:52 +01:00
Daniel Rudolf
b7a296ffb4 CHANGELOG.md: Update v1.0.1 release date 2016-02-27 19:25:40 +01:00
Daniel Rudolf
871316962b Update README.md: Add IRC + Issue infos 2016-02-27 19:17:35 +01:00
Daniel Rudolf
51bdee794b Update CHANGELOG.md 2016-02-24 23:30:43 +01:00
Daniel Rudolf
b77c9da29b Force Apache's MultiViews feature to be disabled
Thanks @sonst-was for reporting this. Resolves #329
2016-02-24 23:28:41 +01:00
Daniel Rudolf
159a849c65 CONTRIBUTING.md: Improve "Build & Release process" section 2016-02-12 16:56:05 +01:00
Daniel Rudolf
70d3c76758 README.md: Add Freenode IRC badge
Join #picocms on irc.freenode.net via irc://irc.freenode.net/picocms or https://webchat.freenode.net/?channels=%23picocms
2016-02-06 21:37:10 +01:00
Daniel Rudolf
42c5e0a5b6 README.md: Remove Scrutinizer badge
... due to pretty pointless results and recommendations
2016-02-06 21:35:43 +01:00
Daniel Rudolf
327c55db77 Add Markdown Extra to inline user docs
Resolves #321. Thanks @ufgum for reporting
2016-02-04 14:23:16 +01:00
Daniel Rudolf
d8be108c5b Suppress PHP warning when using date_default_timezone_get()
Thanks to @nem25 for reporting this
2016-02-04 14:19:14 +01:00
Daniel Rudolf
b3f1347379 Update CHANGELOG.md 2016-01-25 19:48:29 +01:00
Daniel Rudolf
ce508fab6b Replace version_compare() in index.php.dist with PHP_VERSION_ID 2016-01-25 19:32:17 +01:00
Daniel Rudolf
1c2f6a1b23 Update class docs 2016-01-25 19:31:53 +01:00
Daniel Rudolf
dbd8fa8c2f Merge pull request #315 from picocms/enhancement/static-badges
Add static shields.io badge generator
2016-01-25 19:28:36 +01:00
Daniel Rudolf
ce84a8618c Build system: Minor code refactoring 2016-01-17 21:26:06 +01:00
Daniel Rudolf
10495c2ce5 _build/generate-badge.sh: Use curl instead of wget
After playing around a little bit with a Ubuntu 12.04 LTS virtual machine, `curl` came in my mind... I've absolutetly no idea why `curl` works, but `wget` does not (it's an issue with OpenSSL and both use it the same way...), but anyway - it works
2016-01-16 00:06:12 +01:00
Daniel Rudolf
0f85f85367 Build scripts: Fix exit codes 2016-01-14 22:57:31 +01:00
Daniel Rudolf
32ea0508cf _build/github-deploy.sh: Fix exit code on conflicting remote commit 2016-01-14 22:49:31 +01:00
Daniel Rudolf
f46d0b978c _build/generate-badge.sh: Skip on emty file 2016-01-14 16:33:42 +01:00
Daniel Rudolf
9f0c7bde5d Revert "_build/generate-badge.sh: Connect to shields.io using SSLv3"
This reverts commit 1561786f31.
2016-01-14 16:24:10 +01:00
Daniel Rudolf
1561786f31 _build/generate-badge.sh: Connect to shields.io using SSLv3
This is necessary due to a strange TLS bug in Ubuntu 12.04 LTS used by Travis CI. See https://bugs.launchpad.net/ubuntu/+source/openssl/+bug/861137 for details.
2016-01-14 16:02:34 +01:00
Daniel Rudolf
4f60289d36 _build/deploy-phpdoc-release.sh: Fix version badge status 2016-01-14 15:16:14 +01:00
Daniel Rudolf
024f994d9e _build/deploy-phpdoc-branch.sh: Don't forget to commit phpDocs cache 2016-01-14 14:51:16 +01:00
Daniel Rudolf
8c24e32f10 Build scripts: Fix formatting 2016-01-14 14:16:24 +01:00
Daniel Rudolf
2ed32d67a7 Update _build/deploy-phpdoc-release.sh 2016-01-14 14:16:14 +01:00
Daniel Rudolf
26d7d2f68e Build scripts: Fix formatting 2016-01-14 13:35:08 +01:00
Daniel Rudolf
b472664a20 Build scripts: Don't try to commit nothing 2016-01-14 13:20:04 +01:00
Daniel Rudolf
cd0e0f706f Build scripts: Git identity must be configured before committing 2016-01-14 13:12:10 +01:00
Daniel Rudolf
8554c0a60d RADME.md: Update badge URLs
Fixes mixed content warnings
2016-01-14 12:58:12 +01:00
Daniel Rudolf
d7ebf52ec9 RADME.md: Update badge URLs
Resolves #314
2016-01-14 12:53:11 +01:00
Daniel Rudolf
92026a3bd0 Add static shields.io badge generator 2016-01-14 12:49:46 +01:00
Daniel Rudolf
73078a3dc3 Fix code formatting + class docs 2016-01-07 03:00:32 +01:00
Daniel Rudolf
0198d827bf Build scripts: Add file comments 2016-01-07 03:00:32 +01:00
Daniel Rudolf
ff59c61c08 CONTRIBUTING.md: Fix wording 2016-01-06 21:29:36 +01:00
Daniel Rudolf
c760205d70 Pico::triggerEvent(): Fix method docs typo 2015-12-28 22:41:39 +01:00
Daniel Rudolf
8ed7ed0137 Version 1.0.0
```
* [New] On Christmas Eve, we are happy to announce Pico's first stable release!
        The Pico Community wants to thank all contributors and users who made
        this possible. Merry Christmas and a Happy New Year 2016!
* [New] Adding `$queryData` parameter to `Pico::getPageUrl()` method
* [Changed] Improve documentation
* [Changed] Moving `LICENSE` to `LICENSE.md`
* [Changed] Throw `LogicException` instead of `RuntimeException` when calling
            `Pico::setConfig()` after processing has started
* [Changed] Default theme now highlights the current page and shows pages with
            a title in the navigation only
* [Changed] #292: Ignore YAML parse errors (meta data) in `Pico::readPages()`
* [Changed] Various small improvements and changes...
* [Fixed] Support empty meta header
* [Fixed] #307: Fix path handling on Windows
```
2015-12-24 13:37:52 +01:00
Daniel Rudolf
d5689cc9af Update CHANGELOG.md 2015-12-24 13:37:31 +01:00
Daniel Rudolf
13632afa54 Update CHANGELOG.md 2015-12-23 16:19:48 +01:00
Daniel Rudolf
070da6d73f Improve "404.md not found" exception message 2015-12-23 16:18:16 +01:00
Daniel Rudolf
c3af40c3b9 PicoDeprecated: Fix LIB_DIR constant 2015-12-23 16:17:33 +01:00
Daniel Rudolf
5be2f8e597 Fix path handling on Windows
Fixes #307; thank you @bpgs for reporting!
2015-12-23 16:17:06 +01:00
Daniel Rudolf
14e5f3236c Partially revert fdf8167
Thanks @smcdougall for spotting
2015-12-21 12:50:31 +01:00
Daniel Rudolf
d2842956b2 Update CHANGELOG.md 2015-12-21 04:19:27 +01:00
Daniel Rudolf
9e4af2cba4 Merge pull request #294 from picocms/enhancement/YamlParseError2
Catch YAML parse errors (2)
2015-12-21 04:13:07 +01:00
Daniel Rudolf
43f953b67a Pico::readPages(): Call Pico::parseFileMeta() again when a exception is thrown 2015-12-21 04:08:35 +01:00
Daniel Rudolf
3798cbe478 Remove page title fallback 2015-12-21 04:05:25 +01:00
Daniel Rudolf
329049bd18 Fix empty meta header 2015-12-21 03:42:59 +01:00
Daniel Rudolf
67e1e8a8ea Default theme: Highlight active page + hide untitled pages
Related to #302
2015-12-21 03:31:34 +01:00
Daniel Rudolf
fdf81672a8 content-sample/index.md: Fix syntax 2015-12-21 03:24:32 +01:00
Daniel Rudolf
daca1b7495 Merge pull request #304 from smcdougall/master
Changed content to match docs changes.
2015-12-21 03:07:40 +01:00
Daniel Rudolf
b7fbf95b9d README.md: Fix EditDevDocs URL 2015-12-21 02:38:05 +01:00
Daniel Rudolf
5694cda14e Update website URLs 2015-12-20 19:44:59 +01:00
Daniel Rudolf
693d8ae4fa Update default theme footer 2015-12-16 21:51:23 +01:00
Daniel Rudolf
dc6ac516a8 Fix Pico::getPageUrl() 2015-12-13 22:27:27 +01:00
Daniel Rudolf
a138d23daf Throw LogicException instead of RuntimeException in Pico::setConfig() 2015-12-13 22:19:02 +01:00
Daniel Rudolf
0c85d70820 Adding $queryData parameter to Pico::getPageUrl() method
This allows developers to easily add custom query data to an page URL without the need to check enabled URL rewriting on their own. Since Twigs `link` filter is just an alias for Pico::getPageUrl(), theme designers can do the same with e.g. `{{ "index"|link("foo=bar&baz=42") }}`.

Theme designers, heads up! Don't forget that the result of the `link` filter is never escaped, so the result could contain unescaped ampersands when passing custom query data. You should pass the result to Twigs `escape` filter when using custom query data.
2015-12-13 22:14:05 +01:00
Daniel Rudolf
d9788c12e4 _build/generate-phpdoc.sh: Fix output formatting 2015-12-07 15:57:00 +01:00
Daniel Rudolf
93f7aaad8b Class docs: Use default markdown table format 2015-12-07 15:17:39 +01:00
smcdougall
1e2d500bfa Formatted lines to 80 characters 2015-12-06 19:28:37 -05:00
smcdougall
d8c16d974f Changed content to match docs changes. 2015-12-06 14:35:39 -05:00
theshka
fa4e095bdf Move LICENSE to LICENSE.md 2015-12-01 15:12:20 -06:00
Tyler Heshka
37082b21db fix typo/animated screenshot 2015-11-30 18:10:26 -06:00
Daniel Rudolf
f0a44910e7 Update README.md
Use automatically generated and updated license and version badges via http://shields.io/
2015-11-30 23:41:43 +01:00
theshka
5f9b070653 update README.md version 1.0.0-beta.2 2015-11-30 15:23:23 -06:00
theshka
c9c8db3e64 improve README.md 2015-11-30 15:00:40 -06:00
Daniel Rudolf
b23a777f5a Update CHANGELOG.md 2015-11-30 19:05:59 +01:00
Daniel Rudolf
2e6ce893e4 Version 1.0.0-beta.2
```
* [New] Introducing the `PicoTwigExtension` Twig extension
* [New] New `markdown` filter for Twig to parse markdown strings; Note: If you
        want to parse the contents of a page, use the `content` filter instead
* [New] New `sort_by` filter to sort an array by a specified key or key path
* [New] New `map` filter to get the values of the given key or key path
* [New] Introducing `index.php.dist` (used for pre-bundled releases)
* [New] Use PHP_CodeSniffer to auto-check source code (see `.phpcs.xml`)
* [New] Use Travis CI to generate phpDocs class docs automatically
* [Changed] Improve documentation
* [Changed] Improve table styling in default theme
* [Changed] Update composer version constraints; almost all dependencies will
            have pending updates, run `composer update`
* [Changed] Throw a RuntimeException when the `content` dir isn't accessible
* [Changed] Reuse `ParsedownExtra` object; new `onParsedownRegistration` event
* [Changed] `$config['rewrite_url']` is now always available
* [Changed] `DummyPlugin` class is now final
* [Changed] Remove `.git` dirs from `vendor/` when deploying
* [Changed] Various small improvements and changes...
* [Fixed] `PicoDeprecated`: Sanitize `content_dir` and `base_url` options when
          reading `config.php` in Picos root dir
* [Fixed] Replace `urldecode()` (deprecated RFC 1738) with `rawurldecode()`
          (RFC 3986) in `Page::evaluateRequestUrl()`
* [Fixed] #272: Encode URLs using `rawurlencode()` in `Pico::getPageUrl()`
* [Fixed] #274: Prevent double slashes in `base_url`
* [Fixed] #285: Make `index.php` work when installed as a composer dependency
* [Fixed] #291: Force `Pico::$requestUrl` to have no leading/trailing slash
```
2015-11-30 18:52:11 +01:00
Daniel Rudolf
268c41e7fa Update CHANGELOG.md 2015-11-30 18:49:05 +01:00
Daniel Rudolf
b47a806efd Merge pull request #296 from picocms/enhancement/refactor-phpdoc-deployment
Refactor phpDoc auto deployment
2015-11-30 18:33:19 +01:00
Daniel Rudolf
67bbae184b phpDocs auto deployment: Fix output formatting 2015-11-30 17:23:25 +01:00
Daniel Rudolf
47d2685c6d phpDocs auto deployment: Disable cache for releases 2015-11-30 16:54:45 +01:00
Daniel Rudolf
c88a26beff phpDocs auto deployment: Set default push strategy to simple 2015-11-30 15:26:09 +01:00
Daniel Rudolf
fe10bca56b phpDocs auto deployment: Fix output formatting 2015-11-30 15:24:00 +01:00
Daniel Rudolf
f5c721aba1 phpDocs auto deployment: Fix paths 2015-11-30 15:11:28 +01:00
Daniel Rudolf
76f243f925 Refactor phpDoc deployment
This should prevent empty phpDoc updates like 55b4a2b
2015-11-30 14:53:10 +01:00
Daniel Rudolf
771bdacf71 Inline docs: Fix navigation loop example in Blogging section 2015-11-30 03:24:37 +01:00
Daniel Rudolf
9a7e53328d Merge pull request #273 from picocms/feature/PicoTwigExtension
Add map and sort_by Twig filters
2015-11-30 03:11:13 +01:00
theshka
3c10c8ac0b fix typo 2015-11-29 19:59:34 -06:00
theshka
02ac0c276b Merge branch 'feature/PicoTwigExtension' of https://github.com/picocms/Pico into feature/PicoTwigExtension 2015-11-29 19:53:05 -06:00
Daniel Rudolf
3d4c4e1669 Fix _build/generate-phpdoc.sh 2015-11-30 02:02:53 +01:00
Tyler Heshka
cf71f36651 Merge pull request #295 from picocms/enhancement/isolate-build
Isolate build-related files from source
2015-11-29 18:56:36 -06:00
Daniel Rudolf
d19ab3814c Merge branch 'enhancement/isolate-build' of github.com:picocms/Pico into enhancement/isolate-build
Conflicts:
	.phpdoc.xml
2015-11-30 00:54:21 +01:00
Daniel Rudolf
4be51a7bee Refactor phpDoc generation 2015-11-30 00:52:19 +01:00
theshka
49e5e44b4a update .phpdoc.xml 2015-11-29 16:28:33 -06:00
theshka
ff02f34e23 Merge branch 'enhancement/isolate-build' of https://github.com/picocms/Pico into enhancement/isolate-build 2015-11-29 15:57:21 -06:00
theshka
1ea81d4b41 add .phpdoc.xml and move ignore list 2015-11-29 15:55:25 -06:00
Daniel Rudolf
4f90296295 Update .phpcs.xml: Check $PWD by default 2015-11-29 22:55:05 +01:00
Daniel Rudolf
272a13f0f2 Update CONTRIBUTING.md: Use Pico's .phpcs.xml instead of PSR2 standard for PHP_CodeSniffer 2015-11-29 22:54:18 +01:00
Daniel Rudolf
24b58175a4 Inline docs: Update Blogging section to use "sort_by" filter 2015-11-29 22:28:18 +01:00
Daniel Rudolf
be46e19677 Merge branch 'master' into feature/PicoTwigExtension
Conflicts:
	CHANGELOG.md
2015-11-29 22:19:57 +01:00
Daniel Rudolf
2ce422d907 PicoTwigExtension: Refactor error handling 2015-11-29 22:18:41 +01:00
Daniel Rudolf
9aaab5de1a Refactor Pico::parseFileMeta() 2015-11-29 21:58:30 +01:00
theshka
1dc410425f Isolate build-related files from source
* [Changed] rename `phpcs.xml` -> `.phpcs.xml`
* [Changed] rename `build/` dir -> `_build/`
* [Changed] update paths in `.gitignore`
* [Changed] update paths in `.travis.yml`
* [Changed] update paths in `.sh` scripts
2015-11-29 14:55:55 -06:00
Daniel Rudolf
5ea94d06e6 Catch YAML parse errors 2015-11-29 20:58:41 +01:00
Daniel Rudolf
6cb378e83f Inline docs: Add link to YAML wikipedia article
Official resources about YAML are ... - impossible to understand for a ordinary user.
2015-11-29 20:26:43 +01:00
theshka
9b31a54adc Merge branch 'enhancement/build-release' 2015-11-29 11:20:54 -06:00
theshka
bef150221b CONTRIBUTING.md: Final tocuhes on Build & Release section. 2015-11-29 11:11:26 -06:00
Daniel Rudolf
372979e45b CONTRIBUTING.md: Update build & release process 2015-11-29 17:18:46 +01:00
Daniel Rudolf
b18464adba CONTRIBUTING.md: Convert Issues template to continuous text 2015-11-29 17:00:05 +01:00
Daniel Rudolf
2d9b5aa1a2 Fix operators 2015-11-29 16:39:03 +01:00
Daniel Rudolf
698a249d45 Force Pico::$requestUrl to have no leading/trailing slash
Fixes #291
2015-11-27 22:52:45 +01:00
Daniel Rudolf
2eed14103a Add @codingStandardsIgnoreFile to index.php.dist
The comments of the "instance Pico" section violate PSR-2, but we want to keep them anyway
2015-11-27 20:36:40 +01:00
Daniel Rudolf
e088f6c6fa Update phpcs.xml 2015-11-27 20:31:17 +01:00
Daniel Rudolf
b50023c8ad Merge branch 'enhancement/build-release' of github.com:picocms/Pico into enhancement/build-release 2015-11-27 20:27:26 +01:00
Daniel Rudolf
2535df7cfe Add index.php.dist
See https://github.com/picocms/Pico/issues/285#issuecomment-160130798
2015-11-27 20:24:29 +01:00
Daniel Rudolf
98022a5a8f Update CHANGELOG.md 2015-11-27 20:21:13 +01:00
Daniel Rudolf
2761f8b751 Refactor Pico::isUrlRewritingEnabled() 2015-11-27 20:13:17 +01:00
Daniel Rudolf
abce8b84b8 Merge branch 'master' into enhancement/build-release
Conflicts:
	index.php
2015-11-27 19:52:17 +01:00
Daniel Rudolf
cb15ea7493 Amend #286 2015-11-27 19:49:53 +01:00
Daniel Rudolf
86d1f713f2 Move PHP version check to index.php 2015-11-27 19:45:21 +01:00
Daniel Rudolf
81138ce06a Merge branch 'master' of github.com:picocms/Pico 2015-11-27 19:43:47 +01:00
Daniel Rudolf
f97cd83cc8 Merge pull request #286 from dmelo/composer-compat
change Pico's default `index.php` to be compatible with `composer require picocms/pico`
2015-11-27 19:43:10 +01:00
Daniel Rudolf
31acaffa67 Add PHP_CodeSniffer 2015-11-27 19:40:26 +01:00
Daniel Rudolf
e14c007789 Default theme: Replace tabs with 4-space-indentation 2015-11-27 19:32:12 +01:00
Daniel Rudolf
913cf3816f Plugins: Improve onPagesLoaded() code styling 2015-11-27 19:31:22 +01:00
Daniel Rudolf
364b9066d9 PicoDeprecated: Use $GLOBALS superglobal instead of global keyword 2015-11-27 19:30:25 +01:00
Daniel Rudolf
81821e7811 Improve Pico::getBaseUrl() code styling 2015-11-27 19:28:48 +01:00
theshka
1fae7ab3df * [New] added PHP_VERSION check to Pico::run() 2015-11-27 12:27:45 -06:00
theshka
917cd6caf3 Consolidate Issue Template 2015-11-27 10:36:44 -06:00
theshka
0dcb49d8ac Consolidate Build & Release section. 2015-11-27 10:31:17 -06:00
Diogo Oliveira de Melo
70d813eafe change the way to call autoload.php.
- As suggested by @theshka, this code first verify if Pico is being used
as local composer install, then verify if it is being used as a composer
library.
2015-11-27 02:16:06 -02:00
Daniel Rudolf
54305c4d33 phpDocs auto deployment: Remove pull requests support
We can deploy phpDocs in safe environments only, but "safe environment" is equivalent to "pull a local branch", therefore we can simply use that local branch to deploy the phpDocs. There's no need for a explicit pull request support.
2015-11-26 04:06:34 +01:00
Daniel Rudolf
8005efdbbb phpDocs auto deployment: Remove latest commit check for pull requests
See https://developer.github.com/v3/pulls/#get-a-single-pull-request
> Each time the pull request receives new commits, GitHub creates a merge
> commit to *test* whether the pull request can be automatically merged into
> the base branch. (This *test* commit is not added to the base branch or the
> head branch.) The  attribute holds the SHA of the *test*
> merge commit; however, this attribute is deprecated and is scheduled for
> removal in the next version of the API.

 holds the SHA of the  merge commit and not of the
latest commit of the head branch, therefore the comparison fails. We could
theoretically compare it against this attribute, but as of its deprecation,
this is a pretty bad idea. Thus we remove the latest commit check for pull
requests.
2015-11-26 02:38:29 +01:00
Daniel Rudolf
45dcf32fa7 phpDocs auto deployment: Support pull requests in a safe environment 2015-11-26 02:15:34 +01:00
Daniel Rudolf
6e0b2aab34 phpDocs auto deployment: Disable for pull requests with a safe environment
Pull requests with a safe environment are primarly local branches
2015-11-26 01:35:35 +01:00
Daniel Rudolf
5af160c31d phpDocs auto deployment: Use $GITHUB_OAUTH_TOKEN to determine latest commit 2015-11-26 01:13:37 +01:00
Daniel Rudolf
869a697977 Merge branch 'master' into enhancement/build-release
Conflicts:
	.travis.yml
2015-11-26 00:38:30 +01:00
Daniel Rudolf
17dbc4cf18 phpDocs auto deployment: Cleanup 2015-11-26 00:29:14 +01:00
Daniel Rudolf
2306010ba7 phpDocs auto deployment: Fix phpDocs generation
phpDocumentor acts very strange when relative paths are involved...
2015-11-25 23:53:58 +01:00
Daniel Rudolf
3ac53d2b4c phpDocs auto deployment: Improve title of class docs for branches 2015-11-25 23:44:11 +01:00
Daniel Rudolf
38d2dd2e20 Travis: Remove .git dirs from vendor/ dir when deploying
See https://github.com/picocms/Pico/issues/289#issuecomment-159722672 - thanks to @joshas for spotting
2015-11-25 23:38:22 +01:00
Daniel Rudolf
137b2ba3a6 phpDocs auto deployment: Fix deployment of branches with slashes 2015-11-25 23:35:42 +01:00
Daniel Rudolf
236ae43dab phpDocs auto deployment: Fix deployment of branches 2015-11-25 23:09:15 +01:00
Daniel Rudolf
c198333de7 Improve phpDocs auto-generation 2015-11-25 22:55:21 +01:00
Daniel Rudolf
728873c5a4 build/deploy-phpdoc.sh: Fix credentials 2015-11-25 22:26:51 +01:00
Daniel Rudolf
3c68095075 Improve phpDocs auto-generation 2015-11-25 22:04:16 +01:00
Daniel Rudolf
3852585ba0 Improve phpDocs auto-generation 2015-11-25 21:55:28 +01:00
Daniel Rudolf
9a46033141 Improve phpDocs auto-generation 2015-11-25 21:36:56 +01:00
Daniel Rudolf
32120e5bbc Fix build/generate-phpdoc.sh permissions 2015-11-25 21:02:43 +01:00
Daniel Rudolf
e4165d35b1 Fix .travis.yml 2015-11-25 20:59:29 +01:00
Daniel Rudolf
5862825265 Travis: Deploy phpDocs on PHP 5.3 only and allow multiple branches 2015-11-25 20:56:13 +01:00
Daniel Rudolf
c9387610f3 Auto-generate phpDoc when committing to master 2015-11-25 20:39:49 +01:00
Daniel Rudolf
1f16be05e3 Merge branch 'master' into enhancement/build-release 2015-11-25 20:38:44 +01:00
Daniel Rudolf
4ddde6b9fb Travis: Deploy on every repo, forks usually don't setup Travis 2015-11-25 20:38:27 +01:00
Daniel Rudolf
d503cea954 Travis: Don't test vendor PHP files 2015-11-25 20:37:45 +01:00
Daniel Rudolf
b198ad48c6 Travis: Allow PHP nightly builds to fail 2015-11-25 20:04:46 +01:00
Daniel Rudolf
18fc928797 Merge branch 'master' into enhancement/build-release
Conflicts:
	.travis.yml
2015-11-25 18:03:03 +01:00
Daniel Rudolf
20387e0bf9 Make DummyPlugin class final
Plugin developers MUST NOT extend from DummyPlugin, they SHOULD extend from AbstractPicoPlugin
2015-11-25 04:10:22 +01:00
Daniel Rudolf
876a500ecf Improve .gitignore 2015-11-25 04:07:57 +01:00
Daniel Rudolf
840d41bca5 Improve type hinting 2015-11-25 04:07:46 +01:00
Daniel Rudolf
2982f5deb9 Optimize composer autoloader before deploying
This converts PSR-0/PSR-4 autoloading to classmap to get a faster autoloader (up to 20% performance increase)
2015-11-24 19:49:16 +01:00
Diogo Oliveira de Melo
85442266b5 update CHANGELOG 2015-11-23 20:29:33 -02:00
Diogo Oliveira de Melo
9e752c1d29 It works when Pico is installed as a dependency 2015-11-23 20:11:42 -02:00
theshka
80049ed966 update build & release section for auto-docs 2015-11-23 15:51:12 -06:00
Daniel Rudolf
9712ae2a97 Fix permissions of build/deploy-phpdoc.sh 2015-11-23 21:52:23 +01:00
Daniel Rudolf
7f4ad75245 Refactor phpDoc auto-deployment 2015-11-23 21:46:36 +01:00
Daniel Rudolf
bd24d518f2 Update .gitignore 2015-11-23 21:33:57 +01:00
theshka
e79388118c Merge branch 'feature/auto-docs' into enhancement/build-release 2015-11-23 13:35:23 -06:00
theshka
c3b908939f update deploy-phpdoc.sh for auto docs 2015-11-23 13:26:31 -06:00
theshka
04f7140347 update .travis.yml for auto-docs 2015-11-23 13:19:47 -06:00
theshka
edbf9f1747 Implement @PhrozenByte 's suggestions.
* [Changed] require phpDocumentor version ^2.8 constraint
2015-11-23 12:27:15 -06:00
theshka
bf2a9622db Update deploy script
* [Changed] move everything inside /build/ directory
* [Changed] use absolute file paths in script
* [Changed] copy docs to both the release number and master dirs
Implement @PhrozenByte 's suggestions.
* [Changed] use `$GITHUB_OAUTH_TOKEN` instead of `$GITHUB_TOKEN`
2015-11-23 12:27:15 -06:00
theshka
e0c6383406 rename script 2015-11-23 12:27:15 -06:00
theshka
7f910e913f update auto-docs files
* [Changed] move everything inside /build/ directory
Implement @PhrozenByte 's suggestions.
* [Changed] don't change directories, pass the paths
* [Removed] unnecessary `composer install`, travis-ci runs this already
* [Removed] unnecessary `composer self-update` command
* [Removed] unnecessary php version check on script
2015-11-23 12:26:25 -06:00
Daniel Rudolf
c34afad4af Fix typo 2015-11-22 14:08:35 +01:00
Daniel Rudolf
60c627c214 Update composer.json: Use latest MINOR versions of Twig/Parsedown/YAML 2015-11-22 14:08:06 +01:00
Daniel Rudolf
d59dba0b5f Update README.md: Add update instructions for composer users 2015-11-21 22:13:54 +01:00
theshka
f062640bb1 test auto docs 2015-11-20 23:28:09 -06:00
theshka
f6d5e8c7f4 can phpDoc be automatic? 2015-11-20 20:30:56 -06:00
Daniel Rudolf
d252df4b98 Throw RuntimeException on invalid content dirs 2015-11-19 04:48:22 +01:00
theshka
31d611a507 add template for new issues 2015-11-18 18:55:26 -06:00
theshka
8093758b3e Improve headings and formatting 2015-11-18 15:26:39 -06:00
theshka
ba766ea65c Update Build & Release section 2015-11-18 13:39:48 -06:00
Daniel Rudolf
3e4bcd4289 Update CONTRIBUTING.md: Fix typo 2015-11-18 00:41:38 +01:00
Daniel Rudolf
3b737aac1a Update README.md: Update "edit inline docs" link 2015-11-18 00:34:59 +01:00
Daniel Rudolf
c0d30d20f8 Follow-up to c72ea0e
Don't use Pico::getAbsolutePath() for $config['content_dir'], just make sure the trailing slash exists. The config.php in Picos root dir should be interpreted exactly like in Pico 0.9 (the option didn't exist in Pico 0.8), thus the path isn't necessarily relative to Picos root dir
2015-11-14 16:50:32 +01:00
Daniel Rudolf
71076e8eba Update CHANGELOG.md 2015-11-14 00:27:49 +01:00
Daniel Rudolf
e0c1e068fb Default theme: Improve table styling 2015-11-14 00:26:45 +01:00
Daniel Rudolf
636f27ae2f Add asset handling recommendations to inline user docs
Thanks @smcdougall for giving the hint about this
2015-11-14 00:26:26 +01:00
Daniel Rudolf
aa68cfaa45 Update CHANGELOG.md 2015-11-13 22:34:47 +01:00
Daniel Rudolf
f5006c036a Prevent double slashes in base_url when installed to document root
Fixes #274
2015-11-13 22:29:58 +01:00
Daniel Rudolf
c72ea0ecec PicoDeprecated: Sanitize content_dir and base_url options when reading config.php in Picos root dir 2015-11-13 19:10:30 +01:00
Daniel Rudolf
c17f18f8cf Update inline user docs to reflect PicoTwigExtension 2015-11-13 17:08:12 +01:00
Daniel Rudolf
10de8efa11 Move markdown filter to PicoTwigExtension 2015-11-13 16:49:53 +01:00
Daniel Rudolf
19cbb41222 Update CHANGELOG.md 2015-11-13 16:48:20 +01:00
Daniel Rudolf
f19adc64b9 Add PicoTwigExtension with map and sort_by filters 2015-11-13 16:48:01 +01:00
Daniel Rudolf
282b7ce16c Update CHANGELOG.md 2015-11-12 20:36:05 +01:00
Daniel Rudolf
78ceabe878 Various improvements
- Reuse ParsedownExtra object
- Add new markdown Twig filter
- Improve class docs in general
- Document plugin number prefix usage
2015-11-12 15:34:56 +01:00
Daniel Rudolf
8ff18c9366 Update CHANGELOG.md 2015-11-08 14:35:28 +01:00
Daniel Rudolf
f9e9642c22 Fix Pico::getPageUrl()
With enabled URL rewriting we must call rawurlencode() on the file path parts rather the whole path
2015-11-08 14:01:35 +01:00
Daniel Rudolf
6638c2b0ee CONTRIBUTING.md: Clarify the suggested branching concept 2015-11-08 03:54:58 +01:00
Daniel Rudolf
2ca711ad59 Add missing rawurlencode() to Pico::getPageUrl()
Replace urldecode() in Pico::evaluateRequestUrl() with rawurldecode()
See #272 for details, thanks @smcdougall for spotting!
2015-11-08 03:12:18 +01:00
Daniel Rudolf
e144cce6b1 Update .gitignore 2015-11-06 21:19:17 +01:00
Daniel Rudolf
7b4ad7f234 Version 1.0.0-beta.1
**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
```
2015-11-06 19:13:17 +01:00
Daniel Rudolf
2d6859af60 Update .travis.yml 2015-11-06 19:13:01 +01:00
Daniel Rudolf
e5b0ec6d7b Merge pull request #252 from PhrozenByte/pico1.0
Pico 1.0
2015-11-06 19:06:39 +01:00
Daniel Rudolf
cd1dc07d81 Sync docs 2015-11-06 17:50:22 +01:00
theshka
82cbe37009 fix typos 2015-11-06 10:15:28 -06:00
Daniel Rudolf
e3e0300025 Fix typo 2015-11-06 02:02:04 +01:00
Daniel Rudolf
cd7cd374bb Add content filter to get the parsed contents of a page (lazy loading) 2015-11-06 01:08:31 +01:00
Daniel Rudolf
b5d54d05c4 Update .travis.yml: Name release archives "pico-release-$TRAVIS_TAG.tar.gz"
Should make it easier for a ordinary user to distinct source code and release 😃
2015-11-05 21:58:45 +01:00
Daniel Rudolf
19f708e572 Sync documentation 2015-11-04 22:44:19 +01:00
Daniel Rudolf
af8de56512 Fix typos 2015-11-04 19:50:44 +01:00
Daniel Rudolf
2a43b21bae Enable PicoDeprecated if no plugins are loaded 2015-11-04 19:44:20 +01:00
Daniel Rudolf
ccac8dd4d3 Force trailing slash of $config['base_url'] and force existance of $config['timezone'] 2015-11-04 19:43:54 +01:00
Daniel Rudolf
e3a6116c79 Sync documentation 2015-11-04 19:43:06 +01:00
Daniel Rudolf
90128f4946 Fix possible foreach on null errors 2015-11-03 23:49:34 +01:00
Daniel Rudolf
82e0ca5216 Small changes
- Use Travis build status
- Update version number in config template
2015-11-03 17:35:33 +01:00
Daniel Rudolf
8164038ff7 Use Markdown for CHANGELOG.md 2015-11-03 17:34:41 +01:00
Daniel Rudolf
48264fce3d Move license.txt and changelog.txt 2015-11-03 17:32:58 +01:00
Daniel Rudolf
365333c62e Update content-sample/index.md 2015-11-03 16:35:27 +01:00
Daniel Rudolf
ffc59362be README.md: Add Getting Help section 2015-11-03 15:50:39 +01:00
Daniel Rudolf
2ab361106c Update content-sample/index.md 2015-11-03 00:41:10 +01:00
Daniel Rudolf
d65eb553ad Update README.md 2015-11-03 00:09:31 +01:00
Daniel Rudolf
641a5d1a02 Merge branch 'pico1.0' of github.com:PhrozenByte/Pico into pico1.0 2015-11-02 23:44:19 +01:00
Daniel Rudolf
0e0eb567fa Update CONTRIBUTING.md
Add "Keep documentation in sync" section
2015-11-02 23:43:40 +01:00
Daniel Rudolf
92adb27da5 Update README.md
- New Contributing section
- Various small improvements
2015-11-02 22:52:51 +01:00
Daniel Rudolf
8db3bc5a18 Update changelog.txt to reflect ebe007b 2015-11-02 21:52:08 +01:00
Daniel Rudolf
a1331e7bd7 Update inline docs to reflect ebe007b 2015-11-02 20:00:48 +01:00
Daniel Rudolf
ebe007bd78 Guess content directory
As pointed out by @Lomanic (see https://github.com/picocms/Pico/pull/260#issuecomment-153091890; thank you btw\!) we actually have to explain users how to change the content directory. This runs contrary to our "stupidly simple" claim. So Pico now simply uses the `content` directory when it exists...
2015-11-02 19:48:58 +01:00
Daniel Rudolf
2597e0dd91 Move upgrade instructions from inline docs to README.md in a more generic form 2015-11-02 19:14:07 +01:00
Daniel Rudolf
85d7c510f9 Update CONTRIBUTING.md 2015-11-02 03:16:37 +01:00
Daniel Rudolf
8da62f4aad PicoDeprecated: Making $config globally accessible again
This was dropped without a replacement with Pico 0.9. I checked all changes since Pico 0.8 manually, as far as I can tell there should be no more surprises regarding BC... Thanks @Lomanic for rubbing our nose in the fact that we should check this! I also added the missing changes of Pico 0.9 to changelog.txt
2015-10-31 01:03:24 +01:00
Daniel Rudolf
9a702415fb Remove return $config in config/config.php
I always thought that doing this is pretty unusual... But now it simply breaks BC - please refer to @Lomanic's [comment](https://github.com/picocms/Pico/pull/260#issuecomment-152610857). Using a return statement has no advantages, but increases the probability that something goes wrong (e.g. a clueless user removes the return statement). It was introduced with 23b90e2, but we never released it ([v0.9.1](4cb2b24fae/lib/pico.php (L188-L189))). Removing the return statement shouldn't cause any problems even for users which installed Pico in the meantime. As a result we don't break BC and moreover remove a prior BC break 😃
2015-10-31 00:32:08 +01:00
Daniel Rudolf
afb55b9cb6 Improve class docs 2015-10-29 18:13:35 +01:00
Daniel Rudolf
e6681ea903 Improve class docs
Also add some ToDos to inline docs
2015-10-29 18:07:45 +01:00
Daniel Rudolf
7a69fdf66d Update CONTRIBUTING.md 2015-10-29 17:16:57 +01:00
Daniel Rudolf
d29e2c1f95 Add CONTRIBUTING.md
The file mostly contains adapted contents @theska wrote for our website and the great CONTRIBUTING.md of phpDocumentor (https://github.com/phpDocumentor/phpDocumentor2/blob/v2.8.5/CONTRIBUTING.md)
2015-10-29 16:57:25 +01:00
Daniel Rudolf
54ce5b9699 Various small improvements
- Improve class docs for phpDocumentor
- Add missing onPagesLoading() event to DummyPlugin
- Add some TODOs to the UPGRADE section of the docs
2015-10-29 02:55:30 +01:00
Daniel Rudolf
f1fc4c979e Revert commit a068850
According to travis-ci/travis-ci#2111 and some own testing, it isn't possible to combine branch whitelists with tag-based auto deployment. Unfortunately it is necessary to whitelist the gh-pages branch, because Travis implicitly blacklists it.
2015-10-29 01:19:43 +01:00
Daniel Rudolf
638638f5a4 Add UPGRADE section to docs
This is still work in progress
2015-10-29 00:57:54 +01:00
Daniel Rudolf
38081b3d52 Sync docs with website 2015-10-29 00:54:01 +01:00
Daniel Rudolf
a068850578 Update .travis.yml
Let Travis build branches master and gh-pages only
2015-10-29 00:37:59 +01:00
Daniel Rudolf
43f9590d5e Update .travis.yml
Use Travis container-based infrastructure
2015-10-28 17:34:10 +01:00
Daniel Rudolf
360e7ab91f Update .travis.yml
Use $TRAVIS_TAG for the "binary" filename
2015-10-28 17:26:43 +01:00
Daniel Rudolf
a068a1f9d7 Update changelog.txt
- Add security section
- Add Travis CI
2015-10-28 15:11:34 +01:00
Daniel Rudolf
efcbbb8ce0 Update .travis.yml
Build on picocms/Pico only
2015-10-28 14:38:02 +01:00
Daniel Rudolf
d3a1308556 Update .travis.yml
Just adding some features inspired by other projects using Travis, e.g. a simple PHP syntax checker with various PHP versions. A short peak into @dav-m85 link leads me to think that running composer and creating the archive should be done with before_deploy rather than script.
2015-10-28 12:53:56 +01:00
David "Paztek" Moreau
3e0161b51a Create .travis.yml 2015-10-28 12:37:46 +01:00
Daniel Rudolf
647a7b5bb7 Trap empty $requestFileParts 2015-10-28 01:41:26 +01:00
Daniel Rudolf
9e2604af85 Prevent content_dir breakouts using malicious request URLs
It's appalling that nobody (including me!) thought about that!
2015-10-28 01:36:28 +01:00
Daniel Rudolf
de6b3a7c28 Fix Markdown %meta.*% replacement
Don't even try to use arrays here...
2015-10-28 01:08:45 +01:00
Daniel Rudolf
a654b1585b phpDocumentor 2.8.5 currently doesn't support the Generic notations
This will likely be implemented as soon as the proposed PSR-5: PHPDoc is accepted
2015-10-27 01:48:58 +01:00
Daniel Rudolf
92af554d14 Improve inline code comments; preparing use of phpDocumentor 2015-10-27 01:39:28 +01:00
Daniel Rudolf
4171f9a031 Move URL Rewriting to Config section 2015-10-10 00:11:56 +02:00
Daniel Rudolf
9cdd34edcc Change content order, add Customization section 2015-10-10 00:08:38 +02:00
Daniel Rudolf
15515ff3fd Fix typo/formatting 2015-10-09 20:51:07 +02:00
theshka
aec024a793 fix spelling 2015-10-09 20:41:00 +02:00
theshka
132399f305 add comments/in-line docs 2015-10-09 20:41:00 +02:00
theshka
8380b54142 fix spelling 2015-10-09 20:41:00 +02:00
theshka
01122f2901 fix spelling 2015-10-09 20:41:00 +02:00
theshka
fe83d1fa7f fix spelling 2015-10-09 20:41:00 +02:00
theshka
3336fb717e fix spelling 2015-10-09 20:40:01 +02:00
Daniel Rudolf
b46ed0535c Let users know about Twigs link filter 2015-10-09 14:27:49 +02:00
Daniel Rudolf
40dbd0ee37 Update Picos inline user docs
Adding a Blogging and URL Rewriting section, splitting the Plugins section into "for users" and "for devs", extend all sections and fix some typos
2015-10-08 21:01:30 +02:00
Daniel Rudolf
7c5f371b9a Use PSR-0 autoload
Makes no big difference... Using PSR-4 breaks BC.
2015-10-08 14:19:59 +02:00
Daniel Rudolf
b09433a37b Allow multiple calls to Pico::setConfig() 2015-10-06 20:38:34 +02:00
Daniel Rudolf
04a1c603d0 Update changelog.txt for 1419cf1 2015-10-06 20:33:31 +02:00
Daniel Rudolf
1419cf1636 Add Pico::setConfig() method
Thanks @dav-m85
2015-10-06 20:23:28 +02:00
Daniel Rudolf
7aa199d77a Update changelog.txt for 7537159 2015-10-05 01:58:11 +02:00
Daniel Rudolf
7537159868 Remove the need to register headers during onMetaHeaders()
Why? I'm currently writing the user docs and I really have no idea how to explain this whole process in a non-technical way... It is very likely that a normal user wants to use custom tags and it would be absurd to tell him,that he should learn a programming language to do so. On the other hand, providing a copy-and-paste template makes the whole idea of explicitly registering headers worthless. The only reasonable solution is to remove the need to register headers.

Anyway, I think @PontusHorn is right to say that registering headers makes the whole system more predictable. So plugin developers are still instructed to register their meta headers during . We actually can't check and ensure this, but that's imho the best solution.
2015-10-05 01:50:55 +02:00
Daniel Rudolf
1cbf48af79 Split PicoDeprecated::onConfigLoaded() into multiple methods 2015-10-04 23:25:32 +02:00
Daniel Rudolf
46ef63186a Support $config['<plugin name>']['enabled'] option
... as a alternative to $config['<plugin name>.enabled']; Thanks @theshka for giving this hint
2015-10-04 22:52:08 +02:00
Daniel Rudolf
9d518fd722 Move sorting of $pages from Pico::getPages() to Pico::sortPages() 2015-10-04 22:39:38 +02:00
Daniel Rudolf
4f1e8667c3 Cast AbstractPicoPlugin::$dependsOn to array
Plugin devs could come up with the idea of setting AbstractPicoPlugin::$dependsOn to a string (single dependency) or null (no dependencies)
2015-10-04 22:30:35 +02:00
Daniel Rudolf
79e2dacdb2 Fix method docs typo 2015-10-04 22:08:04 +02:00
Daniel Rudolf
27d694697f Fix code formatting 2015-10-04 21:34:37 +02:00
Daniel Rudolf
006afa5774 Update changelog.txt
The changelog only provides basic information about the enormous changes introduced with Pico 1.0-beta. Please refer to the (not yet written... 😄) UPGRADE section of the docs for details.
2015-10-04 19:57:20 +02:00
Daniel Rudolf
2e15e112f7 Define deprecated constants before evaluating the config.php in Picos root dir
This prevents E_NOTICEs when using e.g. ROOT_DIR in a old config.php, so upgrading users are usually not bothered with this BC break
2015-10-04 18:50:16 +02:00
Daniel Rudolf
ef1a9e0c33 Improve README.md 2015-10-04 16:59:38 +02:00
Daniel Rudolf
9aa62b4b44 Improve method docs of Pico::load404Content() 2015-10-04 16:57:57 +02:00
Daniel Rudolf
77f939028c Support per-directory 404.md files 2015-10-04 15:24:38 +02:00
Daniel Rudolf
3f7b0998c6 Declare undefined $plugins variable
Thanks @Lomanic
2015-10-04 14:47:54 +02:00
Daniel Rudolf
3a4721a20c SCANDIR_SORT_* constants are available since PHP 5.4
Thanks @Lomanic
2015-10-04 14:15:11 +02:00
Daniel Rudolf
ab8994593f Improve README.md formatting; Run PHP web server on localhost only 2015-10-03 18:38:16 +02:00
Daniel Rudolf
fa024ce849 Fix README.md formatting 2015-10-03 18:35:17 +02:00
Daniel Rudolf
7698f18df0 Merge branch 'master' into pico1.0
Merging @theshka's README.md updates...

Conflicts:
	README.md
2015-10-03 18:28:48 +02:00
Daniel Rudolf
00f76d1083 Update README.md 2015-10-03 17:36:43 +02:00
theshka
a8e68eaac8 Update README 2015-10-02 17:02:27 -06:00
Daniel Rudolf
9be23de897 Require PHP >= 5.3.6 until erusev/parsedown-extra#75 is solved 2015-10-02 16:53:29 +02:00
Daniel Rudolf
241a52907e Update inline code comments 2015-10-01 22:52:10 +02:00
Daniel Rudolf
fbb744dd43 Deny access to config, content, content-sample, lib and vendor dirs
Send 404 Not Found instead of 403 Forbidden
2015-10-01 22:42:23 +02:00
Daniel Rudolf
012dffa856 Fix #257 2015-10-01 21:59:03 +02:00
Daniel Rudolf
fd64e4fa5e Add a exception to alpha sorting: List index files first
This guarantees that e.g. sub/index.md is listed before sub/foo.md
2015-10-01 21:54:30 +02:00
Daniel Rudolf
45815e2c6d Don't read file contents of inaccessible pages 2015-10-01 17:22:14 +02:00
Daniel Rudolf
95db5ba1a1 Drop inaccessible pages
e.g. drop sub.md if sub/index.md exists
2015-10-01 15:59:47 +02:00
Daniel Rudolf
cdef7a6324 Explicitly treat relative paths to be relative to Picos root dir
This tempers the BC break, we can now recommend to simply remove the ROOT_DIR part
2015-10-01 15:14:45 +02:00
Daniel Rudolf
fc7632b0ac Overhaul init of Pico
This may break BC if you're using one of the now deprecated constants (e.g. ROOT_DIR)
2015-10-01 15:05:50 +02:00
Daniel Rudolf
5e77d862bf Remove twig cache dir 2015-09-29 00:42:04 +02:00
Daniel Rudolf
8d88863805 Fix whitespace 2015-09-28 17:42:47 +02:00
Daniel Rudolf
13a50c7f2f Don't change $pageData['id'], add ~dup1 to the array key only 2015-09-28 17:25:10 +02:00
Daniel Rudolf
a5755b0d39 Fix deprecated get_page_data and get_pages events 2015-09-28 17:13:26 +02:00
Daniel Rudolf
a7fd853f8f Add striptags filter to description meta header
Thanks @PontusHorn
2015-09-17 23:44:05 +02:00
Daniel Rudolf
5533b07531 Re-add lost PicoPluginInterface 2015-09-15 13:20:52 +02:00
Daniel Rudolf
f76a0b75be Use v0.7 releases of erusev/parsedown-extra 2015-09-15 13:17:00 +02:00
Daniel Rudolf
70f187fb45 Rename IPicoPlugin to PicoPluginInterface 2015-09-15 13:15:45 +02:00
Daniel Rudolf
4821454ad5 Declare in config/config.php.template to prevent a E_NOTICE 2015-09-14 23:08:02 +02:00
Daniel Rudolf
5731ede297 Allow omitting config/config.php; Fix write context on return value
Thanks @Lomanic for reporting
2015-09-14 23:01:08 +02:00
Daniel Rudolf
71e7da28cc Various fixes
Thanks @PontusHorn for spotting!
2015-09-13 20:46:09 +02:00
Daniel Rudolf
a83b01ef4f Access plugins by class name, not file name
Class name and file name can differ regarding case sensitivity
2015-09-06 14:35:23 +02:00
Daniel Rudolf
533822320e Workaround for webservers omitting QUERY_STRING
Thanks @theshka for spotting
2015-08-30 21:31:47 +02:00
Daniel Rudolf
5eed6d0562 Add missing update of index.twig 2015-08-30 21:29:52 +02:00
Daniel Rudolf
df10d60846 Fixing paths in global.php
That shouldn't be there... Thanks @theshka for spotting
2015-08-30 21:29:20 +02:00
Daniel Rudolf
c44afd396d Update .htaccess 2015-08-28 18:37:36 +02:00
Daniel Rudolf
5438fdb368 Rename index.html of default theme to index.twig; Update template 2015-08-28 18:35:53 +02:00
Daniel Rudolf
39e1d788c5 Update sample content 2015-08-28 18:34:14 +02:00
Daniel Rudolf
144939b978 Update config.php.template 2015-08-28 18:33:27 +02:00
Daniel Rudolf
70316eca87 Add PicoDeprecated, PicoParsePagesContent, PicoExcerpt
These plugins are crucial for backward compatibility
2015-08-28 18:30:19 +02:00
Daniel Rudolf
fd1b94e990 Update composer.json 2015-08-28 18:28:49 +02:00
Daniel Rudolf
b3477906f1 Replace Pico_Plugin with DummyPlugin
DummyPlugin is a template for Pico plugins. You're a plugin developer? This template may be helpful :-)
2015-08-28 18:28:25 +02:00
Daniel Rudolf
07ae26789c Add AbstractPicoPlugin
The plugin magic takes place here...
2015-08-28 18:26:56 +02:00
Daniel Rudolf
43a7540f46 Add IPicoPlugin 2015-08-28 18:25:54 +02:00
Daniel Rudolf
cd145821ba Remove pull request message 2015-08-28 18:24:06 +02:00
Daniel Rudolf
92c307d8be Pico 1.0
I unfortunately messed up my repo so this is just a single commit... :(
2015-08-28 18:22:32 +02:00
Daniel Rudolf
284e0ce7de Move constants to global.php 2015-08-28 18:19:03 +02:00
Daniel Rudolf
c496297c44 Class files should exactly match the class name 2015-08-28 18:13:50 +02:00
Daniel Rudolf
adc356251e Remove index.html
A empty index.html is a solution for nothing...
2015-08-28 18:11:45 +02:00
Tyler Heshka
2fdcacc14b Merge pull request #244 from muja/scandir
Use scandir instead of opendir to ensure alphabetical order.
2015-08-04 11:21:18 -06:00
Tyler Heshka
2d6b0ad45a Merge pull request #246 from PhrozenByte/enhancement/CleanupPaths
Cleanup paths
2015-08-04 11:20:33 -06:00
Daniel Rudolf
f90e3b4472 Update inline doc 2015-08-01 22:38:14 +02:00
Daniel Rudolf
6e8bc85a8b Move config.php.template to config/; Add config/.gitignore 2015-08-01 22:07:14 +02:00
Daniel Rudolf
399b73aa3b Move config.php to config/; Add CONFIG_DIR and VENDOR_DIR constants 2015-08-01 22:03:54 +02:00
Daniel Rudolf
e23e61daad CONTENT_DIR constant isn't functional anymore 2015-08-01 21:55:19 +02:00
Danyel Bayraktar
8d82cde120 Use scandir instead of opendir to ensure alphabetical order. 2015-07-14 13:31:51 +02:00
Tyler Heshka
e942d40187 Merge pull request #237 from theshka/master
Fix call on method of an object just created with new/PHP 5.3.10
2015-06-23 19:10:58 -04:00
theshka
f4cc9727ff Fix call on method of an object just created with new/PHP 5.3.10 compatibility error. 2015-06-23 19:06:53 -04:00
Tyler Heshka
6e50ac5cc8 Merge pull request #234 from kushipl/master
Apply PSR1/PSR2 coding standards.
2015-06-12 13:26:16 -04:00
Wojciech Grzebieniowski
577160b109 Apply PSR1/PSR2 coding standards.
Mostly - use consistent indentation. Currently some methods in Pico
class are indented with space ( get_files() ), some with tabs.
2015-06-10 11:40:26 +02:00
Tyler Heshka
376e551ec4 Merge pull request #233 from kushipl/master
Fixed indent
2015-06-10 03:38:26 -04:00
Wojciech Grzebieniowski
83a3313e53 Fixed indent 2015-06-10 09:10:25 +02:00
Tyler Heshka
820e84e0b9 Merge pull request #232 from kushipl/master
Avoid using global config variable.
2015-06-09 13:06:58 -04:00
Wojciech Grzebieniowski
23b90e2a92 Avoid using global config variable.
Instead config is keeped in Pico::$config private variable, and the
config.php returns $config.
2015-06-09 12:01:11 +02:00
Tyler Heshka
48e5c9e500 Merge pull request #230 from theshka/master
fix date_formatted issue
2015-05-29 13:39:14 -04:00
theshka
28a6b721ce fix date_formatted issue 2015-05-29 13:23:20 -04:00
theshka
eb368d31e1 fix date_formatted issue 2015-05-29 13:22:52 -04:00
theshka
a335eec82a add rewrite base directive 2015-05-25 07:51:18 -04:00
theshka
b11a358505 add comments and RewriteBase directive 2015-05-25 07:41:08 -04:00
theshka
d13e88a0b7 Merge branch 'master' of https://github.com/picocms/Pico 2015-05-20 20:45:54 -04:00
theshka
529e268d5b fix namespace error 2015-05-20 20:44:26 -04:00
theshka
5744a5650a Update config.php.template
explicitly clarify how to override the default settings.
2015-05-20 18:41:32 -04:00
theshka
cfde8b6246 Merge pull request #222 from mangeld/patch-1
Clarify which date format to use
2015-05-03 16:20:13 -04:00
Miguel Ángel Durán González
5a7494d0fd Update config.php.template 2015-05-03 22:15:31 +02:00
Miguel Ángel Durán González
523b7c13d4 Clarify which date format to use 2015-05-03 22:12:36 +02:00
theshka
11d4f7cab3 Merge pull request #220 from theshka/master
fix crazy tabs/spacing
2015-04-30 12:15:25 -04:00
theshka
1cfefb0337 Update config.php.template 2015-04-30 12:13:06 -04:00
theshka
4311625ea2 Update config.php.template 2015-04-30 12:10:46 -04:00
theshka
4cb2b24fae Upgrade to Parsedown-extra 2015-04-29 10:32:57 -04:00
theshka
4c52d104c1 Update README.md 2015-04-29 10:31:02 -04:00
theshka
1d25dcbe9e Merge pull request #218 from theshka/master
Upgrade to Parsedown-extra
2015-04-29 10:28:22 -04:00
theshka
968dc183db Upgrade to Parsedown-extra 2015-04-29 07:09:08 -07:00
theshka
0363f1e3a1 Update README.md 2015-04-28 23:39:25 -04:00
theshka
6de5247ff7 Version 0.9 2015-04-28 22:56:48 -04:00
theshka
4ef01ecc22 cleanup config file 2015-04-28 22:50:41 -04:00
theshka
cc47d7676b Version 0.9 2015-04-28 21:02:44 -04:00
theshka
45b156c1df Update README.md 2015-04-28 20:02:10 -04:00
theshka
3004548793 Update README.md 2015-04-28 20:01:59 -04:00
theshka
dfd2533805 update content to content-sample 2015-04-28 19:03:06 -04:00
theshka
b1dab08b98 Merge pull request #121 from caseycs/composer
remove twig and composer files from sources, now composer install is required...
2015-04-28 18:50:51 -04:00
theshka
483334170f Merge pull request #131 from Frodox/devel-chris
Don't remove all comments while parse content
2015-04-28 18:47:49 -04:00
theshka
b586c9fd5f Merge pull request #137 from sergeweyland/patch-1
Update pico.php
2015-04-28 18:28:18 -04:00
theshka
3a58a4efd6 Change yousite to yoursite 2015-04-28 18:27:59 -04:00
theshka
af3c128ef1 Merge pull request #217 from theshka/master
updated default theme
2015-04-28 18:20:04 -04:00
theshka
e7f1646272 Update default theme; responsive/mobile navigation. 2015-04-25 07:57:29 -07:00
theshka
7513f88e6c Update default theme; responsive/mobile navigation. 2015-04-25 07:51:47 -07:00
picocms
d1dd293a3a Merge pull request #215 from theshka/master
Define missing content directory
2015-04-22 21:14:32 +01:00
theshka
c4af6eef9d Define missing content directory
Using the editor plugin after this file was updated causes errors. Fixed by re-defining the content directory.
2015-04-22 15:04:54 -04:00
picocms
cee070f64e Merge pull request #212 from gregfedorov/master
Easing the life of a noob on get go, making sure nothing errors out.
2015-04-21 22:44:35 +01:00
gregfedorov
01803759b6 Clears php warnings if not configured in php.ini or elsewhere. 2015-04-21 22:48:10 +03:00
gregfedorov
d6df89ad2c Typo causes error on php 5.6.7 2015-04-21 22:46:32 +03:00
picocms
275d975ad8 Merge pull request #162 from cmattoon/patch-1
Update pico.php
2015-04-21 14:32:07 +01:00
picocms
eb494c072c Merge pull request #150 from pschmitt/master
Localize date meta
2015-04-21 14:30:34 +01:00
picocms
80fa39769c Merge pull request #113 from Snip1/master
Update pico.php
2015-04-21 14:28:42 +01:00
picocms
ed18e3194b Merge pull request #206 from kstenschke/patch-1
Update Dependeny: Twig (from 1.12 to 1.18)
2015-04-21 14:26:53 +01:00
picocms
fdd60d8f98 Merge pull request #207 from raptorz/master
fix get_protocol bug.
2015-04-21 14:26:30 +01:00
picocms
78a1db490e Merge pull request #211 from dmelo/master
Improve project organization
2015-04-21 14:25:23 +01:00
Diogo Oliveira de Melo
32b179faff Minor fix 2015-03-18 06:50:54 -03:00
Diogo Oliveira de Melo
19c9696a12 Minor fix 2015-03-18 06:50:13 -03:00
Diogo Oliveira de Melo
9e8b09ae41 Add reference to composer on README 2015-03-18 06:49:27 -03:00
Diogo Oliveira de Melo
e05314b671 minor fix on README 2015-03-18 06:46:41 -03:00
Diogo Oliveira de Melo
547687fed3 Add instructions about Pico on README.
- add install and run instructions on README.
2015-03-18 06:44:22 -03:00
Diogo Oliveira de Melo
196d3cf283 Move content to content-sample
- move the directory content to content-sample
- remove CONTENT_DIR as a define on index.php
- create config value "content_dir" and replace all CONTENT_DIR by it's
correspondent $config['content_dir']
- add the content_dir config on config.php.template
2015-03-18 06:32:00 -03:00
Diogo Oliveira de Melo
0f6a55baa0 Organize files on git.
- add vendor to .gitignore
- remove all vendor files
- move content to content-sample
- move config.php to config.php.template
2015-03-18 06:11:45 -03:00
raptor
8efa97accc fix get_protocol bug.
$_SERVER['HTTPS'] == '' on nginx http
2015-02-21 23:03:05 +08:00
Kay Stenschke
62a03174c9 Update Twig too recent version (from 1.12 to 1.18) 2015-02-20 11:45:17 +01:00
picocms
234c295f69 Update README.md 2014-11-07 11:04:43 +00:00
picocms
b2330ad357 Merge pull request #141 from outrunthewolf/patch-1
Update index.php
2014-05-19 23:51:13 +01:00
Curtis Mattoon
dfb5900835 Update pico.php
Added ignore for tmp file extensions in the get_files() method. When editing plugins with emacs, the get_files() method also grabs the temp files, which leads to a "Can't redclare class [PluginName]" error.

Side note: Would these arrays be better in a property (ala DRY)?
2014-04-22 19:44:37 -04:00
picocms
184b18383f Update index.html
Updated link
2014-03-25 15:11:56 +00:00
picocms
1e0d6ce7b6 Update pico_plugin.php
Updated link
2014-03-25 15:10:51 +00:00
picocms
364a395226 Update pico.php
Updated link
2014-03-25 15:10:19 +00:00
picocms
254d390316 Update index.md 2014-03-25 15:07:58 +00:00
picocms
e2df7a2f0d Update index.md
Updated links
2014-03-25 15:07:35 +00:00
picocms
4434205c91 Update composer.json
Updated locations
2014-03-25 15:05:40 +00:00
picocms
8faa006630 Update README.md
Updated link
2014-03-25 11:23:00 +00:00
Philipp Schmitt
a2331c1b53 UTF-8 encoding for date meta 2014-02-27 13:47:35 +01:00
Philipp Schmitt
553a5ea010 Localize date meta
Use strftime() instead of date() so that non-english websites can
display the date meta in their locale. The locale can be set with
setLocale(LC_ALL, 'YOURLOCALE').
Please note that this changes the date format.
More information: http://php.net/strftime
2014-02-27 12:48:56 +01:00
outrunthewolf
48a1b00f87 Update index.php
Require once on core files, to stop redeclare when composer has already done so.
2014-02-10 09:04:20 +00:00
Gilbert Pellegrom
77d8b39ff9 Merge pull request #134 from schoettl/master
Removed space character between /*
2014-01-27 08:20:47 -08:00
Gilbert Pellegrom
c4991aede2 Merge pull request #126 from iheanyi/master
Fix typos within index.md
2014-01-27 08:19:19 -08:00
sergeweyland
aea6779195 Update pico.php
Fixes an issue wherein the alphabetical sorting of pages did not happen, because array key was not, in fact, the page's filename.
2014-01-17 19:05:10 +01:00
Jakob Schöttl
2869a904c2 Removed space character between /* 2014-01-08 17:38:20 +01:00
Cristian
2194dd1bdb Fix comment 2014-01-05 17:42:41 +04:00
Cristian
0cdb1735bb Merge branch 'master' of https://github.com/gilbitron/Pico into devel-chris 2014-01-05 17:20:30 +04:00
Iheanyi Ekechukwu
44fb99ade3 Fix typos within index.md
direcotry --> directory
2013-12-16 14:09:04 -05:00
Ilia Kondrashov
13b1799c92 remove twig and composer files from sources, now composer install is required to run after clone 2013-11-28 21:55:44 +04:00
Gilbert Pellegrom
dc663cee6d Fix. 2013-11-28 17:13:07 +00:00
Gilbert Pellegrom
fd3ac9405f Merge pull request #120 from caseycs/packagist
improve composer.json so Pico would be able to publish on Packagist and ...
2013-11-28 09:02:52 -08:00
Ilia Kondrashov
c8fa3398c4 improve composer.json so Pico would be able to publish on Packagist and include by adding gilbitron/Pico in composer.json 2013-11-28 20:49:07 +04:00
Snip1
395011c770 Update pico.php
Adding    				'description' => isset($page_meta['description']) ? $page_meta['description'] : '',
 to    $data=array  allows for use of the description meta in place of the excerpt.
2013-11-17 20:36:27 -05:00
Christopher
b136780988 Dont remove all comments from *.md. Only first one (other may be code) 2013-11-01 01:37:20 +04:00
Gilbert Pellegrom
aa59661ff8 v0.8
Added ability to set template in content meta
2013-10-23 10:39:23 +01:00
Gilbert Pellegrom
b2fa0a4abe Changed Pico methods to protected. 2013-10-23 10:23:11 +01:00
Gilbert Pellegrom
022334ff13 Added before_parse_content & after_parse_content hooks. content_parsed
hook is depreciated. Updated get_protocol() method.
2013-10-23 10:19:24 +01:00
Gilbert Pellegrom
9616d902e0 Merge pull request #88 from NeoBlack/feature/moveConfigLoading
[BUGFIX] load config and call hook before the other hooks
2013-10-23 02:07:07 -07:00
Gilbert Pellegrom
d35d87f3ea Merge pull request #91 from beheh/master
Change limit_words to only show ellipsis when word count exceeds max
2013-10-23 02:05:50 -07:00
Benedict Etzel
f665564a79 only append ellipsis in limit_words when string was actually limited 2013-10-21 13:04:02 +02:00
Frank Nägler
3d91c03979 [BUGFIX] load config and call hook before the other hooks
this bugfix is very important, because other hooks like "after_load_content" can not use the config.
2013-10-14 20:26:02 +02:00
Gilbert Pellegrom
6acc979655 Update README.md 2013-10-02 18:23:08 +01:00
Gilbert Pellegrom
45cd4ca5b7 v0.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-09-04 12:10:26 +01:00
Gilbert Pellegrom
69d67b2b71 Merge pull request #61 from cmattoon/master
Modified Pico::get_pages() to ignore Emacs (~) and (#) temp files
2013-09-04 03:33:04 -07:00
Gilbert Pellegrom
014a4df61f Merge pull request #38 from barryjmenard/copy_editing
fix minor grammatical errors
2013-09-04 03:23:53 -07:00
Gilbert Pellegrom
b3c7648e3a Merge pull request #36 from ibr/master
Using composer version of Markdown
2013-09-04 03:23:16 -07:00
Gilbert Pellegrom
41bfe9ab49 Merge pull request #31 from cochrandv/master
Make get_files ignore dotfiles.
2013-09-04 03:21:19 -07:00
Gilbert Pellegrom
c6ff554611 Merge pull request #30 from dstreet/master
Add plugin hooks to customize page meta data
2013-09-04 03:20:24 -07:00
Gilbert Pellegrom
753bac2928 Update README.md 2013-09-03 16:17:35 +01:00
Curtis Mattoon
2e26edaa13 Replaced spaces with tabs... d'oh 2013-08-06 21:51:03 -04:00
Curtis Mattoon
9e9ea4f46d Fix indentation
Conflicts:
	lib/pico.php
2013-08-06 21:45:36 -04:00
Curtis Mattoon
8141ccaeb5 Merge branch 'master' of https://github.com/cmattoon/Pico
Conflicts:
	lib/pico.php
2013-08-06 21:43:49 -04:00
Curtis Mattoon
10eeea80c1 Modified Pico::get_pages() to ignore Emacs (~) and Nano (#) temp files 2013-08-06 21:40:13 -04:00
Curtis Mattoon
9fa454499d Modified Pico::get_pages() to ignore Emacs (~) and Nano (#) temp files 2013-08-06 20:34:36 -04:00
Barry Menard
d30aa79a6f fix minor grammatical errors
Signed-off-by: Barry Menard <barry@projectevolution.com>
2013-07-12 10:53:39 -04:00
Konrad Riedel
145915346c using composer for markdown 2013-07-10 15:12:44 +02:00
David Cochran
adf440a9dd get_files() will ignore dotfiles now 2013-07-07 21:48:04 -05:00
David Street
51b46c89de Minor fixes 2013-07-07 22:31:19 -04:00
David Street
0458c857c1 Added two new plugin hooks allowing better customization of page meta data. 2013-07-07 22:09:39 -04:00
Gilbert Pellegrom
ec37ff4e75 Merge pull request #19 from kikijiki/bugs
Fixed the problem with pages having the same date.
2013-05-30 03:00:47 -07:00
KIKIJIKI
fc9409e5a1 Fixed the problem with pages having the same date.
If the order is by date and some pages have the same date, only one will
be added to the array because it uses the date as the key.

By adding an auto-incrementing id the key is guaranteed to be unique.
2013-05-12 19:52:27 +09:00
Gilbert Pellegrom
295b7e42ec Updating README 2013-05-08 14:34:29 +01:00
Gilbert Pellegrom
b145ea7d23 v0.6.2
[Changed] Replaced glob_recursive with get_files
2013-05-07 16:27:39 +01:00
Gilbert Pellegrom
f9ebb4d75c v0.6.2
[New] Added "content" and "excerpt" fields to pages
[New] Added excerpt_length config setting
2013-05-07 10:09:03 +01:00
Gilbert Pellegrom
2416172ba7 v0.6
[New] Added plugin functionality
[Changed] Other small cleanup
2013-05-06 16:38:38 +01:00
Gilbert Pellegrom
842c05824a v0.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-03 15:45:42 +01:00
Gilbert Pellegrom
8cebbb51f8 v0.4.1
[New] Added CONTENT_EXT global
[Changed] Use .md files instead of .txt
2013-05-01 15:52:18 +01:00
Gilbert Pellegrom
cc7ceafc1e v0.4
[New] Add get_pages() function for listing content
[New] Added changelog.txt
[Changed] Updated default theme
[Changed] Updated documentation
2013-05-01 14:34:24 +01:00
228 changed files with 6980 additions and 17223 deletions

25
.build/clean.sh Executable file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
set -e
[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; }
# parameters
ARCHIVE_DIR="${1:-$PICO_PROJECT_DIR}" # directory to create release archives in
# print parameters
echo "Cleaning up build environment..."
printf 'PICO_DEPLOY_DIR="%s"\n' "$PICO_DEPLOY_DIR"
printf 'PICO_BUILD_DIR="%s"\n' "$PICO_BUILD_DIR"
printf 'ARCHIVE_DIR="%s"\n' "$ARCHIVE_DIR"
echo
echo "Removing deployment directory..."
[ ! -d "$PICO_DEPLOY_DIR" ] || rm -rf "$PICO_DEPLOY_DIR"
echo "Removing build directory..."
[ ! -d "$PICO_BUILD_DIR" ] || rm -rf "$PICO_BUILD_DIR"
echo "Removing release archives..."
find "$ARCHIVE_DIR" -mindepth 1 -maxdepth 1 \
\( -name 'pico-release-*.tar.gz' -o -name 'pico-release-*.zip' \) \
-delete

44
.build/deploy-branch.sh Executable file
View file

@ -0,0 +1,44 @@
#!/usr/bin/env bash
set -e
[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; }
# get current Pico milestone
VERSION="$(php -r "require_once('$PICO_PROJECT_DIR/lib/Pico.php'); echo Pico::VERSION;")"
MILESTONE="Pico$([[ "$VERSION" =~ ^([0-9]+\.[0-9]+)\. ]] && echo " ${BASH_REMATCH[1]}")"
echo "Deploying $PROJECT_REPO_BRANCH branch ($MILESTONE)..."
echo
# clone repo
github-clone.sh "$PICO_DEPLOY_DIR" "https://github.com/$DEPLOY_REPO_SLUG.git" "$DEPLOY_REPO_BRANCH"
cd "$PICO_DEPLOY_DIR"
# setup repo
github-setup.sh
# generate phpDocs
generate-phpdoc.sh \
"$PICO_PROJECT_DIR/.phpdoc.xml" \
"$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT.cache" "$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT" \
"$MILESTONE API Documentation ($PROJECT_REPO_BRANCH branch)"
if [ -z "$(git status --porcelain "$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT.cache")" ]; then
# nothing to do
exit 0
fi
# update phpDoc list
update-phpdoc-list.sh \
"$PICO_DEPLOY_DIR/_data/phpDoc.yml" \
"$PICO_DEPLOYMENT" "branch" "<code>$PROJECT_REPO_BRANCH</code> branch" "$(date +%s)"
# commit phpDocs
github-commit.sh \
"Update phpDocumentor class docs for $PROJECT_REPO_BRANCH branch @ $PROJECT_REPO_COMMIT" \
"$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT.cache" "$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT" \
"$PICO_DEPLOY_DIR/_data/phpDoc.yml"
# deploy phpDocs
github-deploy.sh "$PROJECT_REPO_SLUG" "heads/$PROJECT_REPO_BRANCH" "$PROJECT_REPO_COMMIT"

119
.build/deploy-release.sh Executable file
View file

@ -0,0 +1,119 @@
#!/usr/bin/env bash
set -e
[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; }
DEPLOY_FULL="true"
if [ "$DEPLOY_PHPDOC_RELEASES" != "true" ]; then
echo "Skipping phpDoc release deployment because it has been disabled"
DEPLOY_FULL="false"
fi
if [ "$DEPLOY_VERSION_BADGE" != "true" ]; then
echo "Skipping version badge deployment because it has been disabled"
DEPLOY_FULL="false"
fi
if [ "$DEPLOY_VERSION_FILE" != "true" ]; then
echo "Skipping version file deployment because it has been disabled"
DEPLOY_FULL="false"
fi
if [ "$DEPLOY_CLOC_STATS" != "true" ]; then
echo "Skipping cloc statistics deployment because it has been disabled"
DEPLOY_FULL="false"
fi
if [ "$DEPLOY_FULL" != "true" ]; then
if [ "$DEPLOY_PHPDOC_RELEASES" != "true" ] \
&& [ "$DEPLOY_VERSION_BADGE" != "true" ] \
&& [ "$DEPLOY_VERSION_FILE" != "true" ] \
&& [ "$DEPLOY_CLOC_STATS" != "true" ]
then
# nothing to do
exit 0
fi
echo
fi
# parse version
. "$PICO_TOOLS_DIR/functions/parse-version.sh.inc"
if ! parse_version "$PROJECT_REPO_TAG"; then
echo "Invalid version '$PROJECT_REPO_TAG'; aborting..." >&2
exit 1
fi
echo "Deploying Pico $VERSION_MILESTONE ($VERSION_STABILITY)..."
printf 'VERSION_FULL="%s"\n' "$VERSION_FULL"
printf 'VERSION_NAME="%s"\n' "$VERSION_NAME"
printf 'VERSION_ID="%s"\n' "$VERSION_ID"
echo
# clone repo
github-clone.sh "$PICO_DEPLOY_DIR" "https://github.com/$DEPLOY_REPO_SLUG.git" "$DEPLOY_REPO_BRANCH"
cd "$PICO_DEPLOY_DIR"
# setup repo
github-setup.sh
# generate phpDocs
if [ "$DEPLOY_PHPDOC_RELEASES" == "true" ]; then
# generate phpDocs
generate-phpdoc.sh \
"$PICO_PROJECT_DIR/.phpdoc.xml" \
"-" "$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT" \
"Pico $VERSION_MILESTONE API Documentation (v$VERSION_FULL)"
if [ -n "$(git status --porcelain "$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT")" ]; then
# update phpDoc list
update-phpdoc-list.sh \
"$PICO_DEPLOY_DIR/_data/phpDoc.yml" \
"$PICO_DEPLOYMENT" "version" "Pico $VERSION_FULL" "$(date +%s)"
# commit phpDocs
github-commit.sh \
"Update phpDocumentor class docs for v$VERSION_FULL" \
"$PICO_DEPLOY_DIR/phpDoc/$PICO_DEPLOYMENT" "$PICO_DEPLOY_DIR/_data/phpDoc.yml"
fi
fi
# don't update version badge, version file and cloc statistics for pre-releases
if [ "$VERSION_STABILITY" == "stable" ]; then
# update version badge
if [ "$DEPLOY_VERSION_BADGE" == "true" ]; then
generate-badge.sh \
"$PICO_DEPLOY_DIR/badges/pico-version.svg" \
"release" "$VERSION_FULL" "blue"
# commit version badge
github-commit.sh \
"Update version badge for v$VERSION_FULL" \
"$PICO_DEPLOY_DIR/badges/pico-version.svg"
fi
# update version file
if [ "$DEPLOY_VERSION_FILE" == "true" ]; then
update-version-file.sh \
"$PICO_DEPLOY_DIR/_data/version.yml" \
"$VERSION_FULL"
# commit version file
github-commit.sh \
"Update version file for v$VERSION_FULL" \
"$PICO_DEPLOY_DIR/_data/version.yml"
fi
# update cloc statistics
if [ "$DEPLOY_CLOC_STATS" == "true" ]; then
update-cloc-stats.sh \
"$PICO_PROJECT_DIR" \
"$PICO_DEPLOY_DIR/_data/cloc.yml"
# commit cloc statistics
github-commit.sh \
"Update cloc statistics for v$VERSION_FULL" \
"$PICO_DEPLOY_DIR/_data/cloc.yml"
fi
fi
# deploy
github-deploy.sh "$PROJECT_REPO_SLUG" "tags/$PROJECT_REPO_TAG" "$PROJECT_REPO_COMMIT"

19
.build/init.sh.inc Normal file
View file

@ -0,0 +1,19 @@
if [ -z "$PICO_BUILD_ENV" ]; then
echo "No Pico build environment specified" >&2
exit 1
fi
# add project build dir to $PATH
export PATH="$PICO_PROJECT_DIR/.build:$PATH"
# set environment variables
__picocms_cmd export RELEASE_REPO_SLUG="${RELEASE_REPO_SLUG:-picocms/pico-composer}"
__picocms_cmd export RELEASE_REPO_BRANCH="${RELEASE_REPO_BRANCH:-master}"
if [ "$PROJECT_REPO_SLUG" != "picocms/Pico" ]; then
__picocms_cmd export DEPLOY_REPO_SLUG="${DEPLOY_REPO_SLUG:-$PROJECT_REPO_SLUG}"
__picocms_cmd export DEPLOY_REPO_BRANCH="${DEPLOY_REPO_BRANCH:-gh-pages}"
else
__picocms_cmd export DEPLOY_REPO_SLUG="${DEPLOY_REPO_SLUG:-picocms.github.io}"
__picocms_cmd export DEPLOY_REPO_BRANCH="${DEPLOY_REPO_BRANCH:-master}"
fi

40
.build/install.sh Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/env bash
set -e
[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; }
# setup build system
BUILD_REQUIREMENTS=( --phpcs )
[ "$1" != "--deploy" ] || BUILD_REQUIREMENTS+=( --cloc --phpdoc )
"$PICO_TOOLS_DIR/setup/$PICO_BUILD_ENV.sh" "${BUILD_REQUIREMENTS[@]}"
# set COMPOSER_ROOT_VERSION when necessary
if [ -z "$COMPOSER_ROOT_VERSION" ] && [ -n "$PROJECT_REPO_BRANCH" ]; then
echo "Setting up Composer..."
PICO_VERSION_PATTERN="$(php -r "
\$json = json_decode(file_get_contents('$PICO_PROJECT_DIR/composer.json'), true);
if (\$json !== null) {
if (isset(\$json['extra']['branch-alias']['dev-$PROJECT_REPO_BRANCH'])) {
echo 'dev-$PROJECT_REPO_BRANCH';
}
}
")"
if [ -z "$PICO_VERSION_PATTERN" ]; then
PICO_VERSION_PATTERN="$(php -r "
require_once('$PICO_PROJECT_DIR/lib/Pico.php');
echo preg_replace('/\.[0-9]+-dev$/', '.x-dev', Pico::VERSION);
")"
fi
if [ -n "$PICO_VERSION_PATTERN" ]; then
export COMPOSER_ROOT_VERSION="$PICO_VERSION_PATTERN"
fi
echo
fi
# install dependencies
echo "Running \`composer install\`$([ -n "$COMPOSER_ROOT_VERSION" ] && echo -n " ($COMPOSER_ROOT_VERSION)")..."
composer install --no-suggest

91
.build/release.sh Executable file
View file

@ -0,0 +1,91 @@
#!/usr/bin/env bash
set -e
[ -n "$PICO_BUILD_ENV" ] || { echo "No Pico build environment specified" >&2; exit 1; }
# parameters
VERSION="${1:-$PROJECT_REPO_TAG}" # version to create a release for
ARCHIVE_DIR="${2:-$PICO_PROJECT_DIR}" # directory to create release archives in
# print parameters
echo "Creating new release..."
printf 'VERSION="%s"\n' "$VERSION"
echo
# guess version string
if [ -z "$VERSION" ]; then
PICO_VERSION="$(php -r "
require_once('$PICO_PROJECT_DIR/lib/Pico.php');
echo preg_replace('/-(?:dev|n|nightly)(?:[.-]?[0-9]+)?(?:[.-]dev)?$/', '', Pico::VERSION);
")"
VERSION="v$PICO_VERSION-dev+${PROJECT_REPO_BRANCH:-master}"
echo "Creating development release of Pico v$PICO_VERSION ($VERSION)..."
echo
fi
# parse version
. "$PICO_TOOLS_DIR/functions/parse-version.sh.inc"
if ! parse_version "$VERSION"; then
echo "Unable to create release archive: Invalid version '$VERSION'" >&2
exit 1
fi
DEPENDENCY_VERSION="$VERSION_FULL@$VERSION_STABILITY"
if [ "$VERSION_STABILITY" == "dev" ] && [ -n "$VERSION_BUILD" ]; then
DEPENDENCY_VERSION="dev-$VERSION_BUILD"
fi
# clone repo
github-clone.sh "$PICO_BUILD_DIR" "https://github.com/$RELEASE_REPO_SLUG.git" "$RELEASE_REPO_BRANCH"
cd "$PICO_BUILD_DIR"
# force Pico version
echo "Updating composer dependencies..."
composer require --no-update \
"picocms/pico $DEPENDENCY_VERSION" \
"picocms/pico-theme $DEPENDENCY_VERSION" \
"picocms/pico-deprecated $DEPENDENCY_VERSION"
echo
# force minimum stability <= beta due to Parsedown 1.8 currently being in beta
if [ "$VERSION_STABILITY" == "stable" ] || [ "$VERSION_STABILITY" == "rc" ]; then
VERSION_STABILITY="beta"
fi
# set minimum stability
if [ "$VERSION_STABILITY" != "stable" ]; then
echo "Setting minimum stability to '$VERSION_STABILITY'..."
composer config "minimum-stability" "$VERSION_STABILITY"
composer config "prefer-stable" "true"
echo
fi
# install dependencies
echo "Running \`composer install\`..."
composer install --no-suggest --prefer-dist --no-dev --optimize-autoloader
echo
# prepare release
echo "Replacing 'index.php'..."
cp vendor/picocms/pico/index.php.dist index.php
echo "Adding 'README.md', 'CONTRIBUTING.md', 'CHANGELOG.md'..."
cp vendor/picocms/pico/README.md README.md
cp vendor/picocms/pico/CONTRIBUTING.md CONTRIBUTING.md
cp vendor/picocms/pico/CHANGELOG.md CHANGELOG.md
echo "Removing '.git' directories of plugins and themes..."
find themes/ -type d -path 'themes/*/.git' -print0 | xargs -0 rm -rf
find plugins/ -type d -path 'plugins/*/.git' -print0 | xargs -0 rm -rf
echo "Preparing 'composer.json' for release..."
composer require --no-update \
"picocms/pico ^$VERSION_MILESTONE" \
"picocms/pico-theme ^$VERSION_MILESTONE" \
"picocms/pico-deprecated ^$VERSION_MILESTONE"
# create release archives
create-release.sh "$PICO_BUILD_DIR" "$ARCHIVE_DIR" "pico-release-v$VERSION_FULL"

12
.gitattributes vendored Normal file
View file

@ -0,0 +1,12 @@
/.build export-ignore
/.github export-ignore
/assets/.gitignore export-ignore
/config/.gitignore export-ignore
/content/.gitignore export-ignore
/plugins/.gitignore export-ignore
/themes/.gitignore export-ignore
/.gitattributes export-ignore
/.gitignore export-ignore
/.phpcs.xml export-ignore
/.phpdoc.xml export-ignore
/.travis.yml export-ignore

1
.github/FUNDING.yml vendored Normal file
View file

@ -0,0 +1 @@
custom: https://www.bountysource.com/teams/picocms

48
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View file

@ -0,0 +1,48 @@
<!--
Developer Certificate of Origin
===============================
By contributing to Pico, you accept and agree to the following terms and conditions (the *Developer Certificate of Origin*) for your present and future contributions submitted to Pico. Please refer to the *Developer Certificate of Origin* section in Pico's [`CONTRIBUTING.md`](https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) for details.
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
-->

28
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,28 @@
name: "Mark or close stale issues and PRs"
on:
schedule:
- cron: "0 12 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v3
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
days-before-stale: 7
days-before-close: 2
stale-issue-message: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed in two days if no further activity
occurs. Thank you for your contributions! :+1:
stale-pr-message: >
This pull request has been automatically marked as stale because it has not had
recent activity. It will be closed in two days if no further activity
occurs. Thank you for your contributions! :+1:
stale-pr-label: "info: Stale"
stale-issue-label: "info: Stale"
exempt-issue-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned"
exempt-pr-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned"
remove-stale-when-updated: true

31
.gitignore vendored
View file

@ -1,5 +1,26 @@
composer.lock
composer.phar
vendor/twig/twig/doc/*
vendor/twig/twig/ext/*
vendor/twig/twig/test/*
# Linux
*~
*.swp
# Windows
Thumbs.db
desktop.ini
# Mac OS X
.DS_Store
._*
# Composer
/composer.lock
/vendor
# Build system
/.build/build
/.build/deploy
/.build/ci-tools
/pico-release-*.tar.gz
/pico-release-*.zip
# phpDocumentor
/.build/phpdoc
/.build/phpdoc.cache

View file

@ -1,9 +1,23 @@
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . index.php [L]
RewriteEngine On
# May be required to access sub directories
#RewriteBase /
# Deny access to internal dirs and files by passing the URL to Pico
RewriteRule ^(config|content|content-sample|lib|vendor)(/|$) index.php [L]
RewriteRule ^(CHANGELOG\.md|composer\.(json|lock|phar))(/|$) index.php [L]
RewriteRule (^\.|/\.)(?!well-known(/|$)) index.php [L]
# Enable URL rewriting
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^ index.php [L]
<IfModule mod_env.c>
# Let Pico know about available URL rewriting
SetEnv PICO_URL_REWRITING 1
</IfModule>
</IfModule>
# Prevent file browsing
Options -Indexes
Options -Indexes -MultiViews

56
.phpcs.xml Normal file
View file

@ -0,0 +1,56 @@
<?xml version="1.0"?>
<ruleset name="Pico">
<description>
Pico's coding standards mainly base on the PHP-FIG PSR-2 standard,
but without the MissingNamespace sniff.
</description>
<!--
Run on current working directory by default
-->
<file>.</file>
<!--
Exclude .build/, .github/ and vendor/ dirs as well as minified JavaScript files
-->
<exclude-pattern type="relative">^.build/</exclude-pattern>
<exclude-pattern type="relative">^.github/</exclude-pattern>
<exclude-pattern type="relative">^vendor/</exclude-pattern>
<exclude-pattern>*.min.js</exclude-pattern>
<!--
Check files for PHP syntax errors
-->
<config name="php_path" value="php"/>
<rule ref="Generic.PHP.Syntax"/>
<!--
Never use deprecated functions,
as they will be removed in future PHP releases
-->
<rule ref="Generic.PHP.DeprecatedFunctions"/>
<!--
Warn about structures which affect performance negatively
-->
<rule ref="Generic.CodeAnalysis.ForLoopWithTestFunctionCall"/>
<!--
Pico follows PHP-FIG PSR-2 Coding Style,
but doesn't use formal namespaces for historic reasons
-->
<rule ref="PSR2">
<exclude name="PSR1.Classes.ClassDeclaration.MissingNamespace"/>
</rule>
<!--
The PHP-FIG PSR-2 Coding Style doesn't fully apply to JavaScript files
Furthermore, some sniffs aren't able to handle JavaScript peculiarities
-->
<rule ref="Generic.ControlStructures.InlineControlStructure">
<exclude-pattern>*.js</exclude-pattern>
</rule>
<rule ref="Squiz.Functions.MultiLineFunctionDeclaration">
<exclude-pattern>*.js</exclude-pattern>
</rule>
</ruleset>

33
.phpdoc.xml Normal file
View file

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" ?>
<phpdocumentor>
<title><![CDATA[Pico API Documentation]]></title>
<parser>
<target>.build/phpdoc.cache</target>
</parser>
<transformer>
<target>.build/phpdoc</target>
</transformer>
<transformations>
<template name="clean"/>
</transformations>
<files>
<directory>.</directory>
<file>index.php</file>
<file>index.php.dist</file>
<!-- exclude .build and .github directories -->
<ignore>.build/*</ignore>
<ignore>.github/*</ignore>
<!-- exclude user config -->
<ignore>config/*</ignore>
<file>config/config.yml.template</file>
<!-- exclude all plugins -->
<ignore>plugins/*</ignore>
<file>plugins/DummyPlugin.php</file>
<!-- exclude vendor dir -->
<ignore>vendor/*</ignore>
</files>
</phpdocumentor>

82
.travis.yml Normal file
View file

@ -0,0 +1,82 @@
dist: bionic
sudo: false
language: php
cache:
directories:
- $HOME/.composer/cache/files
jobs:
include:
# Test stage
- php: 5.3
dist: precise
- php: 5.4
dist: trusty
- php: 5.5
dist: trusty
- php: 5.6
dist: xenial
- php: 7.0
dist: xenial
- php: 7.1
- php: 7.2
- php: 7.3
- php: 7.4
- php: nightly
- php: hhvm-3.24 # until Dec 2018
- php: hhvm-3.27 # until Sep 2019
- php: hhvm-3.30 # until Nov 2019
# Branch deployment stage
- stage: deploy-branch
if: type == "push" && tag IS blank
php: 5.3
dist: precise
install:
- '[[ ",$DEPLOY_PHPDOC_BRANCHES," == *,"$TRAVIS_BRANCH",* ]] || travis_terminate 0'
- install.sh --deploy
script:
- deploy-branch.sh
# Release deployment stage
- stage: deploy-release
if: tag IS present
php: 5.3
dist: precise
install:
- install.sh --deploy
script:
- '[ "$PROJECT_REPO_TAG" == "v$(php -r "require_once(\"lib/Pico.php\"); echo Pico::VERSION;")" ]'
- deploy-release.sh
before_deploy:
- release.sh "$PROJECT_REPO_TAG"
deploy:
provider: releases
api_key: ${GITHUB_OAUTH_TOKEN}
file:
- pico-release-$PROJECT_REPO_TAG.tar.gz
- pico-release-$PROJECT_REPO_TAG.zip
skip_cleanup: true
name: Version ${PROJECT_REPO_TAG:1}
draft: true
on:
tags: true
# Ignore nightly build failures
allow_failures:
- php: nightly
fast_finish: true
before_install:
- export PICO_TOOLS_DIR="$HOME/__picocms_tools"
- git clone --branch="$TOOLS_REPO_BRANCH" "https://github.com/$TOOLS_REPO_SLUG.git" "$PICO_TOOLS_DIR"
- . "$PICO_TOOLS_DIR/init/travis.sh.inc"
- . "$PICO_PROJECT_DIR/.build/init.sh.inc"
install:
- install.sh
script:
- phpcs --standard=.phpcs.xml "$PICO_PROJECT_DIR"

650
CHANGELOG.md Normal file
View file

@ -0,0 +1,650 @@
Pico Changelog
==============
**Note:** This changelog only provides technical information about the changes
introduced with a particular Pico version, and is meant to supplement
the actual code changes. The information in this changelog are often
insufficient to understand the implications of larger changes. Please
refer to both the UPGRADE and NEWS sections of the docs for more
details.
**Note:** Changes breaking backwards compatibility (BC) are marked with an `!`
(exclamation mark). This doesn't include changes for which BC is
preserved by Pico's official `PicoDeprecated` plugin. If a previously
deprecated feature is later removed in `PicoDeprecated`, this change
is going to be marked as BC-breaking change in both Pico's and
`PicoDeprecated`'s changelog. Please note that BC-breaking changes
are only possible with a new major version.
### Version 2.1.4
Released: 2020-08-29
```
* [Changed] Silence PHP errors in Parsedown
* [Fixed] #560: Improve charset guessing for formatted date strings using
`strftime()` (Pico always uses UTF-8, but `strftime()` might not)
```
### Version 2.1.3
Released: 2020-07-10
```
* [New] Add `locale` option to `config/config.yml`
* [Changed] Improve Pico docs
```
### Version 2.1.2
Released: 2020-04-10
```
* [Fixed] Fix DummyPlugin declaring API version 3
```
### Version 2.1.1
Released: 2019-12-31
```
* [Fixed] Require Parsedown 1.8.0-beta-7 and Parsedown Extra 0.8.0-beta-1 due
to changes in Parsedown and Parsedown Extra breaking BC beyond repair
* [Changed] #523: Check for hidden pages based on page ID instead of full paths
* [Changed] Improve Pico docs
```
### Version 2.1.0
Released: 2019-11-24
```
* [Changed] Add Pico's official logo and tagline to `content-sample/_meta.md`
* [Changed] Improve `content-sample/theme.md` to show Pico's official logo and
the usage of the new image utility classes of Pico's default theme
* [Changed] Improve Pico docs and PHPDoc class docs
```
### Version 2.1.0-beta.1
Released: 2019-11-03
```
* [New] Introduce API version 3
* [New] Add `assets_dir`, `assets_url` and `plugins_url` config params
* [New] Add `%config.*%` Markdown placeholders for scalar config params and the
`%assets_url%`, `%themes_url%` and `%plugins_url%` placeholders
* [New] Add `content-sample/theme.md` for theme testing purposes
* [New] Introduce API versioning for themes and support theme-specific configs
using the new `pico-theme.yml` in a theme's directory; `pico-theme.yml`
allows a theme to influence Pico's Twig config, to register known meta
headers and to provide defaults for theme config params
* [New] Add `assets_url`, `themes_url` and `plugins_url` Twig variables
* [New] Add `pages` Twig function to deal with Pico's page tree; this function
replaces the raw usage of Pico's `pages` array in themes
* [New] Add `url` Twig filter to replace URL placeholders (e.g. `%base_url%`)
in strings using the new `Pico::substituteUrl()` method
* [New] Add `onThemeLoading` and `onThemeLoaded` events
* [New] Add `debug` config param and the `Pico::isDebugModeEnabled()` method,
checking the `PICO_DEBUG` environment variable, to enable debugging
* [New] Add new `Pico::getNormalizedPath()` method to normalize a path; this
method should be used to prevent content dir breakouts when dealing
with paths provided by user input
* [New] Add new `Pico::getUrlFromPath()` method to guess a URL from a file path
* [New] Add new `Pico::getAbsoluteUrl()` method to make a relative URL absolute
* [New] #505: Create pre-built `.zip` release archives
* [Fixed] #461: Proberly handle content files with a UTF-8 BOM
* [Changed] Rename `theme_url` config param to `themes_url`; the `theme_url`
Twig variable and Markdown placeholder are kept unchanged
* [Changed] Update to Parsedown Extra 0.8 and Parsedown 1.8 (both still beta)
* [Changed] Enable Twig's `autoescape` feature by default; outputting a
variable now causes Twig to escape HTML markup; Pico's `content`
variable is a notable exception, as it is marked as being HTML safe
* [Changed] Rename `prev_page` Twig variable to `previous_page`
* [Changed] Mark `markdown` and `content` Twig filters as well as the `content`
variable as being HTML safe
* [Changed] Add `$singleLine` param to `markdown` Twig filter as well as the
`Pico::parseFileContent()` method to parse just a single line of
Markdown input
* [Changed] Add `AbstractPicoPlugin::configEnabled()` method to check whether
a plugin should be enabled or disabled based on Pico's config
* [Changed] Deprecate the use of `AbstractPicoPlugin::__call()`, use
`PicoPluginInterface::getPico()` instead
* [Changed] Update to Twig 1.36 as last version supporting PHP 5.3, use a
Composer-based installation to use a newer Twig version
* [Changed] Add `$basePath` and `$endSlash` params to `Pico::getAbsolutePath()`
* [Changed] Deprecate `Pico::getBaseThemeUrl()`
* [Changed] Replace various `file_exists` calls with proper `is_file` calls
* [Changed] Refactor release & build system
* [Changed] Improve Pico docs and PHPDoc class docs
* [Changed] Various small improvements
* [Removed] Remove superfluous `base_dir` and `theme_dir` Twig variables
* [Removed] Remove `PicoPluginInterface::__construct()`
```
### Version 2.0.5-beta.1
Released: 2019-01-03
```
* [New] Add PHP 7.3 tests
* [New] Add `2.0.x-dev` alias for master branch to `composer.json`
* [Changed] Update to Parsedown Extra 0.8 and Parsedown 1.8 (both still beta)
* [Changed] Improve release & build process
```
### Version 2.0.4
Released: 2018-12-17
```
* [Fixed] Proberly handle hostnames with ports in `Pico::getBaseUrl()`
* [Changed] Improve documentation
```
### Version 2.0.3
Released: 2018-12-03
```
* [Fixed] Support alternative server ports in `Pico::getBaseUrl()`
* [Changed] Don't require server environment variables to be configured
* [Changed] Improve release & build process
* [Changed] Improve documentation
* [Changed] Improve PHP class docs
* [Changed] Various small improvements
```
### Version 2.0.2
Released: 2018-08-12
```
* [Fixed] Support Windows paths (`\` instead of `/`) in `Pico::evaluateRequestUrl()`
```
### Version 2.0.1
Released: 2018-07-29
```
* [Changed] Improve documentation
* [Changed] Add missing "Formatted Date", "Time" and "Hidden" meta headers; use
the "Hidden" meta header to manually hide a page in the pages list
```
### Version 2.0.0
Released: 2018-07-01
```
* [New] Add Bountysource
* [Changed] Improve documentation
* [Changed] Improve release & build process
* [Changed] Add `Pico::setConfig()` example to `index.php.dist`
* [Fixed] Don't load `config/config.yml` multiple times
```
### Version 2.0.0-beta.3
Released: 2018-04-07
```
* [Changed] Add `README.md`, `CONTRIBUTING.md` and `CHANGELOG.md` of main repo
to pre-bundled releases, keep `.gitignore`
* [Changed] Deny access to a possibly existing `composer.phar` in `.htaccess`
* [Changed] Disallow the use of the `callback` filter for the `url_param` and
`form_param` Twig functions
* [Changed] Improve documentation
* [Fixed] Fix page tree when sorting pages by arbitrary values
* [Fixed] Fix sorting of `Pico::$nativePlugins`
```
### Version 2.0.0-beta.2
Released: 2018-01-21
```
* [New] Improve release & build process and move most build tools to the new
`picocms/ci-tools` repo, allowing them to be used by other projects
* [New] Add page tree; refer to the `Pico::buildPageTree()` method for more
details; also see the `onPageTreeBuilt` event
* [Changed] Update dependencies: Twig 1.35
* [Changed] ! Improve `.htaccess` and deny access to all dot files by default
* [Changed] ! Throw a `RuntimeException` when non-native plugins are loaded,
but Pico's `PicoDeprecated` plugin is not loaded
* [Changed] ! Change `AbstractPicoPlugin::$enabled`'s behavior: setting it to
TRUE now leads to throwing a `RuntimeException` when the plugin's
dependencies aren't fulfilled; use NULL to maintain old behavior
* [Changed] ! Force themes to use `.twig` as file extension for Twig templates
* [Changed] Improve PHP class docs
* [Changed] Various small improvements
```
### Version 2.0.0-beta.1
Released: 2017-11-05
```
* [New] Pico is on its way to its second major release!
* [New] Improve Pico's release & build process
* [New] Add "Developer Certificate of Origin" to `CONTRIBUTING.md`
* [New] Add license & copyright header to all relevant files
* [New] Add Pico version constants (`Pico::VERSION` and `Pico::VERSION_ID`),
and add a `version` Twig variable and `%version%` Markdown placeholder
* [New] Add Pico API versioning for plugins (see `Pico::API_VERSION` constant);
Pico now triggers events on plugins using the latest API version only
("native" plugins), `PicoDeprecated` takes care of all other plugins;
as a result, old plugin's always depend on `PicoDeprecated` now
* [New] Add a theme and plugin installer for composer; Pico now additionally
uses the new `vendor/pico-plugin.php` file to discover plugins
installed by composer and loads them using composer's autoloader;
see the `picocms/composer-installer` repo for more details; Pico
loads plugins installed by composer first and ignores conflicting
plugins in Pico's `plugins/` dir
* [New] Add `$enableLocalPlugins` parameter to `Pico::__construct()` to allow
website developers to disable local plugin discovery by scanning the
`plugins/` dir (i.e. load plugins from `vendor/pico-plugin.php` only)
* [New] Add public `AbstractPicoPlugin::getPluginConfig()` method
* [New] Add public `Pico::loadPlugin()` method and the corresponding
`onPluginManuallyLoaded` event
* [New] Add public `Pico::resolveFilePath()` method (replaces the protected
`Pico::discoverRequestFile()` method)
* [New] Add public `Pico::is404Content()` method
* [New] Add public `Pico::getYamlParser()` method and the corresponding
`onYamlParserRegistered` event
* [New] Add public `Pico::substituteFileContent()` method
* [New] Add public `Pico::getPageId()` method
* [New] Add public `Pico::getFilesGlob()` method
* [New] Add public `Pico::getVendorDir()` method, returning Pico's installation
directory (i.e. `/var/www/pico/vendor/picocms/pico`); don't confuse
this with composer's `vendor/` dir!
* [New] Add `$default` parameter to `Pico::getConfig()` method
* [New] Add empty `assets/` and `content/` dirs
* [New] #305: Add `url_param` and `form_param` Twig functions, and the public
`Pico::getUrlParameter()` and `Pico::getFormParameter()` methods,
allowing theme developers to access URL GET and HTTP POST parameters
* [New] Add `$meta` parameter to `markdown` Twig filter
* [New] Add `remove` fallback to `sort_by` Twig filter
* [New] Add `theme_url` config parameter
* [New] Add public `Pico::getBaseThemeUrl()` method
* [New] Add `REQUEST_URI` routing method, allowing one to simply rewrite all
requests to `index.php` (e.g. use `FallbackResource` or `mod_rewrite`
in your `.htaccess` for Apache, or use `try_files` for nginx)
* [New] #299: Add built-in 404 page as fallback when no `404.md` is found
* [New] Allow sorting pages by arbitrary meta values
* [New] Add `onSinglePageLoading` event, allowing one to skip a page
* [New] Add `onSinglePageContent` event
* [New] Add some config parameters to change Parsedown's behavior
* [Changed] ! Disallow running the same Pico instance multiple times by
throwing a `RuntimeException` when calling `Pico::run()`
* [Changed] ! #203: Load plugins from `plugins/<plugin name>/<plugin name>.php`
and `plugins/<plugin name>.php` only (directory and file name must
match case-sensitive), and throw a `RuntimeException` when Pico is
unable to load a plugin; also throw a `RuntimeException` when
superfluous files or directories in `plugins/` are found; use a
scope-isolated `require()` to include plugin files
* [Changed] ! Use a plugin dependency topology to sort `Pico::$plugins`,
changing the execution order of plugins so that plugins, on which
other plugins depend, are always executed before their dependants
* [Changed] ! Don't pass `$plugins` parameter to `onPluginsLoaded` event by
reference anymore; use `Pico::loadPlugin()` instead
* [Changed] ! Leave `Pico::$pages` unsorted when a unknown sort method was
configured; this usually means that a plugin wants to sort it
* [Changed] Overhaul page discovery events: add `onPagesDiscovered` event which
is triggered right before `Pico::$pages` is sorted and move the
`$currentPage`, `$previousPage` and `$nextPage` parameters of the
`onPagesLoaded` event to the new `onCurrentPageDiscovered` event
* [Changed] Move the `$twig` parameter of the `onPageRendering` event to the
`onTwigRegistered` event, replacing the `onTwigRegistration` event
* [Changed] Unify the `onParsedownRegistration` event by renaming it to
`onParsedownRegistered` and add the `$parsedown` parameter
* [Changed] #330: Replace `config/config.php` by a modular YAML-based approach;
you can now use a arbitrary number of `config/*.yml` files to
configure Pico
* [Changed] ! When trying to auto-detect Pico's `content` dir, Pico no longer
searches just for a (possibly empty) directory, but rather checks
whether a `index.md` exists in this directory
* [Changed] ! Use the relative path between `index.php` and `Pico::$themesDir`
for Pico's theme URL (also refer to the new `theme_url` config and
the public `Pico::getBaseThemeUrl()` method for more details)
* [Changed] #347: Drop the superfluous trailing "/index" from Pico's URLs
* [Changed] Flip registered meta headers array, so that the array key is used
to search for a meta value and the array value is used to store the
found meta value (previously it was the other way round)
* [Changed] ! Add lazy loading for `Pico::$yamlParser`, `Pico::$parsedown` and
`Pico::$twig`; the corresponding events are no longer part of
Pico's event flow and are triggered on demand
* [Changed] ! Trigger the `onMetaHeaders` event just once; the event is no
longer part of Pico's event flow and is triggered on demand
* [Changed] Don't lower meta headers on the first level of a page's meta data
(i.e. `SomeKey: value` is accessible using `$meta['SomeKey']`)
* [Changed] Don't compare registered meta headers case-insensitive, require
matching case
* [Changed] Allow users to explicitly set values for the `date_formatted` and
`time` meta headers in a page's YAML front matter
* [Changed] Add page siblings for all pages
* [Changed] ! Treat pages or directories that are prefixed by `_` as hidden;
when requesting a hidden page, Pico responds with a 404 page;
hidden pages are still in `Pico::$pages`, but are moved to the end
of the pages array when sorted alphabetically or by date
* [Changed] ! Don't treat explicit requests to a 404 page as successful request
* [Changed] Change method visibility of `Pico::getFiles()` to public
* [Changed] Change method visibility of `Pico::triggerEvent()` to public;
at first glance this method triggers events on native plugins only,
however, `PicoDeprecated` takes care of triggering events for other
plugins, thus you can use this method to trigger (custom) events on
all plugins; never use it to trigger Pico core events!
* [Changed] Move Pico's default theme to the new `picocms/pico-theme` repo; the
theme was completely rewritten from scratch and is a much better
starting point for creating your own theme; refer to the theme's
`CHANGELOG.md` for more details
* [Changed] Move `PicoDeprecated` plugin to the new `picocms/pico-deprecated`
repo; refer to the plugin's `CHANGELOG.md` for more details
* [Changed] Update dependencies: Twig 1.34, Symfony YAML 2.8, Parsedown 1.6
* [Changed] Improve Pico docs and PHP class docs
* [Changed] A vast number of small improvements and changes...
* [Removed] ! Remove `PicoParsePagesContent` plugin
* [Removed] ! Remove `PicoExcerpt` plugin
* [Removed] Remove `rewrite_url` and `is_front_page` Twig variables
* [Removed] Remove superfluous parameters of various events to reduce Pico's
error-proneness (plugins hopefully interfere with each other less)
```
### Version 1.0.6
Released: 2017-07-25
```
* [Changed] Improve documentation
* [Changed] Improve handling of Pico's Twig config (`$config['twig_config']`)
* [Changed] Improve PHP platform requirement checks
```
### Version 1.0.5
Released: 2017-05-02
```
* [Changed] Improve documentation
* [Fixed] Improve hostname detection with proxies
* [Fixed] Fix detection of Windows-based server environments
* [Removed] Remove Twitter links
```
### Version 1.0.4
Released: 2016-10-04
```
* [New] Add Pico's social icons to default theme
* [Changed] Improve documentation
* [Changed] Add CSS flexbox rules to default theme
* [Fixed] Fix handling of non-YAML 1-line front matters
* [Fixed] Fix responsiveness in default theme
```
### Version 1.0.3
Released: 2016-05-11
```
* [Changed] Improve documentation
* [Changed] Heavily extend nginx configuration docs
* [Changed] Add CSS rules for definition lists to default theme
* [Changed] Always use `on404Content...` execution path when serving a `404.md`
* [Changed] Deny access to `.git` directory, `CHANGELOG.md`, `composer.json`
and `composer.lock` (`.htaccess` file)
* [Changed] Use Pico's `404.md` to deny access to `.git`, `config`, `content`,
* `content-sample`, `lib` and `vendor` dirs (`.htaccess` file)
* [Fixed] #342: Fix responsiveness in default theme
* [Fixed] #344: Improve HTTPS detection with proxies
* [Fixed] #346: Force HTTPS to load Google Fonts in default theme
```
### Version 1.0.2
Released: 2016-03-16
```
* [Changed] Various small improvements and changes...
* [Fixed] Check dependencies when a plugin is enabled by default
* [Fixed] Allow `Pico::$requestFile` to point to somewhere outside `content_dir`
* [Fixed] #336: Fix `Date` meta header parsing with ISO-8601 datetime strings
```
### Version 1.0.1
Released: 2016-02-27
```
* [Changed] Improve documentation
* [Changed] Replace `version_compare()` with `PHP_VERSION_ID` in
`index.php.dist` (available since PHP 5.2.7)
* [Fixed] Suppress PHP warning when using `date_default_timezone_get()`
* [Fixed] #329: Force Apache's `MultiViews` feature to be disabled
```
### Version 1.0.0
Released: 2015-12-24
```
* [New] On Christmas Eve, we are happy to announce Pico's first stable release!
The Pico Community wants to thank all contributors and users who made
this possible. Merry Christmas and a Happy New Year 2016!
* [New] Adding `$queryData` parameter to `Pico::getPageUrl()` method
* [Changed] Improve documentation
* [Changed] Moving `LICENSE` to `LICENSE.md`
* [Changed] Throw `LogicException` instead of `RuntimeException` when calling
`Pico::setConfig()` after processing has started
* [Changed] Default theme now highlights the current page and shows pages with
a title in the navigation only
* [Changed] #292: Ignore YAML parse errors (meta data) in `Pico::readPages()`
* [Changed] Various small improvements and changes...
* [Fixed] Support empty meta header
* [Fixed] #307: Fix path handling on Windows
```
### Version 1.0.0-beta.2
Released: 2015-11-30
```
* [New] Introducing the `PicoTwigExtension` Twig extension
* [New] New `markdown` filter for Twig to parse markdown strings; Note: If you
want to parse the contents of a page, use the `content` filter instead
* [New] New `sort_by` filter to sort an array by a specified key or key path
* [New] New `map` filter to get the values of the given key or key path
* [New] Introducing `index.php.dist` (used for pre-bundled releases)
* [New] Use PHP_CodeSniffer to auto-check source code (see `.phpcs.xml`)
* [New] Use Travis CI to generate phpDocs class docs automatically
* [Changed] Improve documentation
* [Changed] Improve table styling in default theme
* [Changed] Update composer version constraints; almost all dependencies will
have pending updates, run `composer update`
* [Changed] Throw a RuntimeException when the `content` dir isn't accessible
* [Changed] Reuse `ParsedownExtra` object; new `onParsedownRegistration` event
* [Changed] `$config['rewrite_url']` is now always available
* [Changed] `DummyPlugin` class is now final
* [Changed] Remove `.git` dirs from `vendor/` when deploying
* [Changed] Various small improvements and changes...
* [Fixed] `PicoDeprecated`: Sanitize `content_dir` and `base_url` options when
reading `config.php` in Picos root dir
* [Fixed] Replace `urldecode()` (deprecated RFC 1738) with `rawurldecode()`
(RFC 3986) in `Page::evaluateRequestUrl()`
* [Fixed] #272: Encode URLs using `rawurlencode()` in `Pico::getPageUrl()`
* [Fixed] #274: Prevent double slashes in `base_url`
* [Fixed] #285: Make `index.php` work when installed as a composer dependency
* [Fixed] #291: Force `Pico::$requestUrl` to have no leading/trailing slash
```
### Version 1.0.0-beta.1
Released: 2015-11-06
```
* [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] Moving `license.txt` to `LICENSE`
* [Changed] Moving and reformatting `changelog.txt` to `CHANGELOG.md`
* [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] Removing `$pageData['excerpt']`; recoverable with `PicoExcerpt`
* [Removed] #93, #158: Pico doesn't parse all content files anymore; moved to
`PicoParsePagesContent`; i.e. `$pageData['content']` doesn't exist
anymore, use `$pageData['raw_content']` when possible; otherwise
use Twigs new `content` filter (e.g. `{{ "sub/page"|content }}`)
```
### 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
```

209
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,209 @@
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.
By contributing to Pico, you accept and agree to the *Developer Certificate of Origin* for your present and future contributions submitted to Pico. Please refer to the *Developer Certificate of Origin* section below.
Aside from this, we want to *encourage*, but not obligate you, the contributor, to follow the following 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 the *Pico version* you're using. Provided that you're using *plugins*, include a list of them too. We need information about the *actual and expected behavior*, the *steps to reproduce* the problem, and what steps you have taken to resolve the problem by yourself (i.e. *your own troubleshooting*).
Contributing
------------
Once you decide you want to contribute to *Pico's core* (which we really appreciate!) you can fork the project from https://github.com/picocms/Pico. If you're interested in developing a *plugin* or *theme* for Pico, please refer to the [development section](http://picocms.org/development/) of our website.
### Developer Certificate of Origin
By contributing to Pico, you accept and agree to the following terms and conditions for your present and future contributions submitted to Pico. Except for the license granted herein to Pico and recipients of software distributed by Pico, you reserve all right, title, and interest in and to your contributions. All contributions are subject to the following DCO + license terms.
```
Developer Certificate of Origin
Version 1.1
Copyright (C) 2004, 2006 The Linux Foundation and its contributors.
1 Letterman Drive
Suite D4700
San Francisco, CA, 94129
Everyone is permitted to copy and distribute verbatim copies of this
license document, but changing it is not allowed.
Developer's Certificate of Origin 1.1
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I
have the right to submit it under the open source license
indicated in the file; or
(b) The contribution is based upon previous work that, to the best
of my knowledge, is covered under an appropriate open source
license and I have the right under that license to submit that
work with modifications, whether created in whole or in part
by me, under the same open source license (unless I am
permitted to submit under a different license), as indicated
in the file; or
(c) The contribution was provided directly to me by some other
person who certified (a), (b) or (c) and I have not modified
it.
(d) I understand and agree that this project and the contribution
are public and that a record of the contribution (including all
personal information I submit with it, including my sign-off) is
maintained indefinitely and may be redistributed consistent with
this project or the open source license(s) involved.
```
All contributions to this project are licensed under the following MIT License:
```
Copyright (c) <YEAR> <COPYRIGHT HOLDER>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
```
Please note that developing a *plugin* or *theme* for Pico is *not* assumed to be a contribution to Pico itself. By developing a plugin or theme you rather create a 3rd-party project that just uses Pico. Following the spirit of open source, we want to *encourage* you to release your plugin or theme under the terms of a [OSI-approved open source license](https://opensource.org/licenses). After all, Pico is open source, too!
### 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 Pico's `.phpcs.xml` standard. Use the following command:
$ ./vendor/bin/phpcs --standard=.phpcs.xml [file]...
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 working 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 to keep them in sync.
If you update the [`README.md`](https://github.com/picocms/Pico/blob/master/README.md) or [`content-sample/index.md`](https://github.com/picocms/Pico/blob/master/content-sample/index.md), please make sure to update the corresponding files in the [`_docs`](https://github.com/picocms/picocms.github.io/tree/master/_docs/) folder of the `picocms.github.io` repo (i.e. [Pico's website](http://picocms.org/docs/)) and vice versa. Unfortunately this involves three (!) different markdown parsers. If you're experiencing problems, use Pico's [`erusev/parsedown-extra`](https://github.com/erusev/parsedown-extra) as a reference. You can try to make the contents compatible to [Kramdown](http://kramdown.gettalong.org/) (Pico's website) and [CommonMarker](https://github.com/gjtorikian/commonmarker) (`README.md`) 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 (but not necessarily deployed) version of Pico. As soon as development of a new `MAJOR` or `MINOR` release starts, a separate branch (e.g. `pico-1.1`) is created and a [pull request](https://github.com/picocms/Pico/pulls) is opened to receive the desired feedback.
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 non-trivial bug fixes.
As soon as development reaches a point where feedback is appreciated, a pull request is opened. After some time (very soon for bug fixes, and other improvements should have a reasonable feedback phase) the pull request is merged and the development branch will be deleted. Trivial bug fixes that will be part of the next `PATCH` version will be merged directly into `master`.
Build & Release process
-----------------------
We're using [Travis CI](https://travis-ci.com) to automate the build & release process of Pico. It generates and deploys a [PHP class documentation](http://picocms.org/phpDoc/) (powered by [phpDoc](http://phpdoc.org)) for new releases and on every commit to the `master` branch. Travis also prepares new releases by generating Pico's pre-built release packages, a version badge, code statistics (powered by [cloc](https://github.com/AlDanial/cloc)) and updates our website (the [`picocms.github.io` repo](https://github.com/picocms/picocms.github.io)). Please refer to our [`.travis.yml`](https://github.com/picocms/Pico/blob/master/.travis.yml), the [`picocms/ci-tools` repo](https://github.com/picocms/ci-tools) and the [`.build` directory](https://github.com/picocms/Pico/tree/master/.build) for details.
As insinuated above, it is important that each commit to `master` is deployable. Once development of a new Pico release is finished, trigger Pico's build & release process by pushing a new Git tag. This tag should reference a (usually empty) commit on `master`, which message should adhere to the following template:
```
Version 1.0.0
* [Security] ...
* [New] ...
* [Changed] ...
* [Fixed] ...
* [Removed] ...
```
Before pushing a new Git tag, make sure to update the `Pico::VERSION` and `Pico::VERSION_ID` constants. The versions of Pico's official [default theme](https://github.com/picocms/pico-theme) and the [`PicoDeprecated` plugin](https://github.com/picocms/pico-deprecated) both strictly follow Pico's version. Since Pico's pre-built release package contains them, you must always create a new release of them (even though nothing has changed) before creating a new Pico release.
If you're pushing a new major or minor release of Pico, you should also update Pico's `composer.json` to require the latest minor releases of Pico's dependencies. Besides, don't forget to update the `@version` tags in the PHP class docs.
Travis CI will draft the new [release on GitHub](https://github.com/picocms/Pico/releases) automatically, but will require you to manually amend the descriptions formatting. The latest Pico version is always available at https://github.com/picocms/Pico/releases/latest, so please make sure to publish this URL rather than version-specific URLs. [Packagist](http://packagist.org/packages/picocms/pico) will be updated automatically.
Labeling of Issues & Pull Requests
----------------------------------
Pico makes use of GitHub's label and milestone features, to aide developers in quickly identifying and prioritizing which issues need to be worked on. The starting point for labeling issues and pull requests is the `type` label, which is explained in greater detail below. The `type` label might get combined with a `pri` label, describing the issue's priority, and a `status` label, describing the current status of the issue.
Issues and pull requests labeled with `info: Feedback Needed` indicate that feedback from others is highly appreciated. We always appreciate feedback at any time and from anyone, but when this label is present, we explicitly *ask* you to give feedback. It would be great if you leave a comment!
- The `type: Bug` label is assigned to issues or pull requests, which have been identified as bugs or security issues in Pico's core. It might get combined with the `pri: High` label, when the problem was identified as security issue, or as a so-called "show stopper" bug. In contrast, uncritical problems might get labeled with `pri: Low`. `type: Bug` issues and pull requests are usually labeled with one of the following `status` labels when being closed:
- `status: Resolved` is used when the issue has been resolved.
- `status: Conflict` indicates a conflict with another issue or behavior of Pico, making it impossible to resolve the problem at the moment.
- `status: Won't Fix` means, that there is indeed a problem, but for some reason we made the decision that resolving it isn't reasonable, making it intended behavior.
- `status: Rejected` is used when the issue was rejected for another reason.
- The `type: Enhancement` and `type: Feature` labels are used to tag pull requests, which introduce either a comparatively small enhancement, or a "big" new feature. As with the `type: Bug` label, they might get combined with the `pri: High` or `pri: Low` labels to indicate the pull request's priority. If a pull request isn't mergeable at the moment, it is labeled with `status: Work In Progress` until development of the pull request is finished. After merging or closing the pull request, it is labeled with one of the `status` labels as described above for the `type: Bug` label.
- The `type: Idea` label is similar to the `type: Enhancement` and `type: Feature` labels, but is used for issues or incomplete and abandoned pull requests. It is otherwise used in the exact same way as `type: Enhancement` and `type: Feature`.
- The `type: Release` label is used in the exact same way as `type: Feature` and indicates the primary pull request of a new Pico release (please refer to the *Branching* and *Build & Release process* sections above).
- The `type: Notice`, `type: Support` and `type: Discussion` labels are used to indicate "fyi" issues, support-related issues (e.g. issues opened by users or developers asking questions), and issues with disucssions about arbitrary topics related to Pico. They are neither combined with `pri` labels, nor with `status` labels.
- The `type: Duplicate` label is used when there is already another issue or pull request related to this problem or feature request. Issues labeled with `type: Duplicate` are immediately closed.
- The `type: Invalid` label is used for everything else, e.g. issues or pull requests not related to Pico, or invalid bug reports. This includes supposed bug reports that concern actually intended behavior.
The `status: Deferred` label might get added to any open issue or pull request to indicate that it is still unresolved and will be resolved later. This is also true for the `info: Pinned` label: It indicates a important issue or pull request that remains open on purpose.
After resolving a issue, we usually keep it open for about a week to give users some more time for feedback and further questions. This is especially true for issues with the `type: Notice`, `type: Support`, `type: Discussion` and `type: Invalid` labels. After 7 days with no interaction, [Probot](https://probot.github.io/)'s [Stale](https://github.com/apps/stale) bot adds the `info: Stale` label to the issue to ask the participants whether the issue has been resolved. If no more activity occurs, the issue will be automatically closed by Stale bot 2 days later.
Issues and pull requests labeled with `info: Information Needed` indicate that we have asked one of the participants for further information and didn't receive any feedback yet. It is usually added after Stale bot adds the `info: Stale` label to give the participants some more days to give the necessary information.
Issues and pull requests, which are rather related to upstream projects (i.e. projects Pico depends on, like Twig), are additionally labeled with `info: Upstream`.
When a issue or pull request isn't directly related to Pico's core, but the project as a whole, it is labeled with `info: Meta`. Issues labeled with `info: Website` are related to [Pico's website](http://picocms.org), however, in this case it is usually expedient to move the issue to the [`picocms.github.io` repo](https://github.com/picocms/picocms.github.io) instead. The same applies to the `info: Pico CMS for Nextcloud` label; these issues are related to [Pico CMS for Nextcloud](https://apps.nextcloud.com/apps/cms_pico).

1
README
View file

@ -1 +0,0 @@
Pico is a stupidly simple, blazing fast, flat file CMS. See http://pico.dev7studios.com for more info.

273
README.md Normal file
View file

@ -0,0 +1,273 @@
Pico
====
[![License](https://picocms.github.io/badges/pico-license.svg)](https://github.com/picocms/Pico/blob/master/LICENSE.md)
[![Version](https://picocms.github.io/badges/pico-version.svg)](https://github.com/picocms/Pico/releases/latest)
[![Build Status](https://api.travis-ci.org/picocms/Pico.svg?branch=master)](https://travis-ci.org/picocms/Pico)
[![Libera.Chat](https://picocms.github.io/badges/pico-chat.svg)](https://web.libera.chat/#picocms)
[![Open Bounties on Bountysource](https://www.bountysource.com/badge/team?team_id=198139&style=bounties_received)](https://www.bountysource.com/teams/picocms)
Pico is a stupidly simple, blazing fast, flat file CMS.
Visit us at http://picocms.org/ and see http://picocms.org/about/ for more info.
---
### PHP 8.0+ Users
Seeing an `Unparenthesized a ? b : c ? d : e is not supported.` error?
Pico currently has issues with PHP versions newer than 8.0. This is due to Pico's dependencies, and not Pico itself. There's currently an "alpha" build of Pico you can download as a [Pre-Bundled Release](https://github.com/picocms/Pico/releases/tag/v3.0.0-alpha.2) that solves this issue.
This "alpha" is **perfectly safe** to use in production, as the *only* changes are **updated dependencies and version number strings**. If you're curious, you can confirm this by [comparing the changes](https://github.com/picocms/Pico/compare/pico-3.0-alpha) between branches.
More work was intended to be done on this branch, hence the "3.0" label, but it hasn't happened yet. There's an [on-going discussion](https://github.com/picocms/Pico/issues/608) about getting just these updated dependencies merged in as an official update (either Pico 2.2 or 3.0) as soon as possible.
Sorry for the inconvenience, and thanks to all Pico users for your patience on the matter. ❤️
---
Screenshot
----------
![Pico Screenshot](https://picocms.github.io/screenshots/pico-21.png)
Install
-------
Installing Pico is dead simple - and done in seconds! If you have access to a shell on your server (i.e. SSH access), we recommend using [Composer][]. If not, use a pre-bundled release. If you don't know what "SSH access" is, head over to the pre-bundled release. 😇
Pico requires PHP 5.3.6+ and the PHP extensions `dom` and `mbstring` to be enabled.
### I want to use Composer
Starting with Pico 2.0 we recommend installing Pico using Composer whenever possible. Trust us, you won't regret it when it comes to upgrading Pico! Anyway, if you don't want to use Composer, or if you simply can't use Composer because you don't have access to a shell on your server, don't despair, installing Pico using a pre-bundled release is still easier than everything you know!
###### Step 1
Open a shell and navigate to the `httpdocs` directory (e.g. `/var/www/html`) of your server. Download Composer and run it with the `create-project` option to install it to the desired directory (e.g. `/var/www/html/pico`):
```shell
$ curl -sSL https://getcomposer.org/installer | php
$ php composer.phar create-project picocms/pico-composer pico
```
###### Step 2
What second step? There's no second step. That's it! Open your favorite web browser and navigate to your brand new, stupidly simple, blazing fast, flat file CMS! Pico's sample contents will explain how to create your own contents. 😊
### I want to use a pre-bundled release
Do you know the feeling: You want to install a new website, so you upload all files of your favorite CMS and run the setup script - just to find out that you forgot about creating the SQL database first? Later the setup script tells you that the file permissions are wrong. Heck, what does this even mean? Forget about it, Pico is different!
###### Step 1
[Download the latest Pico release][LatestRelease] and upload all files to the desired install directory of Pico within the `httpdocs` directory (e.g. `/var/www/html/pico`) of your server.
###### Step 2
Okay, here's the catch: There's no catch. That's it! Open your favorite web browser and navigate to your brand new, stupidly simple, blazing fast, flat file CMS! Pico's sample contents will explain how to create your own contents. 😊
### I want to manage my website using a Git repository
Git is a very powerful distributed version-control system - and it can be used to establish a nice workflow around your Pico website. Using a Git repository for your website aids content creation and deployment, including collaborative editing and version control. If you want to manage your website in a Git repository, you use a Composer-based installation.
1. Fork [Pico's Composer starter project][PicoComposerGit] using [GitHub's fork button][HelpFork]. If you don't want to use GitHub you aren't required to, you can choose whatever Git server you want. Forking manually just requires some extra steps: First clone the Git repository locally, add your Git server as a remote and push the repository to this new remote.
2. Clone your fork locally and add your contents and assets. You can edit Pico's `composer.json` to include 3rd-party plugins and themes, or simply add your own plugins and themes to Pico's `plugins` resp. `themes` directories. Don't forget to commit your changes and push them to your Git server.
3. Open a shell on your webserver and navigate to the `httpdocs` directory (e.g. `/var/www/html`). Download Composer, clone your Git repository to the desired directory (e.g. `/var/www/html/pico`) and install Pico's dependencies using Composer's `install` option:
```shell
$ curl -sSL https://getcomposer.org/installer | php
$ git clone https://github.com/<YOUR_USERNAME>/<YOUR_REPOSITORY> pico
$ php composer.phar --working-dir=pico install
```
4. If you update your website's contents, simply commit your changes and push them to your Git server. Open a shell on your webserver and navigate to Pico's install directory within the `httpdocs` directory (e.g. `/var/www/html/pico`) of your server. Pull all changes from your Git server and update Pico's dependencies using Composer's `update` option:
```shell
$ git pull
$ php composer.phar update
```
### I'm a developer
So, you're one of these amazing people making all of this possible? We love you folks! As a developer we recommend you to clone [Pico's Git repository][PicoGit] as well as the Git repositories of [Pico's default theme][PicoThemeGit] and the [`PicoDeprecated` plugin][PicoDeprecatedGit]. You can set up your workspace using [Pico's Composer starter project][PicoComposerGit] and include all of Pico's components using local packages.
Using Pico's Git repositories is different from using one of the installation methods elucidated above. It gives you the current development version of Pico, what is likely *unstable* and *not ready for production use*!
1. Open a shell and navigate to the desired directory of Pico's development workspace within the `httpdocs` directory (e.g. `/var/www/html/pico`) of your server. Download and extract Pico's Composer starter project into the `workspace` directory:
```shell
$ curl -sSL https://github.com/picocms/pico-composer/archive/master.tar.gz | tar xz
$ mv pico-composer-master workspace
```
2. Clone the Git repositories of all Pico components (Pico's core, Pico's default theme and the `PicoDeprecated` plugin) into the `components` directory:
```shell
$ mkdir components
$ git clone https://github.com/picocms/Pico.git components/pico
$ git clone https://github.com/picocms/pico-theme.git components/pico-theme
$ git clone https://github.com/picocms/pico-deprecated.git components/pico-deprecated
```
3. Instruct Composer to use the local Git repositories as replacement for the `picocms/pico` (Pico's core), `picocms/pico-theme` (Pico's default theme) and `picocms/pico-deprecated` (the `PicoDeprecated` plugin) packages. Update the `composer.json` of your development workspace (i.e. `workspace/composer.json`) accordingly:
```json
{
"repositories": [
{
"type": "path",
"url": "../components/pico",
"options": { "symlink": true }
},
{
"type": "path",
"url": "../components/pico-theme",
"options": { "symlink": true }
},
{
"type": "path",
"url": "../components/pico-deprecated",
"options": { "symlink": true }
}
],
"require": {
"picocms/pico": "dev-master",
"picocms/pico-theme": "dev-master",
"picocms/pico-deprecated": "dev-master",
"picocms/composer-installer": "^1.0"
}
}
```
4. Download Composer and run it with the `install` option:
```shell
$ curl -sSL https://getcomposer.org/installer | php
$ php composer.phar --working-dir=workspace install
```
You can now open your web browser and navigate to Pico's development workspace. All changes you make to Pico's components will automatically be reflected in the development workspace.
By the way, you can also find all of Pico's components on [Packagist.org][Packagist]: [Pico's core][PicoPackagist], [Pico's default theme][PicoThemePackagist], the [`PicoDeprecated` plugin][PicoDeprecatedPackagist] and [Pico's Composer starter project][PicoComposerPackagist].
Upgrade
-------
Do you remember when you installed Pico? It was ingeniously simple, wasn't it? Upgrading Pico is no difference! The upgrade process differs depending on whether you used [Composer][] or a pre-bundled release to install Pico. Please note that 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. `2.0.0` to `2.0.1`), we made backwards-compatible bug fixes. If we change the `MINOR` version (e.g. `2.0` to `2.1`), we added functionality in a backwards-compatible manner. Upgrading Pico is dead simple in both cases. Simply head over to the appropiate Upgrade sections below.
But wait, we forgot to mention what happens when we update the `MAJOR` version (e.g. `2.0` to `3.0`). In this case we made incompatible API changes. We will then provide a appropriate upgrade tutorial, so please head over to the ["Upgrade" page on our website][HelpUpgrade].
### I've used Composer to install Pico
Upgrading Pico is dead simple if you've used Composer to install Pico. Simply open a shell and navigate to Pico's install directory within the `httpdocs` directory (e.g. `/var/www/html/pico`) of your server. You can now upgrade Pico using just a single command:
```shell
$ php composer.phar update
```
That's it! Composer will automatically update Pico and all plugins and themes you've installed using Composer. Please make sure to manually update all plugins and themes you've installed manually.
### I've used a pre-bundled release to install Pico
Okay, installing Pico was easy, but upgrading Pico is going to be hard, isn't it? I'm afraid I have to disappoint you. It's just as simple as installing Pico!
First you'll have to delete the `vendor` directory of your Pico installation (e.g. if you've installed Pico to `/var/www/html/pico`, delete `/var/www/html/pico/vendor`). Then [download the latest Pico release][LatestRelease] and upload all files to your existing Pico installation directory. You will be prompted whether you want to overwrite files like `index.php`, `.htaccess`, ... - simply hit "Yes".
That's it! Now that Pico is up-to-date, you need to update all plugins and themes you've installed.
### I'm a developer
As a developer you should know how to stay up-to-date... 😉 For the sake of completeness, if you want to upgrade Pico, simply open a shell and navigate to Pico's development workspace (e.g. `/var/www/html/pico`). Then pull the latest commits from the Git repositories of [Pico's core][PicoGit], [Pico's default theme][PicoThemeGit] and the [`PicoDeprecated` plugin][PicoDeprecatedGit]. Let Composer update your dependencies and you're ready to go.
```shell
$ git -C components/pico pull
$ git -C components/pico-theme pull
$ git -C components/pico-deprecated pull
$ php composer.phar --working-dir=workspace update
```
Getting Help
------------
#### 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 1.0 to Pico 2.0. You can find officially supported [plugins][OfficialPlugins] and [themes][OfficialThemes] on our website. 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.
#### 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 [developer docs on our website][HelpDevDocs].
#### You still need help or experience a problem with Pico?
When the docs can't answer your question, you can get help by joining us on [#picocms on Libera.Chat][LiberaChat] ([logs][LiberaChatLogs]). 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 the *Pico version* you're using. Provided that you're using *plugins*, include a list of them too. We need information about the *actual and expected behavior*, the *steps to reproduce* the problem, and what steps you have taken to resolve the problem by yourself (i.e. *your own troubleshooting*).
Contributing
------------
You want to contribute to Pico? We really appreciate that! You can help make Pico better by [contributing code][PullRequests] or [reporting issues][Issues], but please take note of our [contribution guidelines][ContributionGuidelines]. In general you can contribute in three different areas:
1. Plugins & Themes: You're a plugin developer or theme designer? We love you folks! You can find tons of information about how to develop plugins and themes at http://picocms.org/development/. If you have created a plugin or theme, please add it to our [Wiki][], either on the [plugins][WikiPlugins] or [themes][WikiThemes] page. You may also [Submit][] it to our website, where it'll be displayed on the official [plugin][OfficialPlugins] or [theme][OfficialThemes] pages!
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 our website's Git repository from https://github.com/picocms/picocms.github.io, change the Markdown files and open a [pull request][PullRequestsWebsite].
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!
By contributing to Pico, you accept and agree to the *Developer Certificate of Origin* for your present and future contributions submitted to Pico. Please refer to the ["Developer Certificate of Origin" section in our `CONTRIBUTING.md`][ContributionGuidelinesDCO].
You don't have time to contribute code to Pico, but still want to "stand a coffee" for the ones who do? You can contribute monetary to Pico using [Bountysource][], a crowd funding website that focuses on individual issues and feature requests. Just refer to the "Bounties and Fundraisers" section below for more info.
Bounties and Fundraisers
------------------------
Pico uses [Bountysource][] to allow monetary contributions to the project. Bountysource is a crowd funding website that focuses on individual issues and feature requests in Open Source projects using micropayment. Users, or "Backers", can pledge money for fixing a specific issue, implementing new features, or developing a new plugin or theme. Open source software developers, or "Bounty Hunters", can then pick up and solve these tasks to earn the money.
Obviously this won't allow a developer to replace a full time job, it's rather aiming to "stand a coffee". However, it helps bringing users and developers closer together, and shows developers what users want and how much they care about certain things. Nevertheless you can still donate money to the project itself, as an easy way to say "Thank You" and to support Pico.
If you want to encourage developers to [fix a specific issue][Issues] or implement a feature, simply [pledge a new bounty][Bountysource] or back an existing one.
As a developer you can pick up a bounty by simply contributing to Pico (please refer to the "Contributing" section above). You don't have to be a official Pico Contributor! Pico is a Open Source project, anyone can open [pull requests][PullRequests] and claim bounties.
Official Pico Contributors won't claim bounties on their own behalf, Pico will never take any money out of Bountysource. All money collected by Pico is used to pledge new bounties or to support projects Pico depends on.
[Composer]: https://getcomposer.org/
[LatestRelease]: https://github.com/picocms/Pico/releases/latest
[PicoGit]: https://github.com/picocms/Pico
[PicoThemeGit]: https://github.com/picocms/pico-theme
[PicoDeprecatedGit]: https://github.com/picocms/pico-deprecated
[PicoComposerGit]: https://github.com/picocms/pico-composer
[Packagist]: https://packagist.org/
[PicoPackagist]: https://packagist.org/packages/picocms/pico
[PicoThemePackagist]: https://packagist.org/packages/picocms/pico-theme
[PicoDeprecatedPackagist]: https://packagist.org/packages/picocms/pico-deprecated
[PicoComposerPackagist]: https://packagist.org/packages/picocms/pico-composer
[SemVer]: http://semver.org
[HelpFork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo
[HelpUpgrade]: http://picocms.org/in-depth/upgrade/
[HelpUserDocs]: http://picocms.org/docs/
[HelpDevDocs]: http://picocms.org/development/
[Submit]: http://picocms.org/in-depth/submission_guidelines
[OfficialPlugins]: http://picocms.org/plugins/
[OfficialThemes]: http://picocms.org/themes/
[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
[LiberaChat]: https://web.libera.chat/#picocms
[LiberaChatLogs]: http://picocms.org/irc-logs
[PullRequests]: https://github.com/picocms/Pico/pulls
[PullRequestsWebsite]: https://github.com/picocms/picocms.github.io/pulls
[ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md
[ContributionGuidelinesDCO]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md#developer-certificate-of-origin
[EditInlineDocs]: https://github.com/picocms/Pico/edit/master/content-sample/index.md
[EditUserDocs]: https://github.com/picocms/picocms.github.io/tree/master/_docs
[EditDevDocs]: https://github.com/picocms/picocms.github.io/tree/master/_development
[Bountysource]: https://www.bountysource.com/teams/picocms

15
SECURITY.md Normal file
View file

@ -0,0 +1,15 @@
# Security Policy
## Supported Versions
Only the most recent stable version of Pico is supported.
## Reporting a Vulnerability
To mitigate the impact of possible security issues we ask you to disclose any security issues with Pico privately first ("responsible disclosure"). To do so please send an email to Pico's lead developer:
> Daniel Rudolf \<picocms.org@daniel-rudolf.de\>
You should receive an answer within 48 hours.
All messages with valid security reports will be puslished on GitHub in full text.

2
assets/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# This directory is meant to be empty
*

View file

@ -1,5 +1,59 @@
{
"name": "picocms/pico",
"type": "library",
"description": "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\" folder and that becomes a page.",
"keywords": ["pico", "picocms", "pico-cms", "simple", "flat-file", "cms", "content-management", "website", "markdown-to-html", "php", "markdown", "yaml", "twig" ],
"homepage": "http://picocms.org/",
"license": "MIT",
"authors": [
{
"name": "Gilbert Pellegrom",
"email": "gilbert@pellegrom.me",
"role": "Project Founder"
},
{
"name": "Daniel Rudolf",
"email": "picocms.org@daniel-rudolf.de",
"role": "Lead Developer"
},
{
"name": "The Pico Community",
"homepage": "http://picocms.org/"
},
{
"name": "Contributors",
"homepage": "https://github.com/picocms/Pico/graphs/contributors"
}
],
"support": {
"docs": "http://picocms.org/docs",
"issues": "https://github.com/picocms/Pico/issues",
"source": "https://github.com/picocms/Pico"
},
"require": {
"twig/twig": "1.12.*"
"php": ">=5.3.6",
"ext-mbstring": "*",
"twig/twig": "^1.36",
"symfony/yaml" : "^2.8",
"erusev/parsedown": "1.8.0-beta-7",
"erusev/parsedown-extra": "0.8.0-beta-1"
},
"suggest": {
"picocms/pico-theme": "Pico requires a theme to actually display the contents of your website. This is Pico's official default theme.",
"picocms/pico-deprecated": "PicoDeprecated's purpose is to maintain backward compatibility to older versions of Pico.",
"picocms/composer-installer": "This Composer plugin is responsible for installing Pico plugins and themes using the Composer package manager."
},
"autoload": {
"psr-0": {
"Pico": "lib/",
"PicoPluginInterface": "lib/",
"AbstractPicoPlugin": "lib/"
}
},
"extra": {
"branch-alias": {
"dev-master": "2.1.x-dev",
"dev-pico-3.0": "3.0.x-dev"
}
}
}
}

View file

@ -1,17 +0,0 @@
<?php
/*
// Override any of the default settings below:
$config['site_title'] = 'Pico'; // Site title
$config['base_url'] = ''; // Override base URL (e.g. http://example.com)
$config['theme'] = 'default'; // Set the theme (defaults to "default")
$config['enable_cache'] = false; // Enable caching
// To add a custom config setting:
$config['custom_setting'] = 'Hello'; // Can be accessed by {{ config.custom_setting }} in a theme
*/
?>

3
config/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# This directory is meant to be empty, except for config.yml.template
*
!config.yml.template

View file

@ -0,0 +1,60 @@
##
# Basic
#
site_title: Pico # The title of your website
base_url: ~ # Pico will try to guess its base URL, if this fails, override it here;
# Example: https://example.com/pico/
rewrite_url: ~ # A boolean (true or false) indicating whether URL rewriting is forced
debug: ~ # Set this to true to enable Pico's debug mode
timezone: ~ # Your PHP installation might require you to manually specify a timezone
locale: ~ # Your PHP installation might require you to manually specify a locale to use
##
# Theme
#
theme: default # The name of your custom theme
themes_url: ~ # Pico will try to guess the URL to the themes dir of your installation;
# If this fails, override it here. Example: https://example.com/pico/themes/
theme_config: # Additional theme-specific config
widescreen: false # Default theme: Use more horizontal space (i.e. make the site container wider)
twig_config: # Twig template engine config
autoescape: html # Let Twig escape variables by default
strict_variables: false # If set to true, Twig will bail out when unset variables are being used
charset: utf-8 # The charset used by Twig templates
debug: ~ # Enable Twig's debug mode
cache: false # Enable Twig template caching by specifying a path to a writable directory
auto_reload: ~ # Recompile Twig templates whenever the source code changes
##
# Content
#
date_format: %D %T # Pico's default date format;
# See https://php.net/manual/en/function.strftime.php for more info
pages_order_by_meta: author # Sort pages by meta value "author" (set "pages_order_by" to "meta")
pages_order_by: alpha # Change how Pico sorts pages ("alpha" for alphabetical order, "date", or "meta")
pages_order: asc # Sort pages in ascending ("asc") or descending ("desc") order
content_dir: ~ # The path to Pico's content directory
content_ext: .md # The file extension of your Markdown files
content_config: # Parsedown Markdown parser config
extra: true # Use the Parsedown Extra parser to support extended markup;
# See https://michelf.ca/projects/php-markdown/extra/ for more info
breaks: false # A boolean indicating whether breaks in the markup should be reflected in the
# parsed contents of the page
escape: false # Escape HTML markup in your content files; don't confuse this with some sort of
# safe mode, enabling this doesn't allow you to process untrusted user input!
auto_urls: true # Automatically link URLs found in your markup
assets_dir: assets/ # The path to Pico's assets directory
assets_url: ~ # Pico will try to guess the URL to the assets dir of your installation;
# If this fails, override it here. Example: https://example.com/pico/assets/
##
# Plugins
#
plugins_url: ~ # Pico will try to guess the URL to the plugins dir of your installation;
# If this fails, override it here. Example: https://example.com/pico/plugins/
DummyPlugin.enabled: false # Force the plugin "DummyPlugin" to be disabled
##
# Custom
#
my_custom_setting: Hello World! # You can access custom settings in themes using {{ config.my_custom_setting }}

View file

@ -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.

14
content-sample/_meta.md Normal file
View file

@ -0,0 +1,14 @@
---
Logo: %theme_url%/img/pico-white.svg
Tagline: Making the web easy.
Social:
- title: Visit us on GitHub
url: https://github.com/picocms/Pico
icon: octocat
- title: Join us on Libera.Chat
url: https://web.libera.chat/#picocms
icon: chat
- title: Help us by creating/collecting bounties and pledging to fundraisers
url: https://www.bountysource.com/teams/picocms
icon: dollar
---

507
content-sample/index.md Normal file
View file

@ -0,0 +1,507 @@
---
Title: Welcome
Description: Pico is a stupidly simple, blazing fast, flat file CMS.
---
## Welcome to Pico
Congratulations, you have successfully installed [Pico][] %version%.
%meta.description% <!-- replaced by the above Description header -->
## Creating Content
Pico is a flat file CMS. This means there is no administration backend or
database to deal with. You simply create `.md` files in the `content` folder
and those files become your pages. For example, this file is called `index.md`
and is shown as the main landing page.
When you install Pico, it comes with some sample contents that will display
until you add your own content. Simply add some `.md` files to your `content`
folder in Pico's root directory. No configuration is required, Pico will
automatically use the `content` folder as soon as you create your own
`index.md`. Just check out [Pico's sample contents][SampleContents] for an
example!
If you create a folder within the content directory (e.g. `content/sub`) and
put an `index.md` inside it, you can access that folder at the URL
`%base_url%?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/sub/page.md` is accessible from the URL `%base_url%?sub/page`).
Below we've shown some examples of locations and their corresponding URLs:
<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/index.md</td>
<td><a href="%base_url%">/</a></td>
</tr>
<tr>
<td>content/sub.md</td>
<td><del>?sub</del> (not accessible, see below)</td>
</tr>
<tr>
<td>content/sub/index.md</td>
<td><a href="%base_url%?sub">?sub</a> (same as above)</td>
</tr>
<tr>
<td>content/sub/page.md</td>
<td><a href="%base_url%?sub/page">?sub/page</a></td>
</tr>
<tr>
<td>content/theme.md</td>
<td><a href="%base_url%?theme">?theme</a> (hidden in menu)</td>
</tr>
<tr>
<td>content/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/404.md` will be shown. You can add
`404.md` files to any directory. So, for example, if you wanted to use a special
error page for your blog, you could simply create `content/blog/404.md`.
Pico strictly separates contents of your website (the Markdown files in your
`content` directory) and how these contents should be displayed (the Twig
templates in your `themes` directory). However, not every file in your `content`
directory might actually be a distinct page. For example, some themes (including
Pico's default theme) use some special "hidden" file to manage meta data (like
`_meta.md` in Pico's sample contents). Some other themes use a `_footer.md` to
represent the contents of the website's footer. The common point is the `_`: all
files and directories prefixed by a `_` in your `content` directory are hidden.
These pages can't be accessed from a web browser, Pico will show a 404 error
page instead.
As a common practice, we recommend you to separate your contents and assets
(like images, downloads, etc.). We even deny access to your `content` directory
by default. If you want to use some assets (e.g. a image) in one of your content
files, use Pico's `assets` folder. You can then access them in your Markdown
using the <code>&#37;assets_url&#37;</code> placeholder, for example:
<code>!\[Image Title\](&#37;assets_url&#37;/image.png)</code>
### Text File Markup
Text files are marked up using [Markdown][] and [Markdown Extra][MarkdownExtra].
They can also contain regular HTML.
At the top of text files you can place a block comment and specify certain meta
attributes of the page using [YAML][] (the "YAML header"). For example:
---
Title: Welcome
Description: This description will go in the meta description tag
Author: Joe Bloggs
Date: 2001-04-25
Robots: noindex,nofollow
Template: index
---
These values will be contained in the `{{ meta }}` variable in themes (see
below). Meta headers sometimes have a special meaning: For instance, Pico not
only passes through the `Date` meta header, but rather evaluates it to really
"understand" when this page was created. This comes into play when you want to
sort your pages not just alphabetically, but by date. Another example is the
`Template` meta header: It controls what Twig template Pico uses to display
this page (e.g. if you add `Template: blog`, Pico uses `blog.twig`).
In an attempt to separate contents and styling, we recommend you to not use
inline CSS in your Markdown files. You should rather add appropriate CSS
classes to your theme. For example, you might want to add some CSS classes to
your theme to rule how much of the available space a image should use (e.g.
`img.small { width: 80%; }`). You can then use these CSS classes in your
Markdown files, for example:
<code>!\[Image Title\](&#37;assets_url&#37;/image.png) {.small}</code>
There are also certain variables that you can use in your text files:
* <code>&#37;site_title&#37;</code> - The title of your Pico site
* <code>&#37;base_url&#37;</code> - The URL to your Pico site; internal links
can be specified using <code>&#37;base_url&#37;?sub/page</code>
* <code>&#37;theme_url&#37;</code> - The URL to the currently used theme
* <code>&#37;assets_url&#37;</code> - The URL to Pico's `assets` directory
* <code>&#37;themes_url&#37;</code> - The URL to Pico's `themes` directory;
don't confuse this with <code>&#37;theme_url&#37;</code>
* <code>&#37;plugins_url&#37;</code> - The URL to Pico's `plugins` directory
* <code>&#37;version&#37;</code> - Pico's current version string (e.g. `2.0.0`)
* <code>&#37;meta.&#42;&#37;</code> - Access any meta variable of the current
page, e.g. <code>&#37;meta.author&#37;</code> is replaced with `Joe Bloggs`
* <code>&#37;config.&#42;&#37;</code> - Access any scalar config variable,
e.g. <code>&#37;config.theme&#37;</code> is replaced with `default`
### 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 a `Date` meta header.
2. Create a `blog.md` or `blog/index.md` in your `content` directory. Add
`Template: blog-index` to the YAML header of this page. It will later show a
list of all your blog articles (see step 3).
3. Create the new Twig template `blog-index.twig` (the file name must match the
`Template` meta header from Step 2) in your theme directory. This template
probably isn't very different from your default `index.twig` (i.e. copy
`index.twig`), it will create a list of all your blog articles. Add the
following Twig snippet to `blog-index.twig` near `{{ content }}`:
```
{% for page in pages("blog")|sort_by("time")|reverse if not page.hidden %}
<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>
{% endfor %}
```
## 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. Pico
uses [Twig][] for template rendering. You can select your theme by setting the
`theme` option in `config/config.yml` to the name of your theme folder.
[Pico's default theme][PicoTheme] isn't really intended to be used for a
productive website, it's rather a starting point for creating your own theme.
If the default theme isn't sufficient for you, and you don't want to create
your own theme, you can use one of the great themes third-party developers and
designers created in the past. As with plugins, you can find themes on [our website][OfficialThemes].
All themes must include an `index.twig` file to define the HTML structure of
the theme, and a `pico-theme.yml` to set the necessary config parameters. Just
refer to Pico's default theme as an example. You can use different templates
for different content files by specifying the `Template` meta header. Simply
add e.g. `Template: blog` to the YAML header of a content file and Pico will
use the `blog.twig` template in your theme folder to display the page.
Below are the Twig variables that are available to use in themes. Please note
that URLs (e.g. `{{ base_url }}`) never include a trailing slash.
* `{{ site_title }}` - Shortcut to the site title (see `config/config.yml`)
* `{{ config }}` - Contains the values you set in `config/config.yml`
(e.g. `{{ config.theme }}` becomes `default`)
* `{{ base_url }}` - The URL to your Pico site; use Twig's `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_url }}` - The URL to the currently active theme
* `{{ assets_url }}` - The URL to Pico's `assets` directory
* `{{ themes_url }}` - The URL to Pico's `themes` directory; don't confuse this
with `{{ theme_url }}`
* `{{ plugins_url }}` - The URL to Pico's `plugins` directory
* `{{ version }}` - Pico's current version string (e.g. `%version%`)
* `{{ meta }}` - Contains the meta values of the current page
* `{{ meta.title }}` - The `Title` YAML header
* `{{ meta.description }}` - The `Description` YAML header
* `{{ meta.author }}` - The `Author` YAML header
* `{{ meta.date }}` - The `Date` YAML header
* `{{ meta.date_formatted }}` - The formatted date of the page as specified
by the `date_format` parameter in your
`config/config.yml`
* `{{ meta.time }}` - The [Unix timestamp][UnixTimestamp] derived from the
`Date` YAML header
* `{{ meta.robots }}` - The `Robots` YAML header
* ...
* `{{ content }}` - The content of the current page after it has been processed
through Markdown
* `{{ previous_page }}` - The data of the previous page, relative to
`current_page`
* `{{ current_page }}` - The data of the current page; refer to the "Pages"
section below for details
* `{{ next_page }}` - The data of the next page, relative to `current_page`
To call assets from your theme, use `{{ theme_url }}`. For instance, to include
the CSS file `themes/my_theme/example.css`, add
`<link rel="stylesheet" href="{{ theme_url }}/example.css" type="text/css" />`
to your `index.twig`. This works for arbitrary files in your theme's folder,
including images and JavaScript files.
Please note that Twig escapes HTML in all strings before outputting them. So
for example, if you add `headline: My <strong>favorite</strong> color` to the
YAML header of a page and output it using `{{ meta.headline }}`, you'll end up
seeing `My <strong>favorite</strong> color` - yes, including the markup! To
actually get it parsed, you must use `{{ meta.headline|raw }}` (resulting in
the expected <code>My **favorite** color</code>). Notable exceptions to this
are Pico's `content` variable (e.g. `{{ content }}`), Pico's `content` filter
(e.g. `{{ "sub/page"|content }}`), and Pico's `markdown` filter, they all are
marked as HTML safe.
#### Dealing with pages
There are several ways to access Pico's pages list. You can access the current
page's data using the `current_page` variable, or use the `prev_page` and/or
`next_page` variables to access the respective previous/next page in Pico's
pages list. But more importantly there's the `pages()` function. No matter how
you access a page, it will always consist of the following data:
* `{{ id }}` - The relative path to the content file (unique ID)
* `{{ url }}` - The URL to the page
* `{{ title }}` - The title of the page (`Title` YAML header)
* `{{ description }}` - The description of the page (`Description` YAML header)
* `{{ author }}` - The author of the page (`Author` YAML header)
* `{{ date }}` - The date of the page (`Date` YAML header)
* `{{ date_formatted }}` - The formatted date of the page as specified by the
`date_format` parameter in your `config/config.yml`
* `{{ time }}` - The [Unix timestamp][UnixTimestamp] derived from the page's
date
* `{{ raw_content }}` - The raw, not yet parsed contents of the page; use the
filter to get the parsed contents of a page by passing
its unique ID (e.g. `{{ "sub/page"|content }}`)
* `{{ meta }}` - The meta values of the page (see global `{{ meta }}` above)
* `{{ prev_page }}` - The data of the respective previous page
* `{{ next_page }}` - The data of the respective next page
* `{{ tree_node }}` - The page's node in Pico's page tree; check out Pico's
[page tree documentation][FeaturesPageTree] for details
Pico's `pages()` function is the best way to access all of your site's pages.
It uses Pico's page tree to easily traverse a subset of Pico's pages list. It
allows you to filter pages and to build recursive menus (like dropdowns). By
default, `pages()` returns a list of all main pages (e.g. `content/page.md` and
`content/sub/index.md`, but not `content/sub/page.md` or `content/index.md`).
If you want to return all pages below a specific folder (e.g. `content/blog/`),
pass the folder name as first parameter to the function (e.g. `pages("blog")`).
Naturally you can also pass variables to the function. For example, to return a
list of all child pages of the current page, use `pages(current_page.id)`.
Check out the following code snippet:
<section class="articles">
{% for page in pages(current_page.id) if not page.hidden %}
<article>
<h2><a href="{{ page.url }}">{{ page.title }}</a></h2>
{{ page.id|content }}
</article>
{% endfor %}
</section>
The `pages()` function is very powerful and also allows you to return not just
a page's child pages by passing the `depth` and `depthOffset` params. For
example, if you pass `pages(depthOffset=-1)`, the list will also include Pico's
main index page (i.e. `content/index.md`). This one is commonly used to create
a theme's main navigation. If you want to learn more, head over to Pico's
complete [`pages()` function documentation][FeaturesPagesFunction].
If you want to access the data of a particular page, use Pico's `pages`
variable. Just take `content/_meta.md` in Pico's sample contents for an
example: `content/_meta.md` contains some meta data you might want to use in
your theme. If you want to output the page's `tagline` meta value, use
`{{ pages["_meta"].meta.logo }}`. Don't ever try to use Pico's `pages` variable
as an replacement for Pico's `pages()` function. Its usage looks very similar,
it will kinda work and you might even see it being used in old themes, but be
warned: It slows down Pico. Always use Pico's `pages()` function when iterating
Pico's page list (e.g. `{% for page in pages() %}…{% endfor %}`).
#### Twig filters and functions
Additional to [Twig][]'s extensive list of filters, functions and tags, Pico
also provides some useful additional filters and functions to make theming
even easier.
* Pass the unique ID of a page to the `link` filter to return the page's URL
(e.g. `{{ "sub/page"|link }}` gets `%base_url%?sub/page`).
* You can replace URL placeholders (like <code>&#37;base_url&#37;</code>) in
arbitrary strings using the `url` filter. This is helpful together with meta
variables, e.g. if you add <code>image: &#37;assets_url&#37;/stock.jpg</code>
to the YAML header of a page, `{{ meta.image|url }}` will return
`%assets_url%/stock.jpg`.
* To get the parsed contents of a page, pass its unique ID to the `content`
filter (e.g. `{{ "sub/page"|content }}`).
* You can parse any Markdown string using the `markdown` filter. For example,
you might use Markdown in the `description` meta variable and later parse it
in your theme using `{{ meta.description|markdown }}`. You can also pass meta
data as parameter to replace <code>&#37;meta.&#42;&#37;</code> placeholders
(e.g. `{{ "Written by *%meta.author%*"|markdown(meta) }}` yields "Written by
*John Doe*"). However, please note that all contents will be wrapped inside
HTML paragraph elements (i.e. `<p>…</p>`). If you want to parse just a single
line of Markdown markup, pass the `singleLine` param to the `markdown` filter
(e.g. `{{ "This really is a *single* line"|markdown(singleLine=true) }}`).
* Arrays can be sorted by one of its keys using the `sort_by` filter
(e.g. `{% for page in pages|sort_by([ 'meta', 'nav' ]) %}...{% endfor %}`
iterates through all pages, ordered by the `nav` meta header; please note the
`[ 'meta', 'nav' ]` part of the example, it instructs Pico to sort by
`page.meta.nav`). Items which couldn't be sorted are moved to the bottom of
the array; you can specify `bottom` (move items to bottom; default), `top`
(move items to top), `keep` (keep original order) or `remove` (remove items)
as second parameter to change this behavior.
* You can return all values of a given array key using the `map` filter
(e.g. `{{ pages|map("title") }}` returns all page titles).
* Use the `url_param` and `form_param` Twig functions to access HTTP GET (i.e.
a URL's query string like `?some-variable=my-value`) and HTTP POST (i.e. data
of a submitted form) parameters. This allows you to implement things like
pagination, tags and categories, dynamic pages, and even more - with pure
Twig! Simply head over to our [introductory page for accessing HTTP
parameters][FeaturesHttpParams] for details.
### Plugins
#### Plugins for users
Officially tested plugins can be found at http://picocms.org/plugins/, but
there are many awesome third-party plugins out there! A good start point for
discovery is [our Wiki][WikiPlugins].
Pico makes it very easy for you to add new features to your website using
plugins. Just like Pico, you can install plugins either using [Composer][]
(e.g. `composer require phrozenbyte/pico-file-prefixes`), or manually by
uploading the plugin's file (just for small plugins consisting of a single file,
e.g. `PicoFilePrefixes.php`) or directory (e.g. `PicoFilePrefixes`) to your
`plugins` directory. We always recommend you to use Composer whenever possible,
because it makes updating both Pico and your plugins way easier. Anyway,
depending on the plugin you want to install, you may have to go through some
more steps (e.g. specifying config variables) to make the plugin work. Thus you
should always check out the plugin's docs or `README.md` file to learn the
necessary steps.
Plugins which were written to work with Pico 1.0 and later can be enabled and
disabled through your `config/config.yml`. If you want to e.g. disable the
`PicoDeprecated` plugin, add the following line to your `config/config.yml`:
`PicoDeprecated.enabled: false`. To force the plugin to be enabled, replace
`false` by `true`.
#### Plugins for developers
You're a plugin developer? We love you guys! You can find tons of information
about how to develop plugins at http://picocms.org/development/. If you've
developed a plugin before and want to upgrade it to Pico 2.0, refer to the
[upgrade section of the docs][PluginUpgrade].
## Config
Configuring Pico really is stupidly simple: Just create a `config/config.yml`
to override the default Pico settings (and add your own custom settings). Take
a look at the `config/config.yml.template` for a brief overview of the
available settings and their defaults. To override a setting, simply copy the
line from `config/config.yml.template` to `config/config.yml` and set your
custom value.
But we didn't stop there. Rather than having just a single config file, you can
use a arbitrary number of config files. Simply create a `.yml` file in Pico's
`config` dir and you're good to go. This allows you to add some structure to
your config, like a separate config file for your theme (`config/my_theme.yml`).
Please note that Pico loads config files in a special way you should be aware
of. First of all it loads the main config file `config/config.yml`, and then
any other `*.yml` file in Pico's `config` dir in alphabetical order. The file
order is crucial: Config values which have been set already, cannot be
overwritten by a succeeding file. For example, if you set `site_title: Pico` in
`config/a.yml` and `site_title: My awesome site!` in `config/b.yml`, your site
title will be "Pico".
Since YAML files are plain text files, users might read your Pico config by
navigating to `%base_url%/config/config.yml`. This is no problem in the first
place, but might get a problem if you use plugins that require you to store
security-relevant data in the config (like credentials). Thus you should
*always* make sure to configure your webserver to deny access to Pico's
`config` dir. Just refer to the "URL Rewriting" section below. By following the
instructions, you will not just enable URL rewriting, but also deny access to
Pico's `config` dir.
### 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). Below you'll find some basic info
about how to configure your webserver proberly to enable URL rewriting.
#### Apache
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
URL rewriting doesn't work (you're getting `404 Not Found` error messages from
Apache), please make sure to enable the [`mod_rewrite` module][ModRewrite] and
to enable `.htaccess` overrides. You might have to set the
[`AllowOverride` directive][AllowOverride] to `AllowOverride All` in your
virtual host config file or global `httpd.conf`/`apache.conf`. Assuming
rewritten URLs work, but Pico still shows no rewritten URLs, force URL
rewriting by setting `rewrite_url: true` in your `config/config.yml`. If you
rather get a `500 Internal Server Error` no matter what you do, try removing
the `Options` directive from Pico's `.htaccess` file (it's the last line).
#### Nginx
If you're using Nginx, you can use the following config to enable URL rewriting
(lines `5` to `8`) and denying access to Pico's internal files (lines `1` to
`3`). You'll need to adjust the path (`/pico` on lines `1`, `2`, `5` and `7`)
to match your installation directory. Additionally, you'll need to enable URL
rewriting by setting `rewrite_url: true` in your `config/config.yml`. The Nginx
config should provide the *bare minimum* you need for Pico. Nginx is a very
extensive subject. If you have any trouble, please read through our
[Nginx config docs][NginxConfig].
```
location ~ ^/pico/((config|content|vendor|composer\.(json|lock|phar))(/|$)|(.+/)?\.(?!well-known(/|$))) {
try_files /pico/index.php$is_args$args =404;
}
location /pico/ {
index index.php;
try_files $uri $uri/ /pico/index.php$is_args$args;
}
```
#### Lighttpd
Pico runs smoothly on Lighttpd. You can use the following config to enable URL
rewriting (lines `6` to `9`) and denying access to Pico's internal files (lines
`1` to `4`). Make sure to adjust the path (`/pico` on lines `2`, `3` and `7`)
to match your installation directory, and let Pico know about available URL
rewriting by setting `rewrite_url: true` in your `config/config.yml`. The
config below should provide the *bare minimum* you need for Pico.
```
url.rewrite-once = (
"^/pico/(config|content|vendor|composer\.(json|lock|phar))(/|$)" => "/pico/index.php",
"^/pico/(.+/)?\.(?!well-known(/|$))" => "/pico/index.php"
)
url.rewrite-if-not-file = (
"^/pico(/|$)" => "/pico/index.php"
)
```
## Documentation
For more help have a look at the Pico documentation at https://picocms.org/docs/.
[Pico]: https://picocms.org/
[PicoTheme]: https://github.com/picocms/pico-theme
[SampleContents]: https://github.com/picocms/Pico/tree/master/content-sample
[Markdown]: https://daringfireball.net/projects/markdown/syntax
[MarkdownExtra]: https://michelf.ca/projects/php-markdown/extra/
[YAML]: https://en.wikipedia.org/wiki/YAML
[Twig]: https://twig.symfony.com/doc/
[UnixTimestamp]: https://en.wikipedia.org/wiki/Unix_time
[Composer]: https://getcomposer.org/
[FeaturesHttpParams]: https://picocms.org/in-depth/features/http-params/
[FeaturesPageTree]: https://picocms.org/in-depth/features/page-tree/
[FeaturesPagesFunction]: https://picocms.org/in-depth/features/pages-function/
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins
[OfficialThemes]: https://picocms.org/themes/
[PluginUpgrade]: https://picocms.org/development/#migrating-plugins
[ModRewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
[AllowOverride]: https://httpd.apache.org/docs/current/mod/core.html#allowoverride
[NginxConfig]: https://picocms.org/in-depth/nginx/

View file

@ -0,0 +1,11 @@
---
Title: Sub Page Index
---
## This is a Sub Page Index
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.
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.

View file

@ -0,0 +1,11 @@
---
Title: Sub Page
---
## This is a Sub Page
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.
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.

195
content-sample/theme.md Normal file
View file

@ -0,0 +1,195 @@
---
title: Theme Styling Test
hidden: true
---
Theme Styling Test
==================
This is `theme.md` in Pico's content directory. This page doesn't show up in the website's menu due to `hidden: true` in the page's YAML header. The purpose of this page is to aid theme development - below you'll find basically every format that is possible with Markdown. If you develop a theme, you should make sure that all examples below show decent.
Text
----
**Lorem ipsum dolor sit amet,** consectetur adipisici elit, *sed eiusmod tempor* incidunt ut labore et dolore magna aliqua.[^1] ~~Ut enim ad minim veniam,~~ quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat.[^2] [Quis aute iure reprehenderit][Link] in voluptate velit esse cillum dolore eu fugiat nulla pariatur. `Excepteur` sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
[![Pico Logo](data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MDAiIGhlaWdodD0iNDAwIiB2aWV3Qm94PSIwIDAgNDAwIDQwMCI+PHBhdGggZD0ibTI5OC40IDE5NC43cTAtMTQuMTUtLjgtMzEuMmwtLjg1LTE0LjI1aC01MS4wNXY4OS45NWw4IDEuMXE5LjYgMS4wNSAxNy42IDEuMDUgNy45NSAwIDE3LjUtMS4wNSA0LjgtLjU1IDcuOTUtMS4xIDEuNjUtMjIuMiAxLjY1LTQ0LjVtLTY5Ljc1LTQ1LjhoLTQ5LjN2MTgyLjQ1bDcuNy44NXE5LjMuOCAxNyAuOCAxMi4zIDAgMjQuNi0xLjY1eiIgZmlsbD0iIzJlYWU5YiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTM4Ljg1IC00MC45NSkiLz48L3N2Zz4K)](%base_url% "Pico Logo") {.image .small .float-right}
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Headings
--------
# h1
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
## h2
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
### h3
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
#### h4
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
##### h5
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
###### h6
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Horizontal line
---------------
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
---
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
List
----
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
* Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
2. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
3. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
* Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum.
- Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
- Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
1. Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
2. At vero eos et accusam et justo duo dolores et ea rebum.
1. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet
2. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua.
3. At vero eos et accusam et justo duo dolores et ea rebum.
Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, At accusam aliquyam diam diam dolore dolores duo eirmod eos erat, et nonumy sed tempor et et invidunt justo labore Stet clita ea et gubergren, kasd magna no rebum. sanctus sea sed takimata ut vero voluptua. est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat.
Definition list
---------------
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Duis autem
: Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Lorem ipsum dolor sit amet
: Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam
: Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
: Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi.
Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
Blockquote
----------
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
> Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse
> molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero
> eros et accumsan et iusto odio dignissim qui blandit praesent luptatum
> zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum
> dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod
> tincidunt ut laoreet dolore magna aliquam erat volutpat.
>
> > Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit
> > lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure
> > dolor in hendrerit in vulputate velit esse molestie consequat, vel illum
> > dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio
> > dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te
> > feugait nulla facilisi.
>
> Nam liber tempor cum soluta nobis eleifend option congue nihil imperdiet
> doming id quod mazim placerat facer possim assum. Lorem ipsum dolor sit amet,
> consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut
> laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam,
> quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex
> ea commodo consequat.
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
Code block
----------
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
```
<!DOCTYPE html>
<html>
<head>
<title>This is a title</title>
</head>
<body>
<p>Hello world!</p>
</body>
</html>
```
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Table
-----
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Lorem ipsum | Duis autem vel eum | Ut wisi enim ad minim veniam
----------- | ------------------ | ----------------------------
**Duis autem vel eum iriure dolor** in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. | *Lorem ipsum dolor sit amet,* consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. | ~~Ut wisi enim ad minim veniam,~~ quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.
[Duis autem vel eum iriure dolor][Link] in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. | `Nam liber tempor` cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. | Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat. | | Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis.
At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum.
Forms
-----
Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
<fieldset>
<legend>Legend</legend>
<label>Label</label>
<input type="checkbox"/>
<input type="checkbox" checked="checked"/>
<input type="radio"/>
<input type="radio" checked="checked"/><br/>
<input type="text" value="Lorem ipsum"/>
<input type="password" value="Ut enim"/><br/>
<input type="submit" value="Submit"/>
<input type="reset" value="Reset"/>
<input type="button" value="Button (Input)"/>
<button>Button</button><br/>
<textarea>Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua<br/>.</textarea><br/>
<select>
<option>Lorem ipsum</option>
<option>Ut enim</option>
</select><br/>
<select multiple="multiple">
<option>Lorem ipsum</option>
<option selected="selected">Ut enim</option>
<option>Quis aute iure</option>
<option>Excepteur sint</option>
</select>
</fieldset>
Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.
*[Lorem ipsum]: Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua.
[Link]: %base_url% "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat."
[^1]: Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
[^2]: Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

2
content/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# This directory is meant to be empty
*

View file

@ -1,77 +0,0 @@
/*
Title: Welcome
Description: This description will go in the meta description tag
*/
Welcome to Pico
===============
Congratulations you have successfully installed [Pico](http://pico.dev7studios.com). Pico is a stupidly simple, blazing fast, flat file CMS.
Creating Content
----------------
Pico is a flat file CMS, this means there is no administration backend and database to deal with. You simply create `.txt` files in the "content"
folder and that becomes a page. For example this file is called `index.txt` and is shown as the main landing page.
If you created folder within the content folder (e.g. `content/sub`) and put an `index.txt` inside it, you can access that folder at the URL
`http://yousite.com/sub`. If you want another page within the sub folder, simply create a text file with the corresponding name (e.g. `content/sub/page.txt`)
and will be able to access it from the URL `http://yousite.com/sub/page`. Below we've shown some examples of content locations and their corresponing URL's:
<table>
<thead>
<tr><th>Physical Location</th><th>URL</th></tr>
</thead>
<tbody>
<tr><td>content/index.txt</td><td>/</td></tr>
<tr><td>content/sub.txt</td><td>/sub</td></tr>
<tr><td>content/sub/index.txt</td><td>/sub (same as above)</td></tr>
<tr><td>content/sub/page.txt</td><td>/sub/page</td></tr>
<tr><td>content/a/very/long/url.txt</td><td>/a/very/long/url</td></tr>
</tbody>
</table>
If a file cannot be found, the file `content/404.txt` will be shown.
Text File Markup
----------------
Text files are marked up using [Markdown](http://daringfireball.net/projects/markdown/syntax). 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:
/ *
Title: Welcome
Description: This description will go in the meta description tag
Robots: noindex,nofollow
*/
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:
* &#37;base_url&#37; - The URL to your Pico site
Themes
------
You can create themes for your Pico installation and 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.php to 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:
* `{{ config }}` - Conatins the values you set in config.php (e.g. `{{ config.theme }}` = "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 direcotry
* `{{ theme_url }}` - The URL to the Pico active theme direcotry
* `{{ site_title }}` - Shortcut to the site title (defined in config.php)
* `{{ meta }}` - Contains the meta values from the current page (e.g. `{{ meta.title }}`, `{{ meta.description }}`, `{{ meta.robots }}`)
* `{{ content }}` - The content of the current page (after it has been processed through Markdown)
Config
------
You can override the default Pico settings (and add your own custom settings) by editing config.php in the root Pico directory. The config.php file
list all of the settings and their defaults. To override a setting simply uncomment it in config.php and set your custom value.

View file

@ -1,6 +0,0 @@
/*
Title: Sub Page Index
*/
This is a Sub Page Index
========================

View file

@ -1,6 +0,0 @@
/*
Title: Sub Page
*/
This is a Sub Page
==================

View file

@ -1,14 +1,40 @@
<?php
<?php // @codingStandardsIgnoreFile
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/index.php>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
define('ROOT_DIR', realpath(dirname(__FILE__)) .'/');
define('CONTENT_DIR', ROOT_DIR .'content/');
define('LIB_DIR', ROOT_DIR .'lib/');
define('THEMES_DIR', ROOT_DIR .'themes/');
define('CACHE_DIR', LIB_DIR .'cache/');
// load dependencies
if (is_file(__DIR__ . '/vendor/autoload.php')) {
// composer root package
require_once(__DIR__ . '/vendor/autoload.php');
} elseif (is_file(__DIR__ . '/../../../vendor/autoload.php')) {
// composer dependency package
require_once(__DIR__ . '/../../../vendor/autoload.php');
} else {
die(
"Cannot find 'vendor/autoload.php'. If you're using a composer-based Pico install, run `composer install`. "
. "If you're rather trying to use one of Pico's pre-built release packages, make sure to download Pico's "
. "latest release package named 'pico-release-v*.tar.gz' (don't download a source code package)."
);
}
require(ROOT_DIR .'vendor/autoload.php');
require(LIB_DIR .'markdown.php');
require(LIB_DIR .'pico.php');
$pico = new Pico();
// instance Pico
$pico = new Pico(
__DIR__, // root dir
'config/', // config dir
'plugins/', // plugins dir
'themes/' // themes dir
);
?>
// override configuration?
//$pico->setConfig(array());
// run application
echo $pico->run();

39
index.php.dist Normal file
View file

@ -0,0 +1,39 @@
<?php // @codingStandardsIgnoreFile
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/index.php.dist>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
// check PHP platform requirements
if (PHP_VERSION_ID < 50306) {
die('Pico requires PHP 5.3.6 or above to run');
}
if (!extension_loaded('dom')) {
die("Pico requires the PHP extension 'dom' to run");
}
if (!extension_loaded('mbstring')) {
die("Pico requires the PHP extension 'mbstring' to run");
}
// load dependencies
require_once(__DIR__ . '/vendor/autoload.php');
// instance Pico
$pico = new Pico(
__DIR__, // root dir
'config/', // config dir
'plugins/', // plugins dir
'themes/' // themes dir
);
// override configuration?
//$pico->setConfig(array());
// run application
echo $pico->run();

358
lib/AbstractPicoPlugin.php Normal file
View file

@ -0,0 +1,358 @@
<?php
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/lib/AbstractPicoPlugin.php>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
/**
* Abstract class to extend from when implementing a Pico plugin
*
* Please refer to {@see PicoPluginInterface} for more information about how
* to develop a plugin for Pico.
*
* @see PicoPluginInterface
*
* @author Daniel Rudolf
* @link http://picocms.org
* @license http://opensource.org/licenses/MIT The MIT License
* @version 2.1
*/
abstract class AbstractPicoPlugin implements PicoPluginInterface
{
/**
* Current instance of Pico
*
* @see PicoPluginInterface::getPico()
* @var Pico
*/
protected $pico;
/**
* Boolean indicating if this plugin is enabled (TRUE) or disabled (FALSE)
*
* @see PicoPluginInterface::isEnabled()
* @see PicoPluginInterface::setEnabled()
* @var bool|null
*/
protected $enabled;
/**
* Boolean indicating if this plugin was ever enabled/disabled manually
*
* @see PicoPluginInterface::isStatusChanged()
* @var bool
*/
protected $statusChanged = false;
/**
* Boolean indicating whether this plugin matches Pico's API version
*
* @see AbstractPicoPlugin::checkCompatibility()
* @var bool|null
*/
protected $nativePlugin;
/**
* 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[]|null
*/
protected $dependants;
/**
* Constructs a new instance of a Pico plugin
*
* @param Pico $pico current instance of Pico
*/
public function __construct(Pico $pico)
{
$this->pico = $pico;
}
/**
* {@inheritDoc}
*/
public function handleEvent($eventName, array $params)
{
// plugins can be enabled/disabled using the config
if ($eventName === 'onConfigLoaded') {
$this->configEnabled();
}
if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) {
if (method_exists($this, $eventName)) {
call_user_func_array(array($this, $eventName), $params);
}
}
}
/**
* Enables or disables this plugin depending on Pico's config
*/
protected function configEnabled()
{
$pluginEnabled = $this->getPico()->getConfig(get_called_class() . '.enabled');
if ($pluginEnabled !== null) {
$this->setEnabled($pluginEnabled);
} else {
$pluginEnabled = $this->getPluginConfig('enabled');
if ($pluginEnabled !== null) {
$this->setEnabled($pluginEnabled);
} elseif ($this->enabled) {
$this->setEnabled(true, true, true);
} elseif ($this->enabled === null) {
// make sure dependencies are already fulfilled,
// otherwise the plugin needs to be enabled manually
try {
$this->setEnabled(true, false, true);
} catch (RuntimeException $e) {
$this->enabled = false;
}
}
}
}
/**
* {@inheritDoc}
*/
public function setEnabled($enabled, $recursive = true, $auto = false)
{
$this->statusChanged = (!$this->statusChanged) ? !$auto : true;
$this->enabled = (bool) $enabled;
if ($enabled) {
$this->checkCompatibility();
$this->checkDependencies($recursive);
} else {
$this->checkDependants($recursive);
}
}
/**
* {@inheritDoc}
*/
public function isEnabled()
{
return $this->enabled;
}
/**
* {@inheritDoc}
*/
public function isStatusChanged()
{
return $this->statusChanged;
}
/**
* {@inheritDoc}
*/
public function getPico()
{
return $this->pico;
}
/**
* Returns either the value of the specified plugin config variable or
* the config array
*
* @param string $configName optional name of a config variable
* @param mixed $default optional default value to return when the
* named config variable doesn't exist
*
* @return mixed if no name of a config variable has been supplied, the
* plugin's config array is returned; otherwise it returns either the
* value of the named config variable, or, if the named config variable
* doesn't exist, the provided default value or NULL
*/
public function getPluginConfig($configName = null, $default = null)
{
$pluginConfig = $this->getPico()->getConfig(get_called_class(), array());
if ($configName === null) {
return $pluginConfig;
}
return isset($pluginConfig[$configName]) ? $pluginConfig[$configName] : $default;
}
/**
* Passes all not satisfiable method calls to Pico
*
* @see PicoPluginInterface::getPico()
*
* @deprecated 2.1.0
*
* @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 bool $recursive enable required plugins automatically
*
* @throws RuntimeException thrown when a dependency fails
*/
protected function checkDependencies($recursive)
{
foreach ($this->getDependencies() as $pluginName) {
try {
$plugin = $this->getPico()->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 (($plugin instanceof 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"
);
}
}
}
}
/**
* {@inheritDoc}
*/
public function getDependencies()
{
return (array) $this->dependsOn;
}
/**
* Disables all plugins which depend on this plugin
*
* @see PicoPluginInterface::getDependants()
*
* @param bool $recursive disabled dependant plugins automatically
*
* @throws RuntimeException thrown when a dependency fails
*/
protected function checkDependants($recursive)
{
$dependants = $this->getDependants();
if ($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' : '') . ' '
. "'" . implode("', '", array_keys($dependants)) . "'";
throw new RuntimeException(
"Unable to disable plugin '" . get_called_class() . "': "
. "Required by " . $dependantsList
);
}
}
}
/**
* {@inheritDoc}
*/
public function getDependants()
{
if ($this->dependants === null) {
$this->dependants = array();
foreach ($this->getPico()->getPlugins() as $pluginName => $plugin) {
// only plugins which implement PicoPluginInterface support dependencies
if ($plugin instanceof PicoPluginInterface) {
$dependencies = $plugin->getDependencies();
if (in_array(get_called_class(), $dependencies)) {
$this->dependants[$pluginName] = $plugin;
}
}
}
}
return $this->dependants;
}
/**
* Checks compatibility with Pico's API version
*
* Pico automatically adds a dependency to {@see PicoDeprecated} when the
* plugin's API is older than Pico's API. {@see PicoDeprecated} furthermore
* throws a exception if it can't provide compatibility in such cases.
* However, we still have to decide whether this plugin is compatible to
* newer API versions, what requires some special (version specific)
* precaution and is therefore usually not the case.
*
* @throws RuntimeException thrown when the plugin's and Pico's API aren't
* compatible
*/
protected function checkCompatibility()
{
if ($this->nativePlugin === null) {
$picoClassName = get_class($this->pico);
$picoApiVersion = defined($picoClassName . '::API_VERSION') ? $picoClassName::API_VERSION : 1;
$pluginApiVersion = defined('static::API_VERSION') ? static::API_VERSION : 1;
$this->nativePlugin = ($pluginApiVersion === $picoApiVersion);
if (!$this->nativePlugin && ($pluginApiVersion > $picoApiVersion)) {
throw new RuntimeException(
"Unable to enable plugin '" . get_called_class() . "': The plugin's API (version "
. $pluginApiVersion . ") isn't compatible with Pico's API (version " . $picoApiVersion . ")"
);
}
}
}
}

2791
lib/Pico.php Normal file

File diff suppressed because it is too large Load diff

105
lib/PicoPluginInterface.php Normal file
View file

@ -0,0 +1,105 @@
<?php
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/lib/PicoPluginInterface.php>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
/**
* Common interface for Pico plugins
*
* For a list of supported events see {@see DummyPlugin}; you can use
* {@see DummyPlugin} as template for new plugins. For a list of deprecated
* events see {@see PicoDeprecated}.
*
* If you're developing a new plugin, you MUST both implement this interface
* and define the class constant `API_VERSION`. You SHOULD always use the
* API version of Pico's latest milestone when releasing a plugin. If you're
* developing a new version of an existing plugin, it is strongly recommended
* to update your plugin to use Pico's latest API version.
*
* @author Daniel Rudolf
* @link http://picocms.org
* @license http://opensource.org/licenses/MIT The MIT License
* @version 2.1
*/
interface PicoPluginInterface
{
/**
* Handles a event that was triggered by Pico
*
* @param string $eventName name of the triggered event
* @param array $params passed parameters
*/
public function handleEvent($eventName, array $params);
/**
* Enables or disables this plugin
*
* @see PicoPluginInterface::isEnabled()
* @see PicoPluginInterface::isStatusChanged()
*
* @param bool $enabled enable (TRUE) or disable (FALSE) this plugin
* @param bool $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 bool $auto enable or disable to fulfill a dependency. This
* parameter is optional and defaults to FALSE.
*
* @throws RuntimeException thrown when a dependency fails
*/
public function setEnabled($enabled, $recursive = true, $auto = false);
/**
* Returns a boolean indicating whether this plugin is enabled or not
*
* You musn't rely on the return value when Pico's `onConfigLoaded` event
* wasn't triggered on all plugins yet. This method might even return NULL
* then. The plugin's status might change later.
*
* @see PicoPluginInterface::setEnabled()
*
* @return bool|null plugin is enabled (TRUE) or disabled (FALSE)
*/
public function isEnabled();
/**
* Returns TRUE if the plugin was ever enabled/disabled manually
*
* @see PicoPluginInterface::setEnabled()
*
* @return bool 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 plugin's instance of Pico
*
* @see Pico
*
* @return Pico the plugin's instance of Pico
*/
public function getPico();
}

487
lib/PicoTwigExtension.php Normal file
View file

@ -0,0 +1,487 @@
<?php
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/lib/PicoTwigExtension.php>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
/**
* Pico's Twig extension to implement additional filters
*
* @author Daniel Rudolf
* @link http://picocms.org
* @license http://opensource.org/licenses/MIT The MIT License
* @version 2.1
*/
class PicoTwigExtension extends Twig_Extension
{
/**
* Current instance of Pico
*
* @see PicoTwigExtension::getPico()
* @var Pico
*/
private $pico;
/**
* Constructs a new instance of this Twig extension
*
* @param Pico $pico current instance of Pico
*/
public function __construct(Pico $pico)
{
$this->pico = $pico;
}
/**
* Returns the extensions instance of Pico
*
* @see Pico
*
* @return Pico the extension's instance of Pico
*/
public function getPico()
{
return $this->pico;
}
/**
* Returns the name of the extension
*
* @see Twig_ExtensionInterface::getName()
*
* @return string the extension name
*/
public function getName()
{
return 'PicoTwigExtension';
}
/**
* Returns a list of Pico-specific Twig filters
*
* @see Twig_ExtensionInterface::getFilters()
*
* @return Twig_SimpleFilter[] array of Pico's Twig filters
*/
public function getFilters()
{
return array(
'markdown' => new Twig_SimpleFilter(
'markdown',
array($this, 'markdownFilter'),
array('is_safe' => array('html'))
),
'map' => new Twig_SimpleFilter('map', array($this, 'mapFilter')),
'sort_by' => new Twig_SimpleFilter('sort_by', array($this, 'sortByFilter')),
'link' => new Twig_SimpleFilter('link', array($this->pico, 'getPageUrl')),
'url' => new Twig_SimpleFilter('url', array($this->pico, 'substituteUrl'))
);
}
/**
* Returns a list of Pico-specific Twig functions
*
* @see Twig_ExtensionInterface::getFunctions()
*
* @return Twig_SimpleFunction[] array of Pico's Twig functions
*/
public function getFunctions()
{
return array(
'url_param' => new Twig_SimpleFunction('url_param', array($this, 'urlParamFunction')),
'form_param' => new Twig_SimpleFunction('form_param', array($this, 'formParamFunction')),
'pages' => new Twig_SimpleFunction('pages', array($this, 'pagesFunction'))
);
}
/**
* Parses a markdown string to HTML
*
* This method is registered as the Twig `markdown` filter. You can use it
* to e.g. parse a meta variable (`{{ meta.description|markdown }}`).
* Don't use it to parse the contents of a page, use the `content` filter
* instead, what ensures the proper preparation of the contents.
*
* @see Pico::substituteFileContent()
* @see Pico::parseFileContent()
*
* @param string $markdown markdown to parse
* @param array $meta meta data to use for %meta.*% replacement
* @param bool $singleLine whether to parse just a single line of markup
*
* @return string parsed HTML
*/
public function markdownFilter($markdown, array $meta = array(), $singleLine = false)
{
$markdown = $this->getPico()->substituteFileContent($markdown, $meta);
return $this->getPico()->parseFileContent($markdown, $singleLine);
}
/**
* Returns a array with the values of the given key or key path
*
* This method is registered as the Twig `map` filter. You can use this
* filter to e.g. get all page titles (`{{ pages|map("title") }}`).
*
* @param array|Traversable $var variable to map
* @param mixed $mapKeyPath key to map; either a scalar or a
* array interpreted as key path (i.e. ['foo', 'bar'] will return all
* $item['foo']['bar'] values)
*
* @return array mapped values
*
* @throws Twig_Error_Runtime
*/
public function mapFilter($var, $mapKeyPath)
{
if (!is_array($var) && (!is_object($var) || !($var instanceof Traversable))) {
throw new Twig_Error_Runtime(sprintf(
'The map filter only works with arrays or "Traversable", got "%s"',
is_object($var) ? get_class($var) : gettype($var)
));
}
$result = array();
foreach ($var as $key => $value) {
$mapValue = $this->getKeyOfVar($value, $mapKeyPath);
$result[$key] = ($mapValue !== null) ? $mapValue : $value;
}
return $result;
}
/**
* Sorts an array by one of its keys or a arbitrary deep sub-key
*
* This method is registered as the Twig `sort_by` filter. You can use this
* filter to e.g. sort the pages array by a arbitrary meta value. Calling
* `{{ pages|sort_by([ "meta", "nav" ]) }}` returns all pages sorted by the
* meta value `nav`. The sorting algorithm will never assume equality of
* two values, it will then fall back to the original order. The result is
* always sorted in ascending order, apply Twigs `reverse` filter to
* achieve a descending order.
*
* @param array|Traversable $var variable to sort
* @param mixed $sortKeyPath key to use for sorting; either
* a scalar or a array interpreted as key path (i.e. ['foo', 'bar']
* will sort $var by $item['foo']['bar'])
* @param string $fallback specify what to do with items
* which don't contain the specified sort key; use "bottom" (default)
* to move these items to the end of the sorted array, "top" to rank
* them first, "keep" to keep the original order, or "remove" to remove
* these items
*
* @return array sorted array
*
* @throws Twig_Error_Runtime
*/
public function sortByFilter($var, $sortKeyPath, $fallback = 'bottom')
{
if (is_object($var) && ($var instanceof Traversable)) {
$var = iterator_to_array($var, true);
} elseif (!is_array($var)) {
throw new Twig_Error_Runtime(sprintf(
'The sort_by filter only works with arrays or "Traversable", got "%s"',
is_object($var) ? get_class($var) : gettype($var)
));
}
if (($fallback !== 'top') && ($fallback !== 'bottom') && ($fallback !== 'keep') && ($fallback !== "remove")) {
throw new Twig_Error_Runtime(
'The sort_by filter only supports the "top", "bottom", "keep" and "remove" fallbacks'
);
}
$twigExtension = $this;
$varKeys = array_keys($var);
$removeItems = array();
uksort($var, function ($a, $b) use ($twigExtension, $var, $varKeys, $sortKeyPath, $fallback, &$removeItems) {
$aSortValue = $twigExtension->getKeyOfVar($var[$a], $sortKeyPath);
$aSortValueNull = ($aSortValue === null);
$bSortValue = $twigExtension->getKeyOfVar($var[$b], $sortKeyPath);
$bSortValueNull = ($bSortValue === null);
if (($fallback === 'remove') && ($aSortValueNull || $bSortValueNull)) {
if ($aSortValueNull) {
$removeItems[$a] = $var[$a];
}
if ($bSortValueNull) {
$removeItems[$b] = $var[$b];
}
return ($aSortValueNull - $bSortValueNull);
} elseif ($aSortValueNull xor $bSortValueNull) {
if ($fallback === 'top') {
return ($aSortValueNull - $bSortValueNull) * -1;
} elseif ($fallback === 'bottom') {
return ($aSortValueNull - $bSortValueNull);
}
} elseif (!$aSortValueNull && !$bSortValueNull) {
if ($aSortValue != $bSortValue) {
return ($aSortValue > $bSortValue) ? 1 : -1;
}
}
// never assume equality; fallback to original order
$aIndex = array_search($a, $varKeys);
$bIndex = array_search($b, $varKeys);
return ($aIndex > $bIndex) ? 1 : -1;
});
if ($removeItems) {
$var = array_diff_key($var, $removeItems);
}
return $var;
}
/**
* Returns the value of a variable item specified by a scalar key or a
* arbitrary deep sub-key using a key path
*
* @param array|Traversable|ArrayAccess|object $var base variable
* @param mixed $keyPath scalar key or a
* array interpreted as key path (when passing e.g. ['foo', 'bar'],
* the method will return $var['foo']['bar']) specifying the value
*
* @return mixed the requested value or NULL when the given key or key path
* didn't match
*/
public static function getKeyOfVar($var, $keyPath)
{
if (!$keyPath) {
return null;
} elseif (!is_array($keyPath)) {
$keyPath = array($keyPath);
}
foreach ($keyPath as $key) {
if (is_object($var)) {
if ($var instanceof ArrayAccess) {
// use ArrayAccess, see below
} elseif ($var instanceof Traversable) {
$var = iterator_to_array($var);
} elseif (isset($var->{$key})) {
$var = $var->{$key};
continue;
} elseif (is_callable(array($var, 'get' . ucfirst($key)))) {
try {
$var = call_user_func(array($var, 'get' . ucfirst($key)));
continue;
} catch (BadMethodCallException $e) {
return null;
}
} else {
return null;
}
} elseif (!is_array($var)) {
return null;
}
if (isset($var[$key])) {
$var = $var[$key];
continue;
}
return null;
}
return $var;
}
/**
* Filters a URL GET parameter with a specified filter
*
* The Twig function disallows the use of the `callback` filter.
*
* @see Pico::getUrlParameter()
*
* @param string $name name of the URL GET parameter
* to filter
* @param int|string $filter the filter to apply
* @param mixed|array $options either a associative options
* array to be used by the filter or a scalar default value
* @param int|string|int[]|string[] $flags flags and flag strings to be
* used by the filter
*
* @return mixed either the filtered data, FALSE if the filter fails, or
* NULL if the URL GET parameter doesn't exist and no default value is
* given
*/
public function urlParamFunction($name, $filter = '', $options = null, $flags = null)
{
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
if (!$filter || ($filter === FILTER_CALLBACK)) {
return false;
}
return $this->pico->getUrlParameter($name, $filter, $options, $flags);
}
/**
* Filters a HTTP POST parameter with a specified filter
*
* The Twig function disallows the use of the `callback` filter.
*
* @see Pico::getFormParameter()
*
* @param string $name name of the HTTP POST
* parameter to filter
* @param int|string $filter the filter to apply
* @param mixed|array $options either a associative options
* array to be used by the filter or a scalar default value
* @param int|string|int[]|string[] $flags flags and flag strings to be
* used by the filter
*
* @return mixed either the filtered data, FALSE if the filter fails, or
* NULL if the HTTP POST parameter doesn't exist and no default value
* is given
*/
public function formParamFunction($name, $filter = '', $options = null, $flags = null)
{
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
if (!$filter || ($filter === FILTER_CALLBACK)) {
return false;
}
return $this->pico->getFormParameter($name, $filter, $options, $flags);
}
/**
* Returns all pages within a particular branch of Pico's page tree
*
* This function should be used most of the time when dealing with Pico's
* pages array, as it allows one to easily traverse Pico's pages tree
* ({@see Pico::getPageTree()}) to retrieve a subset of Pico's pages array
* in a very convenient and performant way.
*
* The function's default parameters are `$start = ""`, `$depth = 0`,
* `$depthOffset = 0` and `$offset = 1`. A positive `$offset` is equivalent
* to `$depth = $depth + $offset`, `$depthOffset = $depthOffset + $offset`
* and `$offset = 0`.
*
* Consequently the default `$start = ""`, `$depth = 0`, `$depthOffset = 0`
* and `$offset = 1` is equivalent to `$depth = 1`, `$depthOffset = 1` and
* `$offset = 0`. `$start = ""` instruct the function to start from the
* root node (i.e. the node of Pico's main index page at `index.md`).
* `$depth` tells the function what pages to return. In this example,
* `$depth = 1` matches the start node (i.e. the zeroth generation) and all
* its descendant pages until the first generation (i.e. the start node's
* children). `$depthOffset` instructs the function to exclude some of the
* older generations. `$depthOffset = 1` specifically tells the function
* to exclude the zeroth generation, so that the function returns all of
* Pico's main index page's direct child pages (like `sub/index.md` and
* `page.md`, but not `sub/page.md`) only.
*
* Passing `$depthOffset = -1` only is the same as passing `$start = ""`,
* `$depth = 1`, `$depthOffset = 0` and `$offset = 0`. The only difference
* is that `$depthOffset` won't exclude the zeroth generation, so that the
* function returns Pico's main index page as well as all of its direct
* child pages.
*
* Passing `$depth = 0`, `$depthOffset = -2` and `$offset = 2` is the same
* as passing `$depth = 2`, `$depthOffset = 0` and `$offset = 0`. Both will
* return the zeroth, first and second generation of pages. For Pico's main
* index page this would be `index.md` (0th gen), `sub/index.md` (1st gen),
* `sub/page.md` (2nd gen) and `page.md` (1st gen). If you want to return
* 2nd gen pages only, pass `$offset = 2` only (with implicit `$depth = 0`
* and `$depthOffset = 0` it's the same as `$depth = 2`, `$depthOffset = 2`
* and `$offset = 0`).
*
* Instead of an integer you can also pass `$depth = null`. This is the
* same as passing an infinitely large number as `$depth`, so that this
* function simply returns all descendant pages. Consequently passing
* `$start = ""`, `$depth = null`, `$depthOffset = 0` and `$offset = 0`
* returns Pico's full pages array.
*
* If `$depth` is negative after taking `$offset` into consideration, the
* function will throw a {@see Twig_Error_Runtime} exception, since this
* would simply make no sense and is likely an error. Passing a negative
* `$depthOffset` is equivalent to passing `$depthOffset = 0`.
*
* But what about a negative `$offset`? Passing `$offset = -1` instructs
* the function not to start from the given `$start` node, but its parent
* node. Consequently `$offset = -2` instructs the function to use the
* `$start` node's grandparent node. Obviously this won't make any sense
* for Pico's root node, but just image `$start = "sub/index"`. Passing
* this together with `$offset = -1` is equivalent to `$start = ""` and
* `$offset = 0`.
*
* @param string $start name of the node to start from
* @param int|null $depth return pages until the given maximum depth;
* pass NULL to return all descendant pages; defaults to 0
* @param int $depthOffset start returning pages from the given
* minimum depth; defaults to 0
* @param int $offset ascend (positive) or descend (negative) the
* given number of branches before returning pages; defaults to 1
*
* @return array[] the data of the matched pages
*
* @throws Twig_Error_Runtime
*/
public function pagesFunction($start = '', $depth = 0, $depthOffset = 0, $offset = 1)
{
$start = (string) $start;
if (basename($start) === 'index') {
$start = dirname($start);
}
for (; $offset < 0; $offset++) {
if (in_array($start, array('', '.', '/'), true)) {
$offset = 0;
break;
}
$start = dirname($start);
}
$depth = ($depth !== null) ? $depth + $offset : null;
$depthOffset = $depthOffset + $offset;
if (($depth !== null) && ($depth < 0)) {
throw new Twig_Error_Runtime('The pages function doesn\'t support negative depths');
}
$pageTree = $this->getPico()->getPageTree();
if (in_array($start, array('', '.', '/'), true)) {
if (($depth === null) && ($depthOffset <= 0)) {
return $this->getPico()->getPages();
}
$startNode = isset($pageTree['']['/']) ? $pageTree['']['/'] : null;
} else {
$branch = dirname($start);
$branch = ($branch !== '.') ? $branch : '/';
$node = (($branch !== '/') ? $branch . '/' : '') . basename($start);
$startNode = isset($pageTree[$branch][$node]) ? $pageTree[$branch][$node] : null;
}
if (!$startNode) {
return array();
}
$getPagesClosure = function ($nodes, $depth, $depthOffset) use (&$getPagesClosure) {
$pages = array();
foreach ($nodes as $node) {
if (isset($node['page']) && ($depthOffset <= 0)) {
$pages[$node['page']['id']] = &$node['page'];
}
if (isset($node['children']) && ($depth > 0)) {
$pages += $getPagesClosure($node['children'], $depth - 1, $depthOffset - 1);
}
}
return $pages;
};
return $getPagesClosure(
array($startNode),
($depth !== null) ? $depth : INF,
$depthOffset
);
}
}

View file

@ -1,2 +0,0 @@
*
!.gitignore

File diff suppressed because it is too large Load diff

View file

@ -1,162 +0,0 @@
<?php
/**
* Pico
*
* @author Gilbert Pellegrom
* @link http://pico.dev7studios.com/
* @license http://opensource.org/licenses/MIT
* @version 0.3
*/
class Pico {
/**
* The constructor carries out all the processing in Pico.
* Does URL routing, Markdown processing and Twig processing.
*/
function __construct()
{
// 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), '/');
// Get the file path
if($url) $file = CONTENT_DIR . $url;
else $file = CONTENT_DIR .'index';
// Load the file
if(is_dir($file)) $file = CONTENT_DIR . $url .'/index.txt';
else $file .= '.txt';
if(file_exists($file)) $content = file_get_contents($file);
else {
$content = file_get_contents(CONTENT_DIR .'404.txt');
header($_SERVER['SERVER_PROTOCOL'].' 404 Not Found');
}
$meta = $this->read_file_meta($content);
$content = preg_replace('#/\*.+?\*/#s', '', $content); // Remove comments and meta
$content = $this->parse_content($content);
// Load the settings
$settings = $this->get_config();
$env = array('autoescape' => false);
if($settings['enable_cache']) $env['cache'] = CACHE_DIR;
// Load the theme
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem(THEMES_DIR . $settings['theme']);
$twig = new Twig_Environment($loader, $env);
echo $twig->render('index.html', 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
));
}
/**
* Parses the content using Markdown
*
* @param string $content the raw txt content
* @return string $content the Markdown formatted content
*/
function parse_content($content)
{
$content = str_replace('%base_url%', $this->base_url(), $content);
$content = Markdown($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
*/
function read_file_meta($content)
{
$headers = array(
'title' => 'Title',
'description' => 'Description',
'robots' => 'Robots'
);
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 ] = '';
}
}
return $headers;
}
/**
* Loads the config
*
* @return array $config an array of config values
*/
function get_config()
{
if(!file_exists(ROOT_DIR .'config.php')) return array();
global $config;
require_once(ROOT_DIR .'config.php');
$defaults = array(
'site_title' => 'Pico',
'base_url' => $this->base_url(),
'theme' => 'default',
'enable_cache' => false
);
if(is_array($config)) $config = array_merge($defaults, $config);
else $config = $defaults;
return $config;
}
/**
* Helper function to work out the base URL
*
* @return string the base url
*/
function base_url()
{
global $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
*/
function get_protocol()
{
preg_match("|^HTTP[S]?|is",$_SERVER['SERVER_PROTOCOL'],$m);
return strtolower($m[0]);
}
}
?>

3
plugins/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
# This directory is meant to be empty, except for DummyPlugin.php
*
!DummyPlugin.php

504
plugins/DummyPlugin.php Normal file
View file

@ -0,0 +1,504 @@
<?php
/**
* This file is part of Pico. It's copyrighted by the contributors recorded
* in the version control history of the file, available from the following
* original location:
*
* <https://github.com/picocms/Pico/blob/master/plugins/DummyPlugin.php>
*
* SPDX-License-Identifier: MIT
* License-Filename: LICENSE
*/
/**
* 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 The MIT License
* @version 2.1
*/
class DummyPlugin extends AbstractPicoPlugin
{
/**
* API version used by this plugin
*
* @var int
*/
const API_VERSION = 3;
/**
* This plugin is disabled by default
*
* Usually you should remove this class property (or set it to NULL) to
* leave the decision whether this plugin should be enabled or disabled by
* default up to Pico. If all the plugin's dependenies are fulfilled (see
* {@see DummyPlugin::$dependsOn}), Pico enables the plugin by default.
* Otherwise the plugin is silently disabled.
*
* If this plugin should never be disabled *silently* (e.g. when dealing
* with security-relevant stuff like access control, or similar), set this
* to TRUE. If Pico can't fulfill all the plugin's dependencies, it will
* throw an RuntimeException.
*
* If this plugin rather does some "crazy stuff" a user should really be
* aware of before using it, you can set this to FALSE. The user will then
* have to enable the plugin manually. However, if another plugin depends
* on this plugin, it might get enabled silently nevertheless.
*
* No matter what, the user can always explicitly enable or disable this
* plugin in Pico's config.
*
* @see AbstractPicoPlugin::$enabled
* @var bool|null
*/
protected $enabled = false;
/**
* This plugin depends on ...
*
* If your plugin doesn't depend on any other plugin, remove this class
* property.
*
* @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::loadPlugin()
* @see Pico::getPlugin()
* @see Pico::getPlugins()
*
* @param object[] $plugins loaded plugin instances
*/
public function onPluginsLoaded(array $plugins)
{
// your code
}
/**
* Triggered when Pico manually loads a plugin
*
* @see Pico::loadPlugin()
* @see Pico::getPlugin()
* @see Pico::getPlugins()
*
* @param object $plugin loaded plugin instance
*/
public function onPluginManuallyLoaded($plugin)
{
// your code
}
/**
* Triggered after Pico has read its configuration
*
* @see Pico::getConfig()
* @see Pico::getBaseUrl()
* @see Pico::isUrlRewritingEnabled()
*
* @param array &$config array of config variables
*/
public function onConfigLoaded(array &$config)
{
// your code
}
/**
* Triggered before Pico loads its theme
*
* @see Pico::loadTheme()
* @see DummyPlugin::onThemeLoaded()
*
* @param string &$theme name of current theme
*/
public function onThemeLoading(&$theme)
{
// your code
}
/**
* Triggered after Pico loaded its theme
*
* @see DummyPlugin::onThemeLoading()
* @see Pico::getTheme()
* @see Pico::getThemeApiVersion()
*
* @param string $theme name of current theme
* @param int $themeApiVersion API version of the theme
* @param array &$themeConfig config array of the theme
*/
public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig)
{
// your code
}
/**
* Triggered after Pico has evaluated the request URL
*
* @see Pico::getRequestUrl()
*
* @param string &$url part of the URL describing the requested contents
*/
public function onRequestUrl(&$url)
{
// your code
}
/**
* Triggered after Pico has discovered the content file to serve
*
* @see Pico::resolveFilePath()
* @see Pico::getRequestFile()
*
* @param string &$file absolute path to the content file to serve
*/
public function onRequestFile(&$file)
{
// your code
}
/**
* Triggered before Pico reads the contents of the file to serve
*
* @see Pico::loadFileContent()
* @see DummyPlugin::onContentLoaded()
*/
public function onContentLoading()
{
// your code
}
/**
* Triggered before Pico reads the contents of a 404 file
*
* @see Pico::load404Content()
* @see DummyPlugin::on404ContentLoaded()
*/
public function on404ContentLoading()
{
// your code
}
/**
* Triggered after Pico has read the contents of the 404 file
*
* @see DummyPlugin::on404ContentLoading()
* @see Pico::getRawContent()
* @see Pico::is404Content()
*
* @param string &$rawContent raw file contents
*/
public function on404ContentLoaded(&$rawContent)
{
// your code
}
/**
* Triggered after Pico has read the contents of the file to serve
*
* If Pico serves a 404 file, this event is triggered with the raw contents
* of said 404 file. Use {@see Pico::is404Content()} to check for this
* case when necessary.
*
* @see DummyPlugin::onContentLoading()
* @see Pico::getRawContent()
* @see Pico::is404Content()
*
* @param string &$rawContent raw file contents
*/
public function onContentLoaded(&$rawContent)
{
// your code
}
/**
* Triggered before Pico parses the meta header
*
* @see Pico::parseFileMeta()
* @see DummyPlugin::onMetaParsed()
*/
public function onMetaParsing()
{
// your code
}
/**
* Triggered after Pico has parsed the meta header
*
* @see DummyPlugin::onMetaParsing()
* @see Pico::getFileMeta()
*
* @param string[] &$meta parsed meta data
*/
public function onMetaParsed(array &$meta)
{
// your code
}
/**
* Triggered before Pico parses the pages content
*
* @see Pico::prepareFileContent()
* @see Pico::substituteFileContent()
* @see DummyPlugin::onContentPrepared()
* @see DummyPlugin::onContentParsed()
*/
public function onContentParsing()
{
// your code
}
/**
* Triggered after Pico has prepared the raw file contents for parsing
*
* @see DummyPlugin::onContentParsing()
* @see Pico::parseFileContent()
* @see DummyPlugin::onContentParsed()
*
* @param string &$markdown Markdown contents of the requested page
*/
public function onContentPrepared(&$markdown)
{
// your code
}
/**
* Triggered after Pico has parsed the contents of the file to serve
*
* @see DummyPlugin::onContentParsing()
* @see DummyPlugin::onContentPrepared()
* @see Pico::getFileContent()
*
* @param string &$content parsed contents (HTML) of the requested page
*/
public function onContentParsed(&$content)
{
// your code
}
/**
* Triggered before Pico reads all known pages
*
* @see DummyPlugin::onPagesDiscovered()
* @see DummyPlugin::onPagesLoaded()
*/
public function onPagesLoading()
{
// your code
}
/**
* Triggered before Pico loads a single page
*
* Set the `$skipFile` parameter to TRUE to remove this page from the pages
* array. Pico usually passes NULL by default, unless it is a conflicting
* page (i.e. `content/sub.md`, but there's also a `content/sub/index.md`),
* then it passes TRUE. Don't change this value incautiously if it isn't
* NULL! Someone likely set it to TRUE or FALSE on purpose...
*
* @see DummyPlugin::onSinglePageContent()
* @see DummyPlugin::onSinglePageLoaded()
*
* @param string $id relative path to the content file
* @param bool|null $skipPage set this to TRUE to remove this page from the
* pages array, otherwise leave it unchanged
*/
public function onSinglePageLoading($id, &$skipPage)
{
// your code
}
/**
* Triggered when Pico loads the raw contents of a single page
*
* Please note that this event isn't triggered when the currently processed
* page is the requested page. The reason for this exception is that the
* raw contents of this page were loaded already.
*
* @see DummyPlugin::onSinglePageLoading()
* @see DummyPlugin::onSinglePageLoaded()
*
* @param string $id relative path to the content file
* @param string &$rawContent raw file contents
*/
public function onSinglePageContent($id, &$rawContent)
{
// your code
}
/**
* Triggered when Pico loads a single page
*
* Please refer to {@see Pico::readPages()} for information about the
* structure of a single page's data.
*
* @see DummyPlugin::onSinglePageLoading()
* @see DummyPlugin::onSinglePageContent()
*
* @param array &$pageData data of the loaded page
*/
public function onSinglePageLoaded(array &$pageData)
{
// your code
}
/**
* Triggered after Pico has discovered all known pages
*
* Pico's pages array isn't sorted until the `onPagesLoaded` event is
* triggered. Please refer to {@see Pico::readPages()} for information
* about the structure of Pico's pages array and the structure of a single
* page's data.
*
* @see DummyPlugin::onPagesLoading()
* @see DummyPlugin::onPagesLoaded()
*
* @param array[] &$pages list of all known pages
*/
public function onPagesDiscovered(array &$pages)
{
// your code
}
/**
* Triggered after Pico has sorted the pages array
*
* Please refer to {@see Pico::readPages()} for information about the
* structure of Pico's pages array and the structure of a single page's
* data.
*
* @see DummyPlugin::onPagesLoading()
* @see DummyPlugin::onPagesDiscovered()
* @see Pico::getPages()
*
* @param array[] &$pages sorted list of all known pages
*/
public function onPagesLoaded(array &$pages)
{
// your code
}
/**
* Triggered when Pico discovered the current, previous and next pages
*
* If Pico isn't serving a regular page, but a plugin's virtual page, there
* will neither be a current, nor previous or next pages. Please refer to
* {@see Pico::readPages()} for information about the structure of a single
* page's data.
*
* @see Pico::getCurrentPage()
* @see Pico::getPreviousPage()
* @see Pico::getNextPage()
*
* @param array|null &$currentPage data of the page being served
* @param array|null &$previousPage data of the previous page
* @param array|null &$nextPage data of the next page
*/
public function onCurrentPageDiscovered(
array &$currentPage = null,
array &$previousPage = null,
array &$nextPage = null
) {
// your code
}
/**
* Triggered after Pico built the page tree
*
* Please refer to {@see Pico::buildPageTree()} for information about
* the structure of Pico's page tree array.
*
* @see Pico::getPageTree()
*
* @param array &$pageTree page tree
*/
public function onPageTreeBuilt(array &$pageTree)
{
// your code
}
/**
* Triggered before Pico renders the page
*
* @see DummyPlugin::onPageRendered()
*
* @param string &$templateName file name of the template
* @param array &$twigVariables template variables
*/
public function onPageRendering(&$templateName, array &$twigVariables)
{
// your code
}
/**
* Triggered after Pico has rendered the page
*
* @see DummyPlugin::onPageRendering()
*
* @param string &$output contents which will be sent to the user
*/
public function onPageRendered(&$output)
{
// 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
* key specifies the YAML key to search for, the array value is later
* used to access the found value
*/
public function onMetaHeaders(array &$headers)
{
// your code
}
/**
* Triggered when Pico registers the YAML parser
*
* @see Pico::getYamlParser()
*
* @param \Symfony\Component\Yaml\Parser &$yamlParser YAML parser instance
*/
public function onYamlParserRegistered(\Symfony\Component\Yaml\Parser &$yamlParser)
{
// your code
}
/**
* Triggered when Pico registers the Parsedown parser
*
* @see Pico::getParsedown()
*
* @param Parsedown &$parsedown Parsedown instance
*/
public function onParsedownRegistered(Parsedown &$parsedown)
{
// your code
}
/**
* Triggered when Pico registers the twig template engine
*
* @see Pico::getTwig()
*
* @param Twig_Environment &$twig Twig instance
*/
public function onTwigRegistered(Twig_Environment &$twig)
{
// your code
}
}

2
themes/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
# This directory is meant to be empty
*

View file

@ -1,23 +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="{{ theme_url }}/style.css" type="text/css" media="screen" />
<!--[if IE]>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<script type="text/javascript" src="https://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<script src="{{ theme_url }}/scripts/modernizr-1.7.min.js"></script>
</head>
<body>
{{ content }}
</body>
</html>

File diff suppressed because one or more lines are too long

View file

@ -1,170 +0,0 @@
/*=================================*/
/* Pico Default Theme
/* By: Gilbert Pellegrom
/* http: //dev7studios.com
/*=================================*/
/*====================*/
/*=== Reset Styles ===*/
/*====================*/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, font, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td {
margin: 0;
padding: 0;
border: 0;
outline: 0;
font-weight: inherit;
font-style: inherit;
font-size: 100%;
font-family: inherit;
vertical-align: baseline;
}
body {
line-height: 1;
color: black;
background: white;
}
table {
border-collapse: separate;
border-spacing: 0;
}
caption, th, td {
text-align: left;
font-weight: normal;
}
blockquote:before, blockquote:after,
q:before, q:after {
content: "";
}
blockquote, q {
quotes: "" "";
}
/* HTML5 tags */
header, section, footer,
aside, nav, article, figure {
display: block;
}
/*===================*/
/*=== Main Styles ===*/
/*===================*/
body {
font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
color: #000;
background: #fff;
padding: 40px;
}
a, a:visited {
color: blue;
text-decoration: none;
border-bottom: 1px solid blue;
}
a:hover, a:active {
color: #000;
text-decoration: none;
}
h1, h2, h3, h4, h5, h6 {
line-height: 1.2;
margin-bottom: 0.6em;
}
h1 {
font-size: 2.2em;
}
h2 {
font-size: 1.9em;
}
h3 {
font-size: 1.7em;
margin-top: 2em;
}
h4 {
font-size: 1.5em;
}
h5 {
font-size: 1.3em;
}
h6 {
font-size: 1.2em;
}
p {
margin-bottom: 1em;
}
ol, ul {
padding-left: 30px;
margin-bottom: 1em;
}
b, strong {
font-weight: bold;
}
i, em {
font-style: italic;
}
u {
text-decoration: underline;
}
abbr, acronym {
cursor: help;
border-bottom: .1em dotted;
}
td, td img { vertical-align: top; }
sub { vertical-align: sub; font-size: smaller; }
sup { vertical-align: super; font-size: smaller; }
code {
font-family: Courier,"Courier New",Monaco,Tahoma;
background: #eee;
color: #000;
padding: 0px 2px;
}
pre {
background: #eee;
padding: 20px;
margin-bottom: 1em;
}
blockquote {
font-style: italic;
margin: 0 0 1em 15px;
padding-left: 10px;
border-left: 5px solid #999;
}
/* hand cursor on clickable input elements */
label, input[type=button], input[type=submit], button { cursor: pointer; }
/* make buttons play nice in IE:
www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ */
button { width: auto; overflow: visible; }
table { margin-bottom: 1em; }
th {
font-weight: bold;
padding: 0 5px;
}
td { padding: 0 5px; }
/*====================*/
/*=== Other Styles ===*/
/*====================*/
/* Clearfix */
.cf:before,
.cf:after {
content:"";
display:table;
}
.cf:after {
clear:both;
}
/* For IE 6/7 (trigger hasLayout) */
.cf {
zoom:1;
}

7
vendor/autoload.php vendored
View file

@ -1,7 +0,0 @@
<?php
// autoload.php generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit5115ee54a7a3f173d564b433db6d791a::getLoader();

View file

@ -1,240 +0,0 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0 class loader
*
* See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ClassLoader
{
private $prefixes = array();
private $fallbackDirs = array();
private $useIncludePath = false;
private $classMap = array();
public function getPrefixes()
{
return $this->prefixes;
}
public function getFallbackDirs()
{
return $this->fallbackDirs;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of classes, merging with any others previously set.
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
* @param bool $prepend Prepend the location(s)
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirs = array_merge(
(array) $paths,
$this->fallbackDirs
);
} else {
$this->fallbackDirs = array_merge(
$this->fallbackDirs,
(array) $paths
);
}
return;
}
if (!isset($this->prefixes[$prefix])) {
$this->prefixes[$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixes[$prefix] = array_merge(
(array) $paths,
$this->prefixes[$prefix]
);
} else {
$this->prefixes[$prefix] = array_merge(
$this->prefixes[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of classes, replacing any others previously set.
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirs = (array) $paths;
return;
}
$this->prefixes[$prefix] = (array) $paths;
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
include $file;
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR;
$className = substr($class, $pos + 1);
} else {
// PEAR-like class name
$classPath = null;
$className = $class;
}
$classPath .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';
foreach ($this->prefixes as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
}
}
}
}
foreach ($this->fallbackDirs as $dir) {
if (file_exists($dir . DIRECTORY_SEPARATOR . $classPath)) {
return $dir . DIRECTORY_SEPARATOR . $classPath;
}
}
if ($this->useIncludePath && $file = stream_resolve_include_path($classPath)) {
return $file;
}
return $this->classMap[$class] = false;
}
}

View file

@ -1,9 +0,0 @@
<?php
// autoload_classmap.php generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);

View file

@ -1,10 +0,0 @@
<?php
// autoload_namespaces.php generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Twig_' => $vendorDir . '/twig/twig/lib',
);

View file

@ -1,43 +0,0 @@
<?php
// autoload_real.php generated by Composer
class ComposerAutoloaderInit5115ee54a7a3f173d564b433db6d791a
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit5115ee54a7a3f173d564b433db6d791a', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit5115ee54a7a3f173d564b433db6d791a', 'loadClassLoader'));
$vendorDir = dirname(__DIR__);
$baseDir = dirname($vendorDir);
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->add($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
return $loader;
}
}

View file

@ -1,53 +0,0 @@
[
{
"name": "twig/twig",
"version": "v1.12.3",
"version_normalized": "1.12.3.0",
"source": {
"type": "git",
"url": "https://github.com/fabpot/Twig.git",
"reference": "v1.12.3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fabpot/Twig/zipball/v1.12.3",
"reference": "v1.12.3",
"shasum": ""
},
"require": {
"php": ">=5.2.4"
},
"time": "2013-04-08 12:40:11",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Twig_": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com"
}
],
"description": "Twig, the flexible, fast, and secure template language for PHP",
"homepage": "http://twig.sensiolabs.org",
"keywords": [
"templating"
]
}
]

View file

@ -1,18 +0,0 @@
; top-most EditorConfig file
root = true
; Unix-style newlines
[*]
end_of_line = LF
[*.php]
indent_style = space
indent_size = 4
[*.test]
indent_style = space
indent_size = 4
[*.rst]
indent_style = space
indent_size = 4

View file

@ -1,2 +0,0 @@
/ext/twig/autom4te.cache/

View file

@ -1,14 +0,0 @@
language: php
php:
- 5.2
- 5.3
- 5.4
env:
- TWIG_EXT=no
- TWIG_EXT=yes
before_script:
- if [ "$TWIG_EXT" == "yes" ]; then sh -c "cd ext/twig && phpize && ./configure --enable-twig && make && sudo make install"; fi
- if [ "$TWIG_EXT" == "yes" ]; then echo "extension=twig.so" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"`; fi

View file

@ -1,9 +0,0 @@
Twig is written and maintained by the Twig Team:
Lead Developer:
- Fabien Potencier <fabien.potencier@symfony-project.org>
Project Founder:
- Armin Ronacher <armin.ronacher@active-4.com>

View file

@ -1,615 +0,0 @@
* 1.12.3 (2013-04-08)
* fixed a security issue in the filesystem loader where it was possible to include a template one
level above the configured path
* fixed fatal error that should be an exception when adding a filter/function/test too late
* added a batch filter
* added support for encoding an array as query string in the url_encode filter
* 1.12.2 (2013-02-09)
* fixed the timezone used by the date filter and function when the given date contains a timezone (like 2010-01-28T15:00:00+02:00)
* fixed globals when getGlobals is called early on
* added the first and last filter
* 1.12.1 (2013-01-15)
* added support for object instances as the second argument of the constant function
* relaxed globals management to avoid a BC break
* added support for {{ some_string[:2] }}
* 1.12.0 (2013-01-08)
* added verbatim as an alias for the raw tag to avoid confusion with the raw filter
* fixed registration of tests and functions as anonymous functions
* fixed globals management
* 1.12.0-RC1 (2012-12-29)
* added an include function (does the same as the include tag but in a more flexible way)
* added the ability to use any PHP callable to define filters, functions, and tests
* added a syntax error when using a loop variable that is not defined
* added the ability to set default values for macro arguments
* added support for named arguments for filters, tests, and functions
* moved filters/functions/tests syntax errors to the parser
* added support for extended ternary operator syntaxes
* 1.11.1 (2012-11-11)
* fixed debug info line numbering (was off by 2)
* fixed escaping when calling a macro inside another one (regression introduced in 1.9.1)
* optimized variable access on PHP 5.4
* fixed a crash of the C extension when an exception was thrown from a macro called without being imported (using _self.XXX)
* 1.11.0 (2012-11-07)
* fixed macro compilation when a variable name is a PHP reserved keyword
* changed the date filter behavior to always apply the default timezone, except if false is passed as the timezone
* fixed bitwise operator precedences
* added the template_from_string function
* fixed default timezone usage for the date function
* optimized the way Twig exceptions are managed (to make them faster)
* added Twig_ExistsLoaderInterface (implementing this interface in your loader make the chain loader much faster)
* 1.10.3 (2012-10-19)
* fixed wrong template location in some error messages
* reverted a BC break introduced in 1.10.2
* added a split filter
* 1.10.2 (2012-10-15)
* fixed macro calls on PHP 5.4
* 1.10.1 (2012-10-15)
* made a speed optimization to macro calls when imported via the "import" tag
* fixed C extension compilation on Windows
* fixed a segfault in the C extension when using DateTime objects
* 1.10.0 (2012-09-28)
* extracted functional tests framework to make it reusable for third-party extensions
* added namespaced templates support in Twig_Loader_Filesystem
* added Twig_Loader_Filesystem::prependPath()
* fixed an error when a token parser pass a closure as a test to the subparse() method
* 1.9.2 (2012-08-25)
* fixed the in operator for objects that contain circular references
* fixed the C extension when accessing a public property of an object implementing the \ArrayAccess interface
* 1.9.1 (2012-07-22)
* optimized macro calls when auto-escaping is on
* fixed wrong parent class for Twig_Function_Node
* made Twig_Loader_Chain more explicit about problems
* 1.9.0 (2012-07-13)
* made the parsing independent of the template loaders
* fixed exception trace when an error occurs when rendering a child template
* added escaping strategies for CSS, URL, and HTML attributes
* fixed nested embed tag calls
* added the date_modify filter
* 1.8.3 (2012-06-17)
* fixed paths in the filesystem loader when passing a path that ends with a slash or a backslash
* fixed escaping when a project defines a function named html or js
* fixed chmod mode to apply the umask correctly
* 1.8.2 (2012-05-30)
* added the abs filter
* fixed a regression when using a number in template attributes
* fixed compiler when mbstring.func_overload is set to 2
* fixed DateTimeZone support in date filter
* 1.8.1 (2012-05-17)
* fixed a regression when dealing with SimpleXMLElement instances in templates
* fixed "is_safe" value for the "dump" function when "html_errors" is not defined in php.ini
* switched to use mbstring whenever possible instead of iconv (you might need to update your encoding as mbstring and iconv encoding names sometimes differ)
* 1.8.0 (2012-05-08)
* enforced interface when adding tests, filters, functions, and node visitors from extensions
* fixed a side-effect of the date filter where the timezone might be changed
* simplified usage of the autoescape tag; the only (optional) argument is now the escaping strategy or false (with a BC layer)
* added a way to dynamically change the auto-escaping strategy according to the template "filename"
* changed the autoescape option to also accept a supported escaping strategy (for BC, true is equivalent to html)
* added an embed tag
* 1.7.0 (2012-04-24)
* fixed a PHP warning when using CIFS
* fixed template line number in some exceptions
* added an iterable test
* added an error when defining two blocks with the same name in a template
* added the preserves_safety option for filters
* fixed a PHP notice when trying to access a key on a non-object/array variable
* enhanced error reporting when the template file is an instance of SplFileInfo
* added Twig_Environment::mergeGlobals()
* added compilation checks to avoid misuses of the sandbox tag
* fixed filesystem loader freshness logic for high traffic websites
* fixed random function when charset is null
* 1.6.5 (2012-04-11)
* fixed a regression when a template only extends another one without defining any blocks
* 1.6.4 (2012-04-02)
* fixed PHP notice in Twig_Error::guessTemplateLine() introduced in 1.6.3
* fixed performance when compiling large files
* optimized parent template creation when the template does not use dynamic inheritance
* 1.6.3 (2012-03-22)
* fixed usage of Z_ADDREF_P for PHP 5.2 in the C extension
* fixed compilation of numeric values used in templates when using a locale where the decimal separator is not a dot
* made the strategy used to guess the real template file name and line number in exception messages much faster and more accurate
* 1.6.2 (2012-03-18)
* fixed sandbox mode when used with inheritance
* added preserveKeys support for the slice filter
* fixed the date filter when a DateTime instance is passed with a specific timezone
* added a trim filter
* 1.6.1 (2012-02-29)
* fixed Twig C extension
* removed the creation of Twig_Markup instances when not needed
* added a way to set the default global timezone for dates
* fixed the slice filter on strings when the length is not specified
* fixed the creation of the cache directory in case of a race condition
* 1.6.0 (2012-02-04)
* fixed raw blocks when used with the whitespace trim option
* made a speed optimization to macro calls when imported via the "from" tag
* fixed globals, parsers, visitors, filters, tests, and functions management in Twig_Environment when a new one or new extension is added
* fixed the attribute function when passing arguments
* added slice notation support for the [] operator (syntactic sugar for the slice operator)
* added a slice filter
* added string support for the reverse filter
* fixed the empty test and the length filter for Twig_Markup instances
* added a date function to ease date comparison
* fixed unary operators precedence
* added recursive parsing support in the parser
* added string and integer handling for the random function
* 1.5.1 (2012-01-05)
* fixed a regression when parsing strings
* 1.5.0 (2012-01-04)
* added Traversable objects support for the join filter
* 1.5.0-RC2 (2011-12-30)
* added a way to set the default global date interval format
* fixed the date filter for DateInterval instances (setTimezone() does not exist for them)
* refactored Twig_Template::display() to ease its extension
* added a number_format filter
* 1.5.0-RC1 (2011-12-26)
* removed the need to quote hash keys
* allowed hash keys to be any expression
* added a do tag
* added a flush tag
* added support for dynamically named filters and functions
* added a dump function to help debugging templates
* added a nl2br filter
* added a random function
* added a way to change the default format for the date filter
* fixed the lexer when an operator ending with a letter ends a line
* added string interpolation support
* enhanced exceptions for unknown filters, functions, tests, and tags
* 1.4.0 (2011-12-07)
* fixed lexer when using big numbers (> PHP_INT_MAX)
* added missing preserveKeys argument to the reverse filter
* fixed macros containing filter tag calls
* 1.4.0-RC2 (2011-11-27)
* removed usage of Reflection in Twig_Template::getAttribute()
* added a C extension that can optionally replace Twig_Template::getAttribute()
* added negative timestamp support to the date filter
* 1.4.0-RC1 (2011-11-20)
* optimized variable access when using PHP 5.4
* changed the precedence of the .. operator to be more consistent with languages that implements such a feature like Ruby
* added an Exception to Twig_Loader_Array::isFresh() method when the template does not exist to be consistent with other loaders
* added Twig_Function_Node to allow more complex functions to have their own Node class
* added Twig_Filter_Node to allow more complex filters to have their own Node class
* added Twig_Test_Node to allow more complex tests to have their own Node class
* added a better error message when a template is empty but contain a BOM
* fixed "in" operator for empty strings
* fixed the "defined" test and the "default" filter (now works with more than one call (foo.bar.foo) and for both values of the strict_variables option)
* changed the way extensions are loaded (addFilter/addFunction/addGlobal/addTest/addNodeVisitor/addTokenParser/addExtension can now be called in any order)
* added Twig_Environment::display()
* made the escape filter smarter when the encoding is not supported by PHP
* added a convert_encoding filter
* moved all node manipulations outside the compile() Node method
* made several speed optimizations
* 1.3.0 (2011-10-08)
no changes
* 1.3.0-RC1 (2011-10-04)
* added an optimization for the parent() function
* added cache reloading when auto_reload is true and an extension has been modified
* added the possibility to force the escaping of a string already marked as safe (instance of Twig_Markup)
* allowed empty templates to be used as traits
* added traits support for the "parent" function
* 1.2.0 (2011-09-13)
no changes
* 1.2.0-RC1 (2011-09-10)
* enhanced the exception when a tag remains unclosed
* added support for empty Countable objects for the "empty" test
* fixed algorithm that determines if a template using inheritance is valid (no output between block definitions)
* added better support for encoding problems when escaping a string (available as of PHP 5.4)
* added a way to ignore a missing template when using the "include" tag ({% include "foo" ignore missing %})
* added support for an array of templates to the "include" and "extends" tags ({% include ['foo', 'bar'] %})
* added support for bitwise operators in expressions
* added the "attribute" function to allow getting dynamic attributes on variables
* added Twig_Loader_Chain
* added Twig_Loader_Array::setTemplate()
* added an optimization for the set tag when used to capture a large chunk of static text
* changed name regex to match PHP one "[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*" (works for blocks, tags, functions, filters, and macros)
* removed the possibility to use the "extends" tag from a block
* added "if" modifier support to "for" loops
* 1.1.2 (2011-07-30)
* fixed json_encode filter on PHP 5.2
* fixed regression introduced in 1.1.1 ({{ block(foo|lower) }})
* fixed inheritance when using conditional parents
* fixed compilation of templates when the body of a child template is not empty
* fixed output when a macro throws an exception
* fixed a parsing problem when a large chunk of text is enclosed in a comment tag
* added PHPDoc for all Token parsers and Core extension functions
* 1.1.1 (2011-07-17)
* added a performance optimization in the Optimizer (also helps to lower the number of nested level calls)
* made some performance improvement for some edge cases
* 1.1.0 (2011-06-28)
* fixed json_encode filter
* 1.1.0-RC3 (2011-06-24)
* fixed method case-sensitivity when using the sandbox mode
* added timezone support for the date filter
* fixed possible security problems with NUL bytes
* 1.1.0-RC2 (2011-06-16)
* added an exception when the template passed to "use" is not a string
* made 'a.b is defined' not throw an exception if a is not defined (in strict mode)
* added {% line \d+ %} directive
* 1.1.0-RC1 (2011-05-28)
Flush your cache after upgrading.
* fixed date filter when using a timestamp
* fixed the defined test for some cases
* fixed a parsing problem when a large chunk of text is enclosed in a raw tag
* added support for horizontal reuse of template blocks (see docs for more information)
* added whitespace control modifier to all tags (see docs for more information)
* added null as an alias for none (the null test is also an alias for the none test now)
* made TRUE, FALSE, NONE equivalent to their lowercase counterparts
* wrapped all compilation and runtime exceptions with Twig_Error_Runtime and added logic to guess the template name and line
* moved display() method to Twig_Template (generated templates should now use doDisplay() instead)
* 1.0.0 (2011-03-27)
* fixed output when using mbstring
* fixed duplicate call of methods when using the sandbox
* made the charset configurable for the escape filter
* 1.0.0-RC2 (2011-02-21)
* changed the way {% set %} works when capturing (the content is now marked as safe)
* added support for macro name in the endmacro tag
* make Twig_Error compatible with PHP 5.3.0 >
* fixed an infinite loop on some Windows configurations
* fixed the "length" filter for numbers
* fixed Template::getAttribute() as properties in PHP are case sensitive
* removed coupling between Twig_Node and Twig_Template
* fixed the ternary operator precedence rule
* 1.0.0-RC1 (2011-01-09)
Backward incompatibilities:
* the "items" filter, which has been deprecated for quite a long time now, has been removed
* the "range" filter has been converted to a function: 0|range(10) -> range(0, 10)
* the "constant" filter has been converted to a function: {{ some_date|date('DATE_W3C'|constant) }} -> {{ some_date|date(constant('DATE_W3C')) }}
* the "cycle" filter has been converted to a function: {{ ['odd', 'even']|cycle(i) }} -> {{ cycle(['odd', 'even'], i) }}
* the "for" tag does not support "joined by" anymore
* the "autoescape" first argument is now "true"/"false" (instead of "on"/"off")
* the "parent" tag has been replaced by a "parent" function ({{ parent() }} instead of {% parent %})
* the "display" tag has been replaced by a "block" function ({{ block('title') }} instead of {% display title %})
* removed the grammar and simple token parser (moved to the Twig Extensions repository)
Changes:
* added "needs_context" option for filters and functions (the context is then passed as a first argument)
* added global variables support
* made macros return their value instead of echoing directly (fixes calling a macro in sandbox mode)
* added the "from" tag to import macros as functions
* added support for functions (a function is just syntactic sugar for a getAttribute() call)
* made macros callable when sandbox mode is enabled
* added an exception when a macro uses a reserved name
* the "default" filter now uses the "empty" test instead of just checking for null
* added the "empty" test
* 0.9.10 (2010-12-16)
Backward incompatibilities:
* The Escaper extension is enabled by default, which means that all displayed
variables are now automatically escaped. You can revert to the previous
behavior by removing the extension via $env->removeExtension('escaper')
or just set the 'autoescape' option to 'false'.
* removed the "without loop" attribute for the "for" tag (not needed anymore
as the Optimizer take care of that for most cases)
* arrays and hashes have now a different syntax
* arrays keep the same syntax with square brackets: [1, 2]
* hashes now use curly braces (["a": "b"] should now be written as {"a": "b"})
* support for "arrays with keys" and "hashes without keys" is not supported anymore ([1, "foo": "bar"] or {"foo": "bar", 1})
* the i18n extension is now part of the Twig Extensions repository
Changes:
* added the merge filter
* removed 'is_escaper' option for filters (a left over from the previous version) -- you must use 'is_safe' now instead
* fixed usage of operators as method names (like is, in, and not)
* changed the order of execution for node visitors
* fixed default() filter behavior when used with strict_variables set to on
* fixed filesystem loader compatibility with PHAR files
* enhanced error messages when an unexpected token is parsed in an expression
* fixed filename not being added to syntax error messages
* added the autoescape option to enable/disable autoescaping
* removed the newline after a comment (mimics PHP behavior)
* added a syntax error exception when parent block is used on a template that does not extend another one
* made the Escaper extension enabled by default
* fixed sandbox extension when used with auto output escaping
* fixed escaper when wrapping a Twig_Node_Print (the original class must be preserved)
* added an Optimizer extension (enabled by default; optimizes "for" loops and "raw" filters)
* added priority to node visitors
* 0.9.9 (2010-11-28)
Backward incompatibilities:
* the self special variable has been renamed to _self
* the odd and even filters are now tests:
{{ foo|odd }} must now be written {{ foo is odd }}
* the "safe" filter has been renamed to "raw"
* in Node classes,
sub-nodes are now accessed via getNode() (instead of property access)
attributes via getAttribute() (instead of array access)
* the urlencode filter had been renamed to url_encode
* the include tag now merges the passed variables with the current context by default
(the old behavior is still possible by adding the "only" keyword)
* moved Exceptions to Twig_Error_* (Twig_SyntaxError/Twig_RuntimeError are now Twig_Error_Syntax/Twig_Error_Runtime)
* removed support for {{ 1 < i < 3 }} (use {{ i > 1 and i < 3 }} instead)
* the "in" filter has been removed ({{ a|in(b) }} should now be written {{ a in b }})
Changes:
* added file and line to Twig_Error_Runtime exceptions thrown from Twig_Template
* changed trans tag to accept any variable for the plural count
* fixed sandbox mode (__toString() method check was not enforced if called implicitly from complex statements)
* added the ** (power) operator
* changed the algorithm used for parsing expressions
* added the spaceless tag
* removed trim_blocks option
* added support for is*() methods for attributes (foo.bar now looks for foo->getBar() or foo->isBar())
* changed all exceptions to extend Twig_Error
* fixed unary expressions ({{ not(1 or 0) }})
* fixed child templates (with an extend tag) that uses one or more imports
* added support for {{ 1 not in [2, 3] }} (more readable than the current {{ not (1 in [2, 3]) }})
* escaping has been rewritten
* the implementation of template inheritance has been rewritten
(blocks can now be called individually and still work with inheritance)
* fixed error handling for if tag when a syntax error occurs within a subparse process
* added a way to implement custom logic for resolving token parsers given a tag name
* fixed js escaper to be stricter (now uses a whilelist-based js escaper)
* added the following filers: "constant", "trans", "replace", "json_encode"
* added a "constant" test
* fixed objects with __toString() not being autoescaped
* fixed subscript expressions when calling __call() (methods now keep the case)
* added "test" feature (accessible via the "is" operator)
* removed the debug tag (should be done in an extension)
* fixed trans tag when no vars are used in plural form
* fixed race condition when writing template cache
* added the special _charset variable to reference the current charset
* added the special _context variable to reference the current context
* renamed self to _self (to avoid conflict)
* fixed Twig_Template::getAttribute() for protected properties
* 0.9.8 (2010-06-28)
Backward incompatibilities:
* the trans tag plural count is now attached to the plural tag:
old: `{% trans count %}...{% plural %}...{% endtrans %}`
new: `{% trans %}...{% plural count %}...{% endtrans %}`
* added a way to translate strings coming from a variable ({% trans var %})
* fixed trans tag when used with the Escaper extension
* fixed default cache umask
* removed Twig_Template instances from the debug tag output
* fixed objects with __isset() defined
* fixed set tag when used with a capture
* fixed type hinting for Twig_Environment::addFilter() method
* 0.9.7 (2010-06-12)
Backward incompatibilities:
* changed 'as' to '=' for the set tag ({% set title as "Title" %} must now be {% set title = "Title" %})
* removed the sandboxed attribute of the include tag (use the new sandbox tag instead)
* refactored the Node system (if you have custom nodes, you will have to update them to use the new API)
* added self as a special variable that refers to the current template (useful for importing macros from the current template)
* added Twig_Template instance support to the include tag
* added support for dynamic and conditional inheritance ({% extends some_var %} and {% extends standalone ? "minimum" : "base" %})
* added a grammar sub-framework to ease the creation of custom tags
* fixed the for tag for large arrays (some loop variables are now only available for arrays and objects that implement the Countable interface)
* removed the Twig_Resource::resolveMissingFilter() method
* fixed the filter tag which did not apply filtering to included files
* added a bunch of unit tests
* added a bunch of phpdoc
* added a sandbox tag in the sandbox extension
* changed the date filter to support any date format supported by DateTime
* added strict_variable setting to throw an exception when an invalid variable is used in a template (disabled by default)
* added the lexer, parser, and compiler as arguments to the Twig_Environment constructor
* changed the cache option to only accepts an explicit path to a cache directory or false
* added a way to add token parsers, filters, and visitors without creating an extension
* added three interfaces: Twig_NodeInterface, Twig_TokenParserInterface, and Twig_FilterInterface
* changed the generated code to match the new coding standards
* fixed sandbox mode (__toString() method check was not enforced if called implicitly from a simple statement like {{ article }})
* added an exception when a child template has a non-empty body (as it is always ignored when rendering)
* 0.9.6 (2010-05-12)
* fixed variables defined outside a loop and for which the value changes in a for loop
* fixed the test suite for PHP 5.2 and older versions of PHPUnit
* added support for __call() in expression resolution
* fixed node visiting for macros (macros are now visited by visitors as any other node)
* fixed nested block definitions with a parent call (rarely useful but nonetheless supported now)
* added the cycle filter
* fixed the Lexer when mbstring.func_overload is used with an mbstring.internal_encoding different from ASCII
* added a long-syntax for the set tag ({% set foo %}...{% endset %})
* unit tests are now powered by PHPUnit
* added support for gettext via the `i18n` extension
* fixed twig_capitalize_string_filter() and fixed twig_length_filter() when used with UTF-8 values
* added a more useful exception if an if tag is not closed properly
* added support for escaping strategy in the autoescape tag
* fixed lexer when a template has a big chunk of text between/in a block
* 0.9.5 (2010-01-20)
As for any new release, don't forget to remove all cached templates after
upgrading.
If you have defined custom filters, you MUST upgrade them for this release. To
upgrade, replace "array" with "new Twig_Filter_Function", and replace the
environment constant by the "needs_environment" option:
// before
'even' => array('twig_is_even_filter', false),
'escape' => array('twig_escape_filter', true),
// after
'even' => new Twig_Filter_Function('twig_is_even_filter'),
'escape' => new Twig_Filter_Function('twig_escape_filter', array('needs_environment' => true)),
If you have created NodeTransformer classes, you will need to upgrade them to
the new interface (please note that the interface is not yet considered
stable).
* fixed list nodes that did not extend the Twig_NodeListInterface
* added the "without loop" option to the for tag (it disables the generation of the loop variable)
* refactored node transformers to node visitors
* fixed automatic-escaping for blocks
* added a way to specify variables to pass to an included template
* changed the automatic-escaping rules to be more sensible and more configurable in custom filters (the documentation lists all the rules)
* improved the filter system to allow object methods to be used as filters
* changed the Array and String loaders to actually make use of the cache mechanism
* included the default filter function definitions in the extension class files directly (Core, Escaper)
* added the // operator (like the floor() PHP function)
* added the .. operator (as a syntactic sugar for the range filter when the step is 1)
* added the in operator (as a syntactic sugar for the in filter)
* added the following filters in the Core extension: in, range
* added support for arrays (same behavior as in PHP, a mix between lists and dictionaries, arrays and hashes)
* enhanced some error messages to provide better feedback in case of parsing errors
* 0.9.4 (2009-12-02)
If you have custom loaders, you MUST upgrade them for this release: The
Twig_Loader base class has been removed, and the Twig_LoaderInterface has also
been changed (see the source code for more information or the documentation).
* added support for DateTime instances for the date filter
* fixed loop.last when the array only has one item
* made it possible to insert newlines in tag and variable blocks
* fixed a bug when a literal '\n' were present in a template text
* fixed bug when the filename of a template contains */
* refactored loaders
* 0.9.3 (2009-11-11)
This release is NOT backward compatible with the previous releases.
The loaders do not take the cache and autoReload arguments anymore. Instead,
the Twig_Environment class has two new options: cache and auto_reload.
Upgrading your code means changing this kind of code:
$loader = new Twig_Loader_Filesystem('/path/to/templates', '/path/to/compilation_cache', true);
$twig = new Twig_Environment($loader);
to something like this:
$loader = new Twig_Loader_Filesystem('/path/to/templates');
$twig = new Twig_Environment($loader, array(
'cache' => '/path/to/compilation_cache',
'auto_reload' => true,
));
* deprecated the "items" filter as it is not needed anymore
* made cache and auto_reload options of Twig_Environment instead of arguments of Twig_Loader
* optimized template loading speed
* removed output when an error occurs in a template and render() is used
* made major speed improvements for loops (up to 300% on even the smallest loops)
* added properties as part of the sandbox mode
* added public properties support (obj.item can now be the item property on the obj object)
* extended set tag to support expression as value ({% set foo as 'foo' ~ 'bar' %} )
* fixed bug when \ was used in HTML
* 0.9.2 (2009-10-29)
* made some speed optimizations
* changed the cache extension to .php
* added a js escaping strategy
* added support for short block tag
* changed the filter tag to allow chained filters
* made lexer more flexible as you can now change the default delimiters
* added set tag
* changed default directory permission when cache dir does not exist (more secure)
* added macro support
* changed filters first optional argument to be a Twig_Environment instance instead of a Twig_Template instance
* made Twig_Autoloader::autoload() a static method
* avoid writing template file if an error occurs
* added $ escaping when outputting raw strings
* enhanced some error messages to ease debugging
* fixed empty cache files when the template contains an error
* 0.9.1 (2009-10-14)
* fixed a bug in PHP 5.2.6
* fixed numbers with one than one decimal
* added support for method calls with arguments ({{ foo.bar('a', 43) }})
* made small speed optimizations
* made minor tweaks to allow better extensibility and flexibility
* 0.9.0 (2009-10-12)
* Initial release

View file

@ -1,31 +0,0 @@
Copyright (c) 2009-2013 by the Twig Team, see AUTHORS for more details.
Some rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* The names of the contributors may not be used to endorse or
promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View file

@ -1,17 +0,0 @@
Twig, the flexible, fast, and secure template language for PHP
==============================================================
[![Build Status](https://secure.travis-ci.org/fabpot/Twig.png?branch=master)](http://travis-ci.org/fabpot/Twig)
Twig is a template language for PHP, released under the new BSD license (code
and documentation).
Twig uses a syntax similar to the Django and Jinja template languages which
inspired the Twig runtime environment.
More Information
----------------
Read the [documentation][1] for more information.
[1]: http://twig.sensiolabs.org/documentation

View file

@ -1,31 +0,0 @@
{
"name": "twig/twig",
"type": "library",
"description": "Twig, the flexible, fast, and secure template language for PHP",
"keywords": ["templating"],
"homepage": "http://twig.sensiolabs.org",
"license": "BSD-3",
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Armin Ronacher",
"email": "armin.ronacher@active-4.com"
}
],
"require": {
"php": ">=5.2.4"
},
"autoload": {
"psr-0" : {
"Twig_" : "lib/"
}
},
"extra": {
"branch-alias": {
"dev-master": "1.12-dev"
}
}
}

View file

@ -1,43 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Autoloads Twig classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Autoloader
{
/**
* Registers Twig_Autoloader as an SPL autoloader.
*/
public static function register()
{
ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array(new self, 'autoload'));
}
/**
* Handles autoloading of classes.
*
* @param string $class A class name.
*/
public static function autoload($class)
{
if (0 !== strpos($class, 'Twig')) {
return;
}
if (is_file($file = dirname(__FILE__).'/../'.str_replace(array('_', "\0"), array('/', ''), $class).'.php')) {
require $file;
}
}
}

View file

@ -1,267 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Compiles a node to PHP code.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Compiler implements Twig_CompilerInterface
{
protected $lastLine;
protected $source;
protected $indentation;
protected $env;
protected $debugInfo;
protected $sourceOffset;
protected $sourceLine;
protected $filename;
/**
* Constructor.
*
* @param Twig_Environment $env The twig environment instance
*/
public function __construct(Twig_Environment $env)
{
$this->env = $env;
$this->debugInfo = array();
}
public function getFilename()
{
return $this->filename;
}
/**
* Returns the environment instance related to this compiler.
*
* @return Twig_Environment The environment instance
*/
public function getEnvironment()
{
return $this->env;
}
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource()
{
return $this->source;
}
/**
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
* @param integer $indentation The current indentation
*
* @return Twig_Compiler The current compiler instance
*/
public function compile(Twig_NodeInterface $node, $indentation = 0)
{
$this->lastLine = null;
$this->source = '';
$this->sourceOffset = 0;
// source code starts at 1 (as we then increment it when we encounter new lines)
$this->sourceLine = 1;
$this->indentation = $indentation;
if ($node instanceof Twig_Node_Module) {
$this->filename = $node->getAttribute('filename');
}
$node->compile($this);
return $this;
}
public function subcompile(Twig_NodeInterface $node, $raw = true)
{
if (false === $raw) {
$this->addIndentation();
}
$node->compile($this);
return $this;
}
/**
* Adds a raw string to the compiled code.
*
* @param string $string The string
*
* @return Twig_Compiler The current compiler instance
*/
public function raw($string)
{
$this->source .= $string;
return $this;
}
/**
* Writes a string to the compiled code by adding indentation.
*
* @return Twig_Compiler The current compiler instance
*/
public function write()
{
$strings = func_get_args();
foreach ($strings as $string) {
$this->addIndentation();
$this->source .= $string;
}
return $this;
}
/**
* Appends an indentation to the current PHP code after compilation.
*
* @return Twig_Compiler The current compiler instance
*/
public function addIndentation()
{
$this->source .= str_repeat(' ', $this->indentation * 4);
return $this;
}
/**
* Adds a quoted string to the compiled code.
*
* @param string $value The string
*
* @return Twig_Compiler The current compiler instance
*/
public function string($value)
{
$this->source .= sprintf('"%s"', addcslashes($value, "\0\t\"\$\\"));
return $this;
}
/**
* Returns a PHP representation of a given value.
*
* @param mixed $value The value to convert
*
* @return Twig_Compiler The current compiler instance
*/
public function repr($value)
{
if (is_int($value) || is_float($value)) {
if (false !== $locale = setlocale(LC_NUMERIC, 0)) {
setlocale(LC_NUMERIC, 'C');
}
$this->raw($value);
if (false !== $locale) {
setlocale(LC_NUMERIC, $locale);
}
} elseif (null === $value) {
$this->raw('null');
} elseif (is_bool($value)) {
$this->raw($value ? 'true' : 'false');
} elseif (is_array($value)) {
$this->raw('array(');
$i = 0;
foreach ($value as $key => $value) {
if ($i++) {
$this->raw(', ');
}
$this->repr($key);
$this->raw(' => ');
$this->repr($value);
}
$this->raw(')');
} else {
$this->string($value);
}
return $this;
}
/**
* Adds debugging information.
*
* @param Twig_NodeInterface $node The related twig node
*
* @return Twig_Compiler The current compiler instance
*/
public function addDebugInfo(Twig_NodeInterface $node)
{
if ($node->getLine() != $this->lastLine) {
$this->write("// line {$node->getLine()}\n");
// when mbstring.func_overload is set to 2
// mb_substr_count() replaces substr_count()
// but they have different signatures!
if (((int) ini_get('mbstring.func_overload')) & 2) {
// this is much slower than the "right" version
$this->sourceLine += mb_substr_count(mb_substr($this->source, $this->sourceOffset), "\n");
} else {
$this->sourceLine += substr_count($this->source, "\n", $this->sourceOffset);
}
$this->sourceOffset = strlen($this->source);
$this->debugInfo[$this->sourceLine] = $node->getLine();
$this->lastLine = $node->getLine();
}
return $this;
}
public function getDebugInfo()
{
return $this->debugInfo;
}
/**
* Indents the generated code.
*
* @param integer $step The number of indentation to add
*
* @return Twig_Compiler The current compiler instance
*/
public function indent($step = 1)
{
$this->indentation += $step;
return $this;
}
/**
* Outdents the generated code.
*
* @param integer $step The number of indentation to remove
*
* @return Twig_Compiler The current compiler instance
*/
public function outdent($step = 1)
{
// can't outdent by more steps than the current indentation level
if ($this->indentation < $step) {
throw new LogicException('Unable to call outdent() as the indentation would become negative');
}
$this->indentation -= $step;
return $this;
}
}

View file

@ -1,35 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by compiler classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_CompilerInterface
{
/**
* Compiles a node.
*
* @param Twig_NodeInterface $node The node to compile
*
* @return Twig_CompilerInterface The current compiler instance
*/
public function compile(Twig_NodeInterface $node);
/**
* Gets the current PHP code after compilation.
*
* @return string The PHP code
*/
public function getSource();
}

File diff suppressed because it is too large Load diff

View file

@ -1,232 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Twig base exception.
*
* This exception class and its children must only be used when
* an error occurs during the loading of a template, when a syntax error
* is detected in a template, or when rendering a template. Other
* errors must use regular PHP exception classes (like when the template
* cache directory is not writable for instance).
*
* To help debugging template issues, this class tracks the original template
* name and line where the error occurred.
*
* Whenever possible, you must set these information (original template name
* and line number) yourself by passing them to the constructor. If some or all
* these information are not available from where you throw the exception, then
* this class will guess them automatically (when the line number is set to -1
* and/or the filename is set to null). As this is a costly operation, this
* can be disabled by passing false for both the filename and the line number
* when creating a new instance of this class.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error extends Exception
{
protected $lineno;
protected $filename;
protected $rawMessage;
protected $previous;
/**
* Constructor.
*
* Set both the line number and the filename to false to
* disable automatic guessing of the original template name
* and line number.
*
* Set the line number to -1 to enable its automatic guessing.
* Set the filename to null to enable its automatic guessing.
*
* By default, automatic guessing is enabled.
*
* @param string $message The error message
* @param integer $lineno The template line where the error occurred
* @param string $filename The template file name where the error occurred
* @param Exception $previous The previous exception
*/
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
{
if (version_compare(PHP_VERSION, '5.3.0', '<')) {
$this->previous = $previous;
parent::__construct('');
} else {
parent::__construct('', 0, $previous);
}
$this->lineno = $lineno;
$this->filename = $filename;
if (-1 === $this->lineno || null === $this->filename) {
$this->guessTemplateInfo();
}
$this->rawMessage = $message;
$this->updateRepr();
}
/**
* Gets the raw message.
*
* @return string The raw message
*/
public function getRawMessage()
{
return $this->rawMessage;
}
/**
* Gets the filename where the error occurred.
*
* @return string The filename
*/
public function getTemplateFile()
{
return $this->filename;
}
/**
* Sets the filename where the error occurred.
*
* @param string $filename The filename
*/
public function setTemplateFile($filename)
{
$this->filename = $filename;
$this->updateRepr();
}
/**
* Gets the template line where the error occurred.
*
* @return integer The template line
*/
public function getTemplateLine()
{
return $this->lineno;
}
/**
* Sets the template line where the error occurred.
*
* @param integer $lineno The template line
*/
public function setTemplateLine($lineno)
{
$this->lineno = $lineno;
$this->updateRepr();
}
public function guess()
{
$this->guessTemplateInfo();
$this->updateRepr();
}
/**
* For PHP < 5.3.0, provides access to the getPrevious() method.
*
* @param string $method The method name
* @param array $arguments The parameters to be passed to the method
*
* @return Exception The previous exception or null
*
* @throws BadMethodCallException
*/
public function __call($method, $arguments)
{
if ('getprevious' == strtolower($method)) {
return $this->previous;
}
throw new BadMethodCallException(sprintf('Method "Twig_Error::%s()" does not exist.', $method));
}
protected function updateRepr()
{
$this->message = $this->rawMessage;
$dot = false;
if ('.' === substr($this->message, -1)) {
$this->message = substr($this->message, 0, -1);
$dot = true;
}
if ($this->filename) {
if (is_string($this->filename) || (is_object($this->filename) && method_exists($this->filename, '__toString'))) {
$filename = sprintf('"%s"', $this->filename);
} else {
$filename = json_encode($this->filename);
}
$this->message .= sprintf(' in %s', $filename);
}
if ($this->lineno && $this->lineno >= 0) {
$this->message .= sprintf(' at line %d', $this->lineno);
}
if ($dot) {
$this->message .= '.';
}
}
protected function guessTemplateInfo()
{
$template = null;
foreach (debug_backtrace() as $trace) {
if (isset($trace['object']) && $trace['object'] instanceof Twig_Template && 'Twig_Template' !== get_class($trace['object'])) {
if (null === $this->filename || $this->filename == $trace['object']->getTemplateName()) {
$template = $trace['object'];
}
}
}
// update template filename
if (null !== $template && null === $this->filename) {
$this->filename = $template->getTemplateName();
}
if (null === $template || $this->lineno > -1) {
return;
}
$r = new ReflectionObject($template);
$file = $r->getFileName();
$exceptions = array($e = $this);
while (($e instanceof self || method_exists($e, 'getPrevious')) && $e = $e->getPrevious()) {
$exceptions[] = $e;
}
while ($e = array_pop($exceptions)) {
$traces = $e->getTrace();
while ($trace = array_shift($traces)) {
if (!isset($trace['file']) || !isset($trace['line']) || $file != $trace['file']) {
continue;
}
foreach ($template->getDebugInfo() as $codeLine => $templateLine) {
if ($codeLine <= $trace['line']) {
// update template line
$this->lineno = $templateLine;
return;
}
}
}
}
}
}

View file

@ -1,31 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs during template loading.
*
* Automatic template information guessing is always turned off as
* if a template cannot be loaded, there is nothing to guess.
* However, when a template is loaded from another one, then, we need
* to find the current context and this is automatically done by
* Twig_Template::displayWithErrorHandling().
*
* This strategy makes Twig_Environment::resolveTemplate() much faster.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Loader extends Twig_Error
{
public function __construct($message, $lineno = -1, $filename = null, Exception $previous = null)
{
parent::__construct($message, false, false, $previous);
}
}

View file

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when an error occurs at runtime.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Runtime extends Twig_Error
{
}

View file

@ -1,20 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Exception thrown when a syntax error occurs during lexing or parsing of a template.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Error_Syntax extends Twig_Error
{
}

View file

@ -1,28 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Adds an exists() method for loaders.
*
* @author Florin Patan <florinpatan@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_ExistsLoaderInterface
{
/**
* Check if we have the source code of a template, given its name.
*
* @param string $name The name of the template to check if we can load
*
* @return boolean If the template source code is handled by this loader or not
*/
public function exists($name);
}

View file

@ -1,600 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Parses expressions.
*
* This parser implements a "Precedence climbing" algorithm.
*
* @see http://www.engr.mun.ca/~theo/Misc/exp_parsing.htm
* @see http://en.wikipedia.org/wiki/Operator-precedence_parser
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_ExpressionParser
{
const OPERATOR_LEFT = 1;
const OPERATOR_RIGHT = 2;
protected $parser;
protected $unaryOperators;
protected $binaryOperators;
public function __construct(Twig_Parser $parser, array $unaryOperators, array $binaryOperators)
{
$this->parser = $parser;
$this->unaryOperators = $unaryOperators;
$this->binaryOperators = $binaryOperators;
}
public function parseExpression($precedence = 0)
{
$expr = $this->getPrimary();
$token = $this->parser->getCurrentToken();
while ($this->isBinary($token) && $this->binaryOperators[$token->getValue()]['precedence'] >= $precedence) {
$op = $this->binaryOperators[$token->getValue()];
$this->parser->getStream()->next();
if (isset($op['callable'])) {
$expr = call_user_func($op['callable'], $this->parser, $expr);
} else {
$expr1 = $this->parseExpression(self::OPERATOR_LEFT === $op['associativity'] ? $op['precedence'] + 1 : $op['precedence']);
$class = $op['class'];
$expr = new $class($expr, $expr1, $token->getLine());
}
$token = $this->parser->getCurrentToken();
}
if (0 === $precedence) {
return $this->parseConditionalExpression($expr);
}
return $expr;
}
protected function getPrimary()
{
$token = $this->parser->getCurrentToken();
if ($this->isUnary($token)) {
$operator = $this->unaryOperators[$token->getValue()];
$this->parser->getStream()->next();
$expr = $this->parseExpression($operator['precedence']);
$class = $operator['class'];
return $this->parsePostfixExpression(new $class($expr, $token->getLine()));
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$this->parser->getStream()->next();
$expr = $this->parseExpression();
$this->parser->getStream()->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'An opened parenthesis is not properly closed');
return $this->parsePostfixExpression($expr);
}
return $this->parsePrimaryExpression();
}
protected function parseConditionalExpression($expr)
{
while ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '?')) {
$this->parser->getStream()->next();
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$expr2 = $this->parseExpression();
if ($this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$this->parser->getStream()->next();
$expr3 = $this->parseExpression();
} else {
$expr3 = new Twig_Node_Expression_Constant('', $this->parser->getCurrentToken()->getLine());
}
} else {
$this->parser->getStream()->next();
$expr2 = $expr;
$expr3 = $this->parseExpression();
}
$expr = new Twig_Node_Expression_Conditional($expr, $expr2, $expr3, $this->parser->getCurrentToken()->getLine());
}
return $expr;
}
protected function isUnary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->unaryOperators[$token->getValue()]);
}
protected function isBinary(Twig_Token $token)
{
return $token->test(Twig_Token::OPERATOR_TYPE) && isset($this->binaryOperators[$token->getValue()]);
}
public function parsePrimaryExpression()
{
$token = $this->parser->getCurrentToken();
switch ($token->getType()) {
case Twig_Token::NAME_TYPE:
$this->parser->getStream()->next();
switch ($token->getValue()) {
case 'true':
case 'TRUE':
$node = new Twig_Node_Expression_Constant(true, $token->getLine());
break;
case 'false':
case 'FALSE':
$node = new Twig_Node_Expression_Constant(false, $token->getLine());
break;
case 'none':
case 'NONE':
case 'null':
case 'NULL':
$node = new Twig_Node_Expression_Constant(null, $token->getLine());
break;
default:
if ('(' === $this->parser->getCurrentToken()->getValue()) {
$node = $this->getFunctionNode($token->getValue(), $token->getLine());
} else {
$node = new Twig_Node_Expression_Name($token->getValue(), $token->getLine());
}
}
break;
case Twig_Token::NUMBER_TYPE:
$this->parser->getStream()->next();
$node = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
break;
case Twig_Token::STRING_TYPE:
case Twig_Token::INTERPOLATION_START_TYPE:
$node = $this->parseStringExpression();
break;
default:
if ($token->test(Twig_Token::PUNCTUATION_TYPE, '[')) {
$node = $this->parseArrayExpression();
} elseif ($token->test(Twig_Token::PUNCTUATION_TYPE, '{')) {
$node = $this->parseHashExpression();
} else {
throw new Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
}
return $this->parsePostfixExpression($node);
}
public function parseStringExpression()
{
$stream = $this->parser->getStream();
$nodes = array();
// a string cannot be followed by another string in a single expression
$nextCanBeString = true;
while (true) {
if ($stream->test(Twig_Token::STRING_TYPE) && $nextCanBeString) {
$token = $stream->next();
$nodes[] = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
$nextCanBeString = false;
} elseif ($stream->test(Twig_Token::INTERPOLATION_START_TYPE)) {
$stream->next();
$nodes[] = $this->parseExpression();
$stream->expect(Twig_Token::INTERPOLATION_END_TYPE);
$nextCanBeString = true;
} else {
break;
}
}
$expr = array_shift($nodes);
foreach ($nodes as $node) {
$expr = new Twig_Node_Expression_Binary_Concat($expr, $node, $node->getLine());
}
return $expr;
}
public function parseArrayExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '[', 'An array element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'An array element must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
break;
}
}
$first = false;
$node->addElement($this->parseExpression());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']', 'An opened array is not properly closed');
return $node;
}
public function parseHashExpression()
{
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '{', 'A hash element was expected');
$node = new Twig_Node_Expression_Array(array(), $stream->getCurrent()->getLine());
$first = true;
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
if (!$first) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'A hash value must be followed by a comma');
// trailing ,?
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '}')) {
break;
}
}
$first = false;
// a hash key can be:
//
// * a number -- 12
// * a string -- 'a'
// * a name, which is equivalent to a string -- a
// * an expression, which must be enclosed in parentheses -- (1 + 2)
if ($stream->test(Twig_Token::STRING_TYPE) || $stream->test(Twig_Token::NAME_TYPE) || $stream->test(Twig_Token::NUMBER_TYPE)) {
$token = $stream->next();
$key = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
} elseif ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$key = $this->parseExpression();
} else {
$current = $stream->getCurrent();
throw new Twig_Error_Syntax(sprintf('A hash key must be a quoted string, a number, a name, or an expression enclosed in parentheses (unexpected token "%s" of value "%s"', Twig_Token::typeToEnglish($current->getType(), $current->getLine()), $current->getValue()), $current->getLine(), $this->parser->getFilename());
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ':', 'A hash key must be followed by a colon (:)');
$value = $this->parseExpression();
$node->addElement($value, $key);
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '}', 'An opened hash is not properly closed');
return $node;
}
public function parsePostfixExpression($node)
{
while (true) {
$token = $this->parser->getCurrentToken();
if ($token->getType() == Twig_Token::PUNCTUATION_TYPE) {
if ('.' == $token->getValue() || '[' == $token->getValue()) {
$node = $this->parseSubscriptExpression($node);
} elseif ('|' == $token->getValue()) {
$node = $this->parseFilterExpression($node);
} else {
break;
}
} else {
break;
}
}
return $node;
}
public function getFunctionNode($name, $line)
{
switch ($name) {
case 'parent':
$args = $this->parseArguments();
if (!count($this->parser->getBlockStack())) {
throw new Twig_Error_Syntax('Calling "parent" outside a block is forbidden', $line, $this->parser->getFilename());
}
if (!$this->parser->getParent() && !$this->parser->hasTraits()) {
throw new Twig_Error_Syntax('Calling "parent" on a template that does not extend nor "use" another template is forbidden', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_Parent($this->parser->peekBlockStack(), $line);
case 'block':
return new Twig_Node_Expression_BlockReference($this->parseArguments()->getNode(0), false, $line);
case 'attribute':
$args = $this->parseArguments();
if (count($args) < 2) {
throw new Twig_Error_Syntax('The "attribute" function takes at least two arguments (the variable and the attributes)', $line, $this->parser->getFilename());
}
return new Twig_Node_Expression_GetAttr($args->getNode(0), $args->getNode(1), count($args) > 2 ? $args->getNode(2) : new Twig_Node_Expression_Array(array(), $line), Twig_TemplateInterface::ANY_CALL, $line);
default:
if (null !== $alias = $this->parser->getImportedSymbol('function', $name)) {
$arguments = new Twig_Node_Expression_Array(array(), $line);
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
$node = new Twig_Node_Expression_MethodCall($alias['node'], $alias['name'], $arguments, $line);
$node->setAttribute('safe', true);
return $node;
}
$args = $this->parseArguments(true);
$class = $this->getFunctionNodeClass($name, $line);
return new $class($name, $args, $line);
}
}
public function parseSubscriptExpression($node)
{
$stream = $this->parser->getStream();
$token = $stream->next();
$lineno = $token->getLine();
$arguments = new Twig_Node_Expression_Array(array(), $lineno);
$type = Twig_TemplateInterface::ANY_CALL;
if ($token->getValue() == '.') {
$token = $stream->next();
if (
$token->getType() == Twig_Token::NAME_TYPE
||
$token->getType() == Twig_Token::NUMBER_TYPE
||
($token->getType() == Twig_Token::OPERATOR_TYPE && preg_match(Twig_Lexer::REGEX_NAME, $token->getValue()))
) {
$arg = new Twig_Node_Expression_Constant($token->getValue(), $lineno);
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$type = Twig_TemplateInterface::METHOD_CALL;
foreach ($this->parseArguments() as $n) {
$arguments->addElement($n);
}
}
} else {
throw new Twig_Error_Syntax('Expected name or number', $lineno, $this->parser->getFilename());
}
if ($node instanceof Twig_Node_Expression_Name && null !== $alias = $this->parser->getImportedSymbol('template', $node->getAttribute('name'))) {
if (!$arg instanceof Twig_Node_Expression_Constant) {
throw new Twig_Error_Syntax(sprintf('Dynamic macro names are not supported (called on "%s")', $node->getAttribute('name')), $token->getLine(), $this->parser->getFilename());
}
$node = new Twig_Node_Expression_MethodCall($node, 'get'.$arg->getAttribute('value'), $arguments, $lineno);
$node->setAttribute('safe', true);
return $node;
}
} else {
$type = Twig_TemplateInterface::ARRAY_CALL;
// slice?
$slice = false;
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$arg = new Twig_Node_Expression_Constant(0, $token->getLine());
} else {
$arg = $this->parseExpression();
}
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ':')) {
$slice = true;
$stream->next();
}
if ($slice) {
if ($stream->test(Twig_Token::PUNCTUATION_TYPE, ']')) {
$length = new Twig_Node_Expression_Constant(null, $token->getLine());
} else {
$length = $this->parseExpression();
}
$class = $this->getFilterNodeClass('slice', $token->getLine());
$arguments = new Twig_Node(array($arg, $length));
$filter = new $class($node, new Twig_Node_Expression_Constant('slice', $token->getLine()), $arguments, $token->getLine());
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
return $filter;
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ']');
}
return new Twig_Node_Expression_GetAttr($node, $arg, $arguments, $type, $lineno);
}
public function parseFilterExpression($node)
{
$this->parser->getStream()->next();
return $this->parseFilterExpressionRaw($node);
}
public function parseFilterExpressionRaw($node, $tag = null)
{
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE);
$name = new Twig_Node_Expression_Constant($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '(')) {
$arguments = new Twig_Node();
} else {
$arguments = $this->parseArguments(true);
}
$class = $this->getFilterNodeClass($name->getAttribute('value'), $token->getLine());
$node = new $class($node, $name, $arguments, $token->getLine(), $tag);
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, '|')) {
break;
}
$this->parser->getStream()->next();
}
return $node;
}
/**
* Parses arguments.
*
* @param Boolean $namedArguments Whether to allow named arguments or not
* @param Boolean $definition Whether we are parsing arguments for a function definition
*/
public function parseArguments($namedArguments = false, $definition = false)
{
$args = array();
$stream = $this->parser->getStream();
$stream->expect(Twig_Token::PUNCTUATION_TYPE, '(', 'A list of arguments must begin with an opening parenthesis');
while (!$stream->test(Twig_Token::PUNCTUATION_TYPE, ')')) {
if (!empty($args)) {
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ',', 'Arguments must be separated by a comma');
}
if ($definition) {
$token = $stream->expect(Twig_Token::NAME_TYPE, null, 'An argument must be a name');
$value = new Twig_Node_Expression_Name($token->getValue(), $this->parser->getCurrentToken()->getLine());
} else {
$value = $this->parseExpression();
}
$name = null;
if ($namedArguments && $stream->test(Twig_Token::OPERATOR_TYPE, '=')) {
$token = $stream->next();
if (!$value instanceof Twig_Node_Expression_Name) {
throw new Twig_Error_Syntax(sprintf('A parameter name must be a string, "%s" given', get_class($value)), $token->getLine(), $this->parser->getFilename());
}
$name = $value->getAttribute('name');
if ($definition) {
$value = $this->parsePrimaryExpression();
if (!$this->checkConstantExpression($value)) {
throw new Twig_Error_Syntax(sprintf('A default value for an argument must be a constant (a boolean, a string, a number, or an array).'), $token->getLine(), $this->parser->getFilename());
}
} else {
$value = $this->parseExpression();
}
}
if ($definition) {
if (null === $name) {
$name = $value->getAttribute('name');
$value = new Twig_Node_Expression_Constant(null, $this->parser->getCurrentToken()->getLine());
}
$args[$name] = $value;
} else {
if (null === $name) {
$args[] = $value;
} else {
$args[$name] = $value;
}
}
}
$stream->expect(Twig_Token::PUNCTUATION_TYPE, ')', 'A list of arguments must be closed by a parenthesis');
return new Twig_Node($args);
}
public function parseAssignmentExpression()
{
$targets = array();
while (true) {
$token = $this->parser->getStream()->expect(Twig_Token::NAME_TYPE, null, 'Only variables can be assigned to');
if (in_array($token->getValue(), array('true', 'false', 'none'))) {
throw new Twig_Error_Syntax(sprintf('You cannot assign a value to "%s"', $token->getValue()), $token->getLine(), $this->parser->getFilename());
}
$targets[] = new Twig_Node_Expression_AssignName($token->getValue(), $token->getLine());
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
$this->parser->getStream()->next();
}
return new Twig_Node($targets);
}
public function parseMultitargetExpression()
{
$targets = array();
while (true) {
$targets[] = $this->parseExpression();
if (!$this->parser->getStream()->test(Twig_Token::PUNCTUATION_TYPE, ',')) {
break;
}
$this->parser->getStream()->next();
}
return new Twig_Node($targets);
}
protected function getFunctionNodeClass($name, $line)
{
$env = $this->parser->getEnvironment();
if (false === $function = $env->getFunction($name)) {
$message = sprintf('The function "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFunctions()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($function instanceof Twig_SimpleFunction) {
return $function->getNodeClass();
}
return $function instanceof Twig_Function_Node ? $function->getClass() : 'Twig_Node_Expression_Function';
}
protected function getFilterNodeClass($name, $line)
{
$env = $this->parser->getEnvironment();
if (false === $filter = $env->getFilter($name)) {
$message = sprintf('The filter "%s" does not exist', $name);
if ($alternatives = $env->computeAlternatives($name, array_keys($env->getFilters()))) {
$message = sprintf('%s. Did you mean "%s"', $message, implode('", "', $alternatives));
}
throw new Twig_Error_Syntax($message, $line, $this->parser->getFilename());
}
if ($filter instanceof Twig_SimpleFilter) {
return $filter->getNodeClass();
}
return $filter instanceof Twig_Filter_Node ? $filter->getClass() : 'Twig_Node_Expression_Filter';
}
// checks that the node only contains "constant" elements
protected function checkConstantExpression(Twig_NodeInterface $node)
{
if (!($node instanceof Twig_Node_Expression_Constant || $node instanceof Twig_Node_Expression_Array)) {
return false;
}
foreach ($node as $n) {
if (!$this->checkConstantExpression($n)) {
return false;
}
}
return true;
}
}

View file

@ -1,93 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
abstract class Twig_Extension implements Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/
public function initRuntime(Twig_Environment $environment)
{
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array();
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array();
}
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array();
}
/**
* Returns a list of tests to add to the existing list.
*
* @return array An array of tests
*/
public function getTests()
{
return array();
}
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of functions
*/
public function getFunctions()
{
return array();
}
/**
* Returns a list of operators to add to the existing list.
*
* @return array An array of operators
*/
public function getOperators()
{
return array();
}
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*/
public function getGlobals()
{
return array();
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,70 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Debug extends Twig_Extension
{
/**
* Returns a list of global functions to add to the existing list.
*
* @return array An array of global functions
*/
public function getFunctions()
{
// dump is safe if var_dump is overridden by xdebug
$isDumpOutputHtmlSafe = extension_loaded('xdebug')
// false means that it was not set (and the default is on) or it explicitly enabled
&& (false === ini_get('xdebug.overload_var_dump') || ini_get('xdebug.overload_var_dump'))
// false means that it was not set (and the default is on) or it explicitly enabled
// xdebug.overload_var_dump produces HTML only when html_errors is also enabled
&& (false === ini_get('html_errors') || ini_get('html_errors'))
;
return array(
new Twig_SimpleFunction('dump', 'twig_var_dump', array('is_safe' => $isDumpOutputHtmlSafe ? array('html') : array(), 'needs_context' => true, 'needs_environment' => true)),
);
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'debug';
}
}
function twig_var_dump(Twig_Environment $env, $context)
{
if (!$env->isDebug()) {
return;
}
ob_start();
$count = func_num_args();
if (2 === $count) {
$vars = array();
foreach ($context as $key => $value) {
if (!$value instanceof Twig_Template) {
$vars[$key] = $value;
}
}
var_dump($vars);
} else {
for ($i = 2; $i < $count; $i++) {
var_dump(func_get_arg($i));
}
}
return ob_get_clean();
}

View file

@ -1,107 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Escaper extends Twig_Extension
{
protected $defaultStrategy;
public function __construct($defaultStrategy = 'html')
{
$this->setDefaultStrategy($defaultStrategy);
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array(new Twig_TokenParser_AutoEscape());
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Escaper());
}
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters()
{
return array(
new Twig_SimpleFilter('raw', 'twig_raw_filter', array('is_safe' => array('all'))),
);
}
/**
* Sets the default strategy to use when not defined by the user.
*
* The strategy can be a valid PHP callback that takes the template
* "filename" as an argument and returns the strategy to use.
*
* @param mixed $defaultStrategy An escaping strategy
*/
public function setDefaultStrategy($defaultStrategy)
{
// for BC
if (true === $defaultStrategy) {
$defaultStrategy = 'html';
}
$this->defaultStrategy = $defaultStrategy;
}
/**
* Gets the default strategy to use when not defined by the user.
*
* @param string $filename The template "filename"
*
* @return string The default strategy to use for the template
*/
public function getDefaultStrategy($filename)
{
// disable string callables to avoid calling a function named html or js,
// or any other upcoming escaping strategy
if (!is_string($this->defaultStrategy) && is_callable($this->defaultStrategy)) {
return call_user_func($this->defaultStrategy, $filename);
}
return $this->defaultStrategy;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'escaper';
}
}
/**
* Marks a variable as being safe.
*
* @param string $string A PHP variable
*/
function twig_raw_filter($string)
{
return $string;
}

View file

@ -1,35 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Optimizer extends Twig_Extension
{
protected $optimizers;
public function __construct($optimizers = -1)
{
$this->optimizers = $optimizers;
}
/**
* {@inheritdoc}
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Optimizer($this->optimizers));
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'optimizer';
}
}

View file

@ -1,112 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_Sandbox extends Twig_Extension
{
protected $sandboxedGlobally;
protected $sandboxed;
protected $policy;
public function __construct(Twig_Sandbox_SecurityPolicyInterface $policy, $sandboxed = false)
{
$this->policy = $policy;
$this->sandboxedGlobally = $sandboxed;
}
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers()
{
return array(new Twig_TokenParser_Sandbox());
}
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors()
{
return array(new Twig_NodeVisitor_Sandbox());
}
public function enableSandbox()
{
$this->sandboxed = true;
}
public function disableSandbox()
{
$this->sandboxed = false;
}
public function isSandboxed()
{
return $this->sandboxedGlobally || $this->sandboxed;
}
public function isSandboxedGlobally()
{
return $this->sandboxedGlobally;
}
public function setSecurityPolicy(Twig_Sandbox_SecurityPolicyInterface $policy)
{
$this->policy = $policy;
}
public function getSecurityPolicy()
{
return $this->policy;
}
public function checkSecurity($tags, $filters, $functions)
{
if ($this->isSandboxed()) {
$this->policy->checkSecurity($tags, $filters, $functions);
}
}
public function checkMethodAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkMethodAllowed($obj, $method);
}
}
public function checkPropertyAllowed($obj, $method)
{
if ($this->isSandboxed()) {
$this->policy->checkPropertyAllowed($obj, $method);
}
}
public function ensureToStringAllowed($obj)
{
if (is_object($obj)) {
$this->policy->checkMethodAllowed($obj, '__toString');
}
return $obj;
}
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName()
{
return 'sandbox';
}
}

View file

@ -1,113 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Internal class.
*
* This class is used by Twig_Environment as a staging area and must not be used directly.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Extension_Staging extends Twig_Extension
{
protected $functions = array();
protected $filters = array();
protected $visitors = array();
protected $tokenParsers = array();
protected $globals = array();
protected $tests = array();
public function addFunction($name, $function)
{
$this->functions[$name] = $function;
}
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return $this->functions;
}
public function addFilter($name, $filter)
{
$this->filters[$name] = $filter;
}
/**
* {@inheritdoc}
*/
public function getFilters()
{
return $this->filters;
}
public function addNodeVisitor(Twig_NodeVisitorInterface $visitor)
{
$this->visitors[] = $visitor;
}
/**
* {@inheritdoc}
*/
public function getNodeVisitors()
{
return $this->visitors;
}
public function addTokenParser(Twig_TokenParserInterface $parser)
{
$this->tokenParsers[] = $parser;
}
/**
* {@inheritdoc}
*/
public function getTokenParsers()
{
return $this->tokenParsers;
}
public function addGlobal($name, $value)
{
$this->globals[$name] = $value;
}
/**
* {@inheritdoc}
*/
public function getGlobals()
{
return $this->globals;
}
public function addTest($name, $test)
{
$this->tests[$name] = $test;
}
/**
* {@inheritdoc}
*/
public function getTests()
{
return $this->tests;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'staging';
}
}

View file

@ -1,64 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
class Twig_Extension_StringLoader extends Twig_Extension
{
/**
* {@inheritdoc}
*/
public function getFunctions()
{
return array(
new Twig_SimpleFunction('template_from_string', 'twig_template_from_string', array('needs_environment' => true)),
);
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'string_loader';
}
}
/**
* Loads a template from a string.
*
* <pre>
* {% include template_from_string("Hello {{ name }}") }}
* </pre>
*
* @param Twig_Environment $env A Twig_Environment instance
* @param string $template A template as a string
*
* @return Twig_Template A Twig_Template instance
*/
function twig_template_from_string(Twig_Environment $env, $template)
{
static $loader;
if (null === $loader) {
$loader = new Twig_Loader_String();
}
$current = $env->getLoader();
$env->setLoader($loader);
try {
$template = $env->loadTemplate($template);
} catch (Exception $e) {
$env->setLoader($current);
throw $e;
}
$env->setLoader($current);
return $template;
}

View file

@ -1,83 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by extension classes.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
interface Twig_ExtensionInterface
{
/**
* Initializes the runtime environment.
*
* This is where you can load some file that contains filter functions for instance.
*
* @param Twig_Environment $environment The current Twig_Environment instance
*/
public function initRuntime(Twig_Environment $environment);
/**
* Returns the token parser instances to add to the existing list.
*
* @return array An array of Twig_TokenParserInterface or Twig_TokenParserBrokerInterface instances
*/
public function getTokenParsers();
/**
* Returns the node visitor instances to add to the existing list.
*
* @return array An array of Twig_NodeVisitorInterface instances
*/
public function getNodeVisitors();
/**
* Returns a list of filters to add to the existing list.
*
* @return array An array of filters
*/
public function getFilters();
/**
* Returns a list of tests to add to the existing list.
*
* @return array An array of tests
*/
public function getTests();
/**
* Returns a list of functions to add to the existing list.
*
* @return array An array of functions
*/
public function getFunctions();
/**
* Returns a list of operators to add to the existing list.
*
* @return array An array of operators
*/
public function getOperators();
/**
* Returns a list of global variables to add to the existing list.
*
* @return array An array of global variables
*/
public function getGlobals();
/**
* Returns the name of the extension.
*
* @return string The extension name
*/
public function getName();
}

View file

@ -1,83 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Filter implements Twig_FilterInterface, Twig_FilterCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'pre_escape' => null,
'preserves_safety' => null,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $filterArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $filterArgs);
}
return null;
}
public function getPreservesSafety()
{
return $this->options['preserves_safety'];
}
public function getPreEscape()
{
return $this->options['pre_escape'];
}
public function getCallable()
{
return $this->options['callable'];
}
}

View file

@ -1,37 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a function template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Function extends Twig_Filter
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View file

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a method template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Method extends Twig_Filter
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
}
}

View file

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter as a node.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Filter_Node extends Twig_Filter
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View file

@ -1,23 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterCallableInterface
{
public function getCallable();
}

View file

@ -1,42 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template filter.
*
* Use Twig_SimpleFilter instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FilterInterface
{
/**
* Compiles a filter.
*
* @return string The PHP code for the filter
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function getPreservesSafety();
public function getPreEscape();
public function setArguments($arguments);
public function getArguments();
}

View file

@ -1,71 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
abstract class Twig_Function implements Twig_FunctionInterface, Twig_FunctionCallableInterface
{
protected $options;
protected $arguments = array();
public function __construct(array $options = array())
{
$this->options = array_merge(array(
'needs_environment' => false,
'needs_context' => false,
'callable' => null,
), $options);
}
public function setArguments($arguments)
{
$this->arguments = $arguments;
}
public function getArguments()
{
return $this->arguments;
}
public function needsEnvironment()
{
return $this->options['needs_environment'];
}
public function needsContext()
{
return $this->options['needs_context'];
}
public function getSafe(Twig_Node $functionArgs)
{
if (isset($this->options['is_safe'])) {
return $this->options['is_safe'];
}
if (isset($this->options['is_safe_callback'])) {
return call_user_func($this->options['is_safe_callback'], $functionArgs);
}
return array();
}
public function getCallable()
{
return $this->options['callable'];
}
}

View file

@ -1,38 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a function template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Function extends Twig_Function
{
protected $function;
public function __construct($function, array $options = array())
{
$options['callable'] = $function;
parent::__construct($options);
$this->function = $function;
}
public function compile()
{
return $this->function;
}
}

View file

@ -1,40 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a method template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Method extends Twig_Function
{
protected $extension;
protected $method;
public function __construct(Twig_ExtensionInterface $extension, $method, array $options = array())
{
$options['callable'] = array($extension, $method);
parent::__construct($options);
$this->extension = $extension;
$this->method = $method;
}
public function compile()
{
return sprintf('$this->env->getExtension(\'%s\')->%s', $this->extension->getName(), $this->method);
}
}

View file

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function as a node.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
class Twig_Function_Node extends Twig_Function
{
protected $class;
public function __construct($class, array $options = array())
{
parent::__construct($options);
$this->class = $class;
}
public function getClass()
{
return $this->class;
}
public function compile()
{
}
}

View file

@ -1,23 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2012 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a callable template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionCallableInterface
{
public function getCallable();
}

View file

@ -1,39 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2010 Fabien Potencier
* (c) 2010 Arnaud Le Blanc
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Represents a template function.
*
* Use Twig_SimpleFunction instead.
*
* @author Arnaud Le Blanc <arnaud.lb@gmail.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_FunctionInterface
{
/**
* Compiles a function.
*
* @return string The PHP code for the function
*/
public function compile();
public function needsEnvironment();
public function needsContext();
public function getSafe(Twig_Node $filterArgs);
public function setArguments($arguments);
public function getArguments();
}

View file

@ -1,408 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
* (c) 2009 Armin Ronacher
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Lexes a template string.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Lexer implements Twig_LexerInterface
{
protected $tokens;
protected $code;
protected $cursor;
protected $lineno;
protected $end;
protected $state;
protected $states;
protected $brackets;
protected $env;
protected $filename;
protected $options;
protected $regexes;
protected $position;
protected $positions;
protected $currentVarBlockLine;
const STATE_DATA = 0;
const STATE_BLOCK = 1;
const STATE_VAR = 2;
const STATE_STRING = 3;
const STATE_INTERPOLATION = 4;
const REGEX_NAME = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/A';
const REGEX_NUMBER = '/[0-9]+(?:\.[0-9]+)?/A';
const REGEX_STRING = '/"([^#"\\\\]*(?:\\\\.[^#"\\\\]*)*)"|\'([^\'\\\\]*(?:\\\\.[^\'\\\\]*)*)\'/As';
const REGEX_DQ_STRING_DELIM = '/"/A';
const REGEX_DQ_STRING_PART = '/[^#"\\\\]*(?:(?:\\\\.|#(?!\{))[^#"\\\\]*)*/As';
const PUNCTUATION = '()[]{}?:.,|';
public function __construct(Twig_Environment $env, array $options = array())
{
$this->env = $env;
$this->options = array_merge(array(
'tag_comment' => array('{#', '#}'),
'tag_block' => array('{%', '%}'),
'tag_variable' => array('{{', '}}'),
'whitespace_trim' => '-',
'interpolation' => array('#{', '}'),
), $options);
$this->regexes = array(
'lex_var' => '/\s*'.preg_quote($this->options['whitespace_trim'].$this->options['tag_variable'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_variable'][1], '/').'/A',
'lex_block' => '/\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')\n?/A',
'lex_raw_data' => '/('.preg_quote($this->options['tag_block'][0].$this->options['whitespace_trim'], '/').'|'.preg_quote($this->options['tag_block'][0], '/').')\s*(?:end%s)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/s',
'operator' => $this->getOperatorRegex(),
'lex_comment' => '/(?:'.preg_quote($this->options['whitespace_trim'], '/').preg_quote($this->options['tag_comment'][1], '/').'\s*|'.preg_quote($this->options['tag_comment'][1], '/').')\n?/s',
'lex_block_raw' => '/\s*(raw|verbatim)\s*(?:'.preg_quote($this->options['whitespace_trim'].$this->options['tag_block'][1], '/').'\s*|\s*'.preg_quote($this->options['tag_block'][1], '/').')/As',
'lex_block_line' => '/\s*line\s+(\d+)\s*'.preg_quote($this->options['tag_block'][1], '/').'/As',
'lex_tokens_start' => '/('.preg_quote($this->options['tag_variable'][0], '/').'|'.preg_quote($this->options['tag_block'][0], '/').'|'.preg_quote($this->options['tag_comment'][0], '/').')('.preg_quote($this->options['whitespace_trim'], '/').')?/s',
'interpolation_start' => '/'.preg_quote($this->options['interpolation'][0], '/').'\s*/A',
'interpolation_end' => '/\s*'.preg_quote($this->options['interpolation'][1], '/').'/A',
);
}
/**
* Tokenizes a source code.
*
* @param string $code The source code
* @param string $filename A unique identifier for the source code
*
* @return Twig_TokenStream A token stream instance
*/
public function tokenize($code, $filename = null)
{
if (function_exists('mb_internal_encoding') && ((int) ini_get('mbstring.func_overload')) & 2) {
$mbEncoding = mb_internal_encoding();
mb_internal_encoding('ASCII');
}
$this->code = str_replace(array("\r\n", "\r"), "\n", $code);
$this->filename = $filename;
$this->cursor = 0;
$this->lineno = 1;
$this->end = strlen($this->code);
$this->tokens = array();
$this->state = self::STATE_DATA;
$this->states = array();
$this->brackets = array();
$this->position = -1;
// find all token starts in one go
preg_match_all($this->regexes['lex_tokens_start'], $this->code, $matches, PREG_OFFSET_CAPTURE);
$this->positions = $matches;
while ($this->cursor < $this->end) {
// dispatch to the lexing functions depending
// on the current state
switch ($this->state) {
case self::STATE_DATA:
$this->lexData();
break;
case self::STATE_BLOCK:
$this->lexBlock();
break;
case self::STATE_VAR:
$this->lexVar();
break;
case self::STATE_STRING:
$this->lexString();
break;
case self::STATE_INTERPOLATION:
$this->lexInterpolation();
break;
}
}
$this->pushToken(Twig_Token::EOF_TYPE);
if (!empty($this->brackets)) {
list($expect, $lineno) = array_pop($this->brackets);
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
if (isset($mbEncoding)) {
mb_internal_encoding($mbEncoding);
}
return new Twig_TokenStream($this->tokens, $this->filename);
}
protected function lexData()
{
// if no matches are left we return the rest of the template as simple text token
if ($this->position == count($this->positions[0]) - 1) {
$this->pushToken(Twig_Token::TEXT_TYPE, substr($this->code, $this->cursor));
$this->cursor = $this->end;
return;
}
// Find the first token after the current cursor
$position = $this->positions[0][++$this->position];
while ($position[1] < $this->cursor) {
if ($this->position == count($this->positions[0]) - 1) {
return;
}
$position = $this->positions[0][++$this->position];
}
// push the template text first
$text = $textContent = substr($this->code, $this->cursor, $position[1] - $this->cursor);
if (isset($this->positions[2][$this->position][0])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
$this->moveCursor($textContent.$position[0]);
switch ($this->positions[1][$this->position][0]) {
case $this->options['tag_comment'][0]:
$this->lexComment();
break;
case $this->options['tag_block'][0]:
// raw data?
if (preg_match($this->regexes['lex_block_raw'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lexRawData($match[1]);
// {% line \d+ %}
} elseif (preg_match($this->regexes['lex_block_line'], $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
$this->lineno = (int) $match[1];
} else {
$this->pushToken(Twig_Token::BLOCK_START_TYPE);
$this->pushState(self::STATE_BLOCK);
$this->currentVarBlockLine = $this->lineno;
}
break;
case $this->options['tag_variable'][0]:
$this->pushToken(Twig_Token::VAR_START_TYPE);
$this->pushState(self::STATE_VAR);
$this->currentVarBlockLine = $this->lineno;
break;
}
}
protected function lexBlock()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_block'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::BLOCK_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexVar()
{
if (empty($this->brackets) && preg_match($this->regexes['lex_var'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::VAR_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function lexExpression()
{
// whitespace
if (preg_match('/\s+/A', $this->code, $match, null, $this->cursor)) {
$this->moveCursor($match[0]);
if ($this->cursor >= $this->end) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $this->state === self::STATE_BLOCK ? 'block' : 'variable'), $this->currentVarBlockLine, $this->filename);
}
}
// operators
if (preg_match($this->regexes['operator'], $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::OPERATOR_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// names
elseif (preg_match(self::REGEX_NAME, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::NAME_TYPE, $match[0]);
$this->moveCursor($match[0]);
}
// numbers
elseif (preg_match(self::REGEX_NUMBER, $this->code, $match, null, $this->cursor)) {
$number = (float) $match[0]; // floats
if (ctype_digit($match[0]) && $number <= PHP_INT_MAX) {
$number = (int) $match[0]; // integers lower than the maximum
}
$this->pushToken(Twig_Token::NUMBER_TYPE, $number);
$this->moveCursor($match[0]);
}
// punctuation
elseif (false !== strpos(self::PUNCTUATION, $this->code[$this->cursor])) {
// opening bracket
if (false !== strpos('([{', $this->code[$this->cursor])) {
$this->brackets[] = array($this->code[$this->cursor], $this->lineno);
}
// closing bracket
elseif (false !== strpos(')]}', $this->code[$this->cursor])) {
if (empty($this->brackets)) {
throw new Twig_Error_Syntax(sprintf('Unexpected "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
}
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != strtr($expect, '([{', ')]}')) {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
}
$this->pushToken(Twig_Token::PUNCTUATION_TYPE, $this->code[$this->cursor]);
++$this->cursor;
}
// strings
elseif (preg_match(self::REGEX_STRING, $this->code, $match, null, $this->cursor)) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes(substr($match[0], 1, -1)));
$this->moveCursor($match[0]);
}
// opening double quoted string
elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array('"', $this->lineno);
$this->pushState(self::STATE_STRING);
$this->moveCursor($match[0]);
}
// unlexable
else {
throw new Twig_Error_Syntax(sprintf('Unexpected character "%s"', $this->code[$this->cursor]), $this->lineno, $this->filename);
}
}
protected function lexRawData($tag)
{
if (!preg_match(str_replace('%s', $tag, $this->regexes['lex_raw_data']), $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax(sprintf('Unexpected end of file: Unclosed "%s" block', $tag), $this->lineno, $this->filename);
}
$text = substr($this->code, $this->cursor, $match[0][1] - $this->cursor);
$this->moveCursor($text.$match[0][0]);
if (false !== strpos($match[1][0], $this->options['whitespace_trim'])) {
$text = rtrim($text);
}
$this->pushToken(Twig_Token::TEXT_TYPE, $text);
}
protected function lexComment()
{
if (!preg_match($this->regexes['lex_comment'], $this->code, $match, PREG_OFFSET_CAPTURE, $this->cursor)) {
throw new Twig_Error_Syntax('Unclosed comment', $this->lineno, $this->filename);
}
$this->moveCursor(substr($this->code, $this->cursor, $match[0][1] - $this->cursor).$match[0][0]);
}
protected function lexString()
{
if (preg_match($this->regexes['interpolation_start'], $this->code, $match, null, $this->cursor)) {
$this->brackets[] = array($this->options['interpolation'][0], $this->lineno);
$this->pushToken(Twig_Token::INTERPOLATION_START_TYPE);
$this->moveCursor($match[0]);
$this->pushState(self::STATE_INTERPOLATION);
} elseif (preg_match(self::REGEX_DQ_STRING_PART, $this->code, $match, null, $this->cursor) && strlen($match[0]) > 0) {
$this->pushToken(Twig_Token::STRING_TYPE, stripcslashes($match[0]));
$this->moveCursor($match[0]);
} elseif (preg_match(self::REGEX_DQ_STRING_DELIM, $this->code, $match, null, $this->cursor)) {
list($expect, $lineno) = array_pop($this->brackets);
if ($this->code[$this->cursor] != '"') {
throw new Twig_Error_Syntax(sprintf('Unclosed "%s"', $expect), $lineno, $this->filename);
}
$this->popState();
++$this->cursor;
}
}
protected function lexInterpolation()
{
$bracket = end($this->brackets);
if ($this->options['interpolation'][0] === $bracket[0] && preg_match($this->regexes['interpolation_end'], $this->code, $match, null, $this->cursor)) {
array_pop($this->brackets);
$this->pushToken(Twig_Token::INTERPOLATION_END_TYPE);
$this->moveCursor($match[0]);
$this->popState();
} else {
$this->lexExpression();
}
}
protected function pushToken($type, $value = '')
{
// do not push empty text tokens
if (Twig_Token::TEXT_TYPE === $type && '' === $value) {
return;
}
$this->tokens[] = new Twig_Token($type, $value, $this->lineno);
}
protected function moveCursor($text)
{
$this->cursor += strlen($text);
$this->lineno += substr_count($text, "\n");
}
protected function getOperatorRegex()
{
$operators = array_merge(
array('='),
array_keys($this->env->getUnaryOperators()),
array_keys($this->env->getBinaryOperators())
);
$operators = array_combine($operators, array_map('strlen', $operators));
arsort($operators);
$regex = array();
foreach ($operators as $operator => $length) {
// an operator that ends with a character must be followed by
// a whitespace or a parenthesis
if (ctype_alpha($operator[$length - 1])) {
$regex[] = preg_quote($operator, '/').'(?=[\s()])';
} else {
$regex[] = preg_quote($operator, '/');
}
}
return '/'.implode('|', $regex).'/A';
}
protected function pushState($state)
{
$this->states[] = $this->state;
$this->state = $state;
}
protected function popState()
{
if (0 === count($this->states)) {
throw new Exception('Cannot pop state without a previous state');
}
$this->state = array_pop($this->states);
}
}

View file

@ -1,29 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Interface implemented by lexer classes.
*
* @author Fabien Potencier <fabien@symfony.com>
* @deprecated since 1.12 (to be removed in 2.0)
*/
interface Twig_LexerInterface
{
/**
* Tokenizes a source code.
*
* @param string $code The source code
* @param string $filename A unique identifier for the source code
*
* @return Twig_TokenStream A token stream instance
*/
public function tokenize($code, $filename = null);
}

View file

@ -1,98 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2009 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads a template from an array.
*
* When using this loader with a cache mechanism, you should know that a new cache
* key is generated each time a template content "changes" (the cache key being the
* source code of the template). If you don't want to see your cache grows out of
* control, you need to take care of clearing the old cache file by yourself.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Array implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
protected $templates;
/**
* Constructor.
*
* @param array $templates An array of templates (keys are the names, and values are the source code)
*
* @see Twig_Loader
*/
public function __construct(array $templates)
{
$this->templates = array();
foreach ($templates as $name => $template) {
$this->templates[$name] = $template;
}
}
/**
* Adds or overrides a template.
*
* @param string $name The template name
* @param string $template The template source
*/
public function setTemplate($name, $template)
{
$this->templates[(string) $name] = $template;
}
/**
* {@inheritdoc}
*/
public function getSource($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $this->templates[$name];
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
return isset($this->templates[(string) $name]);
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return $this->templates[$name];
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
$name = (string) $name;
if (!isset($this->templates[$name])) {
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined.', $name));
}
return true;
}
}

View file

@ -1,135 +0,0 @@
<?php
/*
* This file is part of Twig.
*
* (c) 2011 Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/**
* Loads templates from other loaders.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class Twig_Loader_Chain implements Twig_LoaderInterface, Twig_ExistsLoaderInterface
{
private $hasSourceCache = array();
protected $loaders;
/**
* Constructor.
*
* @param Twig_LoaderInterface[] $loaders An array of loader instances
*/
public function __construct(array $loaders = array())
{
$this->loaders = array();
foreach ($loaders as $loader) {
$this->addLoader($loader);
}
}
/**
* Adds a loader instance.
*
* @param Twig_LoaderInterface $loader A Loader instance
*/
public function addLoader(Twig_LoaderInterface $loader)
{
$this->loaders[] = $loader;
$this->hasSourceCache = array();
}
/**
* {@inheritdoc}
*/
public function getSource($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getSource($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = $e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(', ', $exceptions)));
}
/**
* {@inheritdoc}
*/
public function exists($name)
{
$name = (string) $name;
if (isset($this->hasSourceCache[$name])) {
return $this->hasSourceCache[$name];
}
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && $loader->exists($name)) {
return $this->hasSourceCache[$name] = true;
}
try {
$loader->getSource($name);
return $this->hasSourceCache[$name] = true;
} catch (Twig_Error_Loader $e) {
}
}
return $this->hasSourceCache[$name] = false;
}
/**
* {@inheritdoc}
*/
public function getCacheKey($name)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->getCacheKey($name);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
}
/**
* {@inheritdoc}
*/
public function isFresh($name, $time)
{
$exceptions = array();
foreach ($this->loaders as $loader) {
if ($loader instanceof Twig_ExistsLoaderInterface && !$loader->exists($name)) {
continue;
}
try {
return $loader->isFresh($name, $time);
} catch (Twig_Error_Loader $e) {
$exceptions[] = get_class($loader).': '.$e->getMessage();
}
}
throw new Twig_Error_Loader(sprintf('Template "%s" is not defined (%s).', $name, implode(' ', $exceptions)));
}
}

Some files were not shown because too many files have changed in this diff Show more