Compare commits
81 commits
Author | SHA1 | Date | |
---|---|---|---|
|
ae9a8ebbba | ||
|
914dd9453c | ||
|
869ab1f2e0 | ||
|
0fa644e64b | ||
|
a3dd0b9fbd | ||
|
efa51f66b1 | ||
|
0c87fae09b | ||
|
311e21bcf3 | ||
|
35d894ec1a | ||
|
a5fefa46fb | ||
|
a178e85c07 | ||
|
268f4033f1 | ||
|
1da5e26d57 | ||
|
6698130b0f | ||
|
0068406e23 | ||
|
81c21722d3 | ||
|
c0639ccef6 | ||
|
3b6984dbd7 | ||
|
60d0f5403c | ||
|
998f0d1dbd | ||
|
cb2cf3a4a3 | ||
|
00ac6c0700 | ||
|
dde3a76d78 | ||
|
070714d1d8 | ||
|
872da5714c | ||
|
71c0dfbffb | ||
|
9a8b3da2ae | ||
|
a3f801b89a | ||
|
0f48280f73 | ||
|
6f1fc9f8de | ||
|
9d08d4247a | ||
|
1aacce829f | ||
|
67408ce935 | ||
|
261b5c68a7 | ||
|
e3365a4345 | ||
|
4bf3260766 | ||
|
93dbbe750d | ||
|
61880d150e | ||
|
bdb86d37ff | ||
|
f4706bb8e1 | ||
|
d01918a2fe | ||
|
b9de38f7f2 | ||
|
23b00ba1e0 | ||
|
92907a1361 | ||
|
8b4b20fe97 | ||
|
68c47429ef | ||
|
e33f6c8148 | ||
|
76a761c3a2 | ||
|
0f152c7165 | ||
|
f7ccd0b703 | ||
|
5a81fe89d8 | ||
|
4e572adb33 | ||
|
1b956afc29 | ||
|
fe6c8f805a | ||
|
41fc15a7e8 | ||
|
edfab74ff2 | ||
|
f7637ad335 | ||
|
888b910a84 | ||
|
4b95733a51 | ||
|
59d9514ed4 | ||
|
c3c7606d2c | ||
|
9bf317f903 | ||
|
d6f9806b32 | ||
|
bc816febfc | ||
|
efc4fb5288 | ||
|
9f596ac5b7 | ||
|
de5bd4399c | ||
|
1b1fa73fd9 | ||
|
646aa355e5 | ||
|
bdafcb5b96 | ||
|
62aa4dbc7e | ||
|
dffaa012f7 | ||
|
85d7573020 | ||
|
b1a58b9300 | ||
|
812ae5c215 | ||
|
039dd4edb2 | ||
|
b6a0343118 | ||
|
727d8a12c0 | ||
|
2ee41e9a8d | ||
|
a053a72a12 | ||
|
718b790b19 |
33 changed files with 1663 additions and 1232 deletions
486
.build/build.sh
Executable file
486
.build/build.sh
Executable file
|
@ -0,0 +1,486 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Pico -- build.sh
|
||||||
|
# Builds a new Pico release and creates release archives.
|
||||||
|
#
|
||||||
|
# This file is part of Pico, a stupidly simple, blazing fast, flat file CMS.
|
||||||
|
# Visit us at https://picocms.org/ for more info.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017 Daniel Rudolf <https://www.daniel-rudolf.de>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the MIT license.
|
||||||
|
# For a copy, see LICENSE file or <https://opensource.org/licenses/MIT>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# License-Filename: LICENSE
|
||||||
|
|
||||||
|
set -eu -o pipefail
|
||||||
|
export LC_ALL=C
|
||||||
|
|
||||||
|
# env variables
|
||||||
|
PHP="${PHP:-php}"
|
||||||
|
export -n PHP
|
||||||
|
|
||||||
|
COMPOSER="${COMPOSER:-composer}"
|
||||||
|
export -n COMPOSER
|
||||||
|
|
||||||
|
if ! which "$PHP" > /dev/null; then
|
||||||
|
echo "Missing script dependency: php" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! which "$COMPOSER" > /dev/null; then
|
||||||
|
echo "Missing script dependency: composer" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! which "git" > /dev/null; then
|
||||||
|
echo "Missing script dependency: git" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! which "gh" > /dev/null; then
|
||||||
|
echo "Missing script dependency: gh" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! which "rsync" > /dev/null; then
|
||||||
|
echo "Missing script dependency: rsync" >&2
|
||||||
|
exit 1
|
||||||
|
elif ! which "jq" > /dev/null; then
|
||||||
|
echo "Missing script dependency: jq" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# parameters
|
||||||
|
BUILD_NAME="pico"
|
||||||
|
BUILD_PROJECT="picocms/pico"
|
||||||
|
BUILD_VERSION=
|
||||||
|
|
||||||
|
PICO_COMPOSER_NAME="pico-composer"
|
||||||
|
PICO_COMPOSER_PROJECT="picocms/pico-composer"
|
||||||
|
PICO_COMPOSER_DIR=
|
||||||
|
|
||||||
|
PICO_THEME_NAME="pico-theme"
|
||||||
|
PICO_THEME_PROJECT="picocms/pico-theme"
|
||||||
|
PICO_THEME_DIR=
|
||||||
|
|
||||||
|
PICO_DEPRECATED_NAME="pico-deprecated"
|
||||||
|
PICO_DEPRECATED_PROJECT="picocms/pico-deprecated"
|
||||||
|
PICO_DEPRECATED_DIR=
|
||||||
|
|
||||||
|
PHP_VERSION="7.2"
|
||||||
|
|
||||||
|
# options
|
||||||
|
VERSION=
|
||||||
|
PUBLISH=
|
||||||
|
NOCHECK=
|
||||||
|
NOCLEAN=
|
||||||
|
|
||||||
|
while [ $# -gt 0 ]; do
|
||||||
|
if [ "$1" == "--help" ]; then
|
||||||
|
echo "Usage:"
|
||||||
|
echo " build.sh [OPTIONS]... [VERSION]"
|
||||||
|
echo
|
||||||
|
echo "Builds a new Pico release and creates release archives."
|
||||||
|
echo
|
||||||
|
echo "Help options:"
|
||||||
|
echo " --help display this help and exit"
|
||||||
|
echo
|
||||||
|
echo "Application options:"
|
||||||
|
echo " --publish create GitHub release and upload artifacts"
|
||||||
|
echo " --pico-composer PATH path to a local copy of '$PICO_COMPOSER_PROJECT'"
|
||||||
|
echo " --pico-theme PATH path to a local copy of '$PICO_THEME_PROJECT'"
|
||||||
|
echo " --pico-deprecated PATH path to a local copy of '$PICO_DEPRECATED_PROJECT'"
|
||||||
|
echo " --no-check skip version checks for dev builds"
|
||||||
|
echo " --no-clean don't remove build dir on exit"
|
||||||
|
echo
|
||||||
|
echo "You must run this script from within Pico's source directory. Please note"
|
||||||
|
echo "that this script will perform a large number of strict sanity checks before"
|
||||||
|
echo "building a new non-development version of Pico. VERSION must start with 'v'."
|
||||||
|
exit 0
|
||||||
|
elif [ "$1" == "--publish" ]; then
|
||||||
|
PUBLISH="y"
|
||||||
|
shift
|
||||||
|
elif [ "$1" == "--no-check" ]; then
|
||||||
|
NOCHECK="y"
|
||||||
|
shift
|
||||||
|
elif [ "$1" == "--no-clean" ]; then
|
||||||
|
NOCLEAN="y"
|
||||||
|
shift
|
||||||
|
elif [ "$1" == "--pico-composer" ] && [ $# -ge 2 ]; then
|
||||||
|
PICO_COMPOSER_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
elif [ "$1" == "--pico-theme" ] && [ $# -ge 2 ]; then
|
||||||
|
PICO_THEME_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
elif [ "$1" == "--pico-deprecated" ] && [ $# -ge 2 ]; then
|
||||||
|
PICO_DEPRECATED_DIR="$2"
|
||||||
|
shift 2
|
||||||
|
elif [ -z "$VERSION" ] && [ "${1:0:1}" == "v" ]; then
|
||||||
|
VERSION="$1"
|
||||||
|
shift
|
||||||
|
else
|
||||||
|
echo "Unknown option: $1" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
# check options and current working dir
|
||||||
|
if [ ! -f "./composer.json" ] || [ ! -f "./lib/Pico.php" ]; then
|
||||||
|
echo "You must run this from within Pico's source directory" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$(git rev-parse --is-inside-work-tree 2> /dev/null)" != "true" ]; then
|
||||||
|
echo "You must run this from within a non-bare Git repository" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$PICO_COMPOSER_DIR" ]; then
|
||||||
|
if [ ! -f "$PICO_COMPOSER_DIR/composer.json" ] || [ ! -f "$PICO_COMPOSER_DIR/index.php" ]; then
|
||||||
|
echo "You must pass a source directory of '$PICO_COMPOSER_PROJECT' as '--pico-composer': $PICO_COMPOSER_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$(git -C "$PICO_COMPOSER_DIR" rev-parse --is-inside-work-tree 2> /dev/null)" != "true" ]; then
|
||||||
|
echo "You must pass a non-bare Git repository as '--pico-composer': $PICO_COMPOSER_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$PICO_THEME_DIR" ]; then
|
||||||
|
if [ ! -f "$PICO_THEME_DIR/composer.json" ] || [ ! -f "$PICO_THEME_DIR/pico-theme.yml" ]; then
|
||||||
|
echo "You must pass a source directory of '$PICO_THEME_PROJECT' as '--pico-theme': $PICO_THEME_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$(git -C "$PICO_THEME_DIR" rev-parse --is-inside-work-tree 2> /dev/null)" != "true" ]; then
|
||||||
|
echo "You must pass a non-bare Git repository as '--pico-theme': $PICO_THEME_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$PICO_DEPRECATED_DIR" ]; then
|
||||||
|
if [ ! -f "$PICO_DEPRECATED_DIR/composer.json" ] || [ ! -f "$PICO_DEPRECATED_DIR/PicoDeprecated.php" ]; then
|
||||||
|
echo "You must pass a source directory of '$PICO_DEPRECATED_PROJECT' as '--pico-deprecated': $PICO_DEPRECATED_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$(git -C "$PICO_DEPRECATED_DIR" rev-parse --is-inside-work-tree 2> /dev/null)" != "true" ]; then
|
||||||
|
echo "You must pass a non-bare Git repository as '--pico-deprecated': $PICO_DEPRECATED_DIR" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# parse version
|
||||||
|
function parse_version {
|
||||||
|
VERSION_FULL="${1#v}"
|
||||||
|
|
||||||
|
if ! [[ "$VERSION_FULL" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z\.\-]+))?(\+([0-9A-Za-z\.\-]+))?$ ]]; then
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
VERSION_MAJOR="${BASH_REMATCH[1]}"
|
||||||
|
VERSION_MINOR="${BASH_REMATCH[2]}"
|
||||||
|
VERSION_PATCH="${BASH_REMATCH[3]}"
|
||||||
|
VERSION_SUFFIX="${BASH_REMATCH[5]}"
|
||||||
|
|
||||||
|
VERSION_STABILITY="stable"
|
||||||
|
if [[ "$VERSION_SUFFIX" =~ ^(dev|a|alpha|b|beta|rc)?([.-]?[0-9]+)?([.-](dev))?$ ]]; then
|
||||||
|
if [ "${BASH_REMATCH[1]}" == "dev" ] || [ "${BASH_REMATCH[4]}" == "dev" ]; then
|
||||||
|
VERSION_STABILITY="dev"
|
||||||
|
elif [ "${BASH_REMATCH[1]}" == "a" ] || [ "${BASH_REMATCH[1]}" == "alpha" ]; then
|
||||||
|
VERSION_STABILITY="alpha"
|
||||||
|
elif [ "${BASH_REMATCH[1]}" == "b" ] || [ "${BASH_REMATCH[1]}" == "beta" ]; then
|
||||||
|
VERSION_STABILITY="beta"
|
||||||
|
elif [ "${BASH_REMATCH[1]}" == "rc" ]; then
|
||||||
|
VERSION_STABILITY="rc"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
BUILD_VERSION="v$("$PHP" -r 'require("./lib/Pico.php"); echo Pico::VERSION;')"
|
||||||
|
|
||||||
|
if ! parse_version "$BUILD_VERSION"; then
|
||||||
|
echo "Unable to build Pico: Invalid Pico version '$BUILD_VERSION'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$VERSION" ]; then
|
||||||
|
GIT_LOCAL_HEAD="$(git rev-parse HEAD)"
|
||||||
|
GIT_LOCAL_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
|
DATETIME="$(date -u +'%Y%m%dT%H%M%SZ')"
|
||||||
|
|
||||||
|
VERSION="v$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH"
|
||||||
|
[ -z "$VERSION_SUFFIX" ] || VERSION+="-$VERSION_SUFFIX"
|
||||||
|
[ "$VERSION_STABILITY" == "dev" ] || VERSION+="-dev"
|
||||||
|
VERSION+="+git.$GIT_LOCAL_HEAD.$DATETIME"
|
||||||
|
|
||||||
|
if ! parse_version "$VERSION"; then
|
||||||
|
echo "Unable to build Pico: Invalid build version '$VERSION'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPENDENCY_VERSION="dev-$GIT_LOCAL_BRANCH"
|
||||||
|
else
|
||||||
|
if ! parse_version "$VERSION"; then
|
||||||
|
echo "Unable to build Pico: Invalid build version '$VERSION'" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
DEPENDENCY_VERSION=
|
||||||
|
if [ "$VERSION_STABILITY" == "dev" ]; then
|
||||||
|
DEPENDENCY_VERSION="$(jq -r --arg ALIAS "$VERSION_MAJOR.$VERSION_MINOR.x-dev" \
|
||||||
|
'.extra."branch-alias"|to_entries|map(select(.value==$ALIAS).key)[0]//empty' \
|
||||||
|
"composer.json")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "$DEPENDENCY_VERSION" ]; then
|
||||||
|
DEPENDENCY_VERSION="$VERSION_MAJOR.$VERSION_MINOR.$VERSION_PATCH"
|
||||||
|
[ -z "$VERSION_SUFFIX" ] || DEPENDENCY_VERSION+="-$VERSION_SUFFIX"
|
||||||
|
[ "$VERSION_STABILITY" == "stable" ] || DEPENDENCY_VERSION+="@$VERSION_STABILITY"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# build checks
|
||||||
|
if [ "$VERSION_STABILITY" != "dev" ]; then
|
||||||
|
GIT_LOCAL_CLEAN="$(git status --porcelain)"
|
||||||
|
GIT_LOCAL_HEAD="$(git rev-parse HEAD)"
|
||||||
|
GIT_LOCAL_TAG="$(git rev-parse --verify "refs/tags/$VERSION" 2> /dev/null || true)"
|
||||||
|
GIT_REMOTE="$(git 'for-each-ref' --format='%(upstream:remotename)' "$(git symbolic-ref -q HEAD)")"
|
||||||
|
GIT_REMOTE_TAG="$(git ls-remote "${GIT_REMOTE:-origin}" "refs/tags/$VERSION" 2> /dev/null | cut -f 1 || true)"
|
||||||
|
PHP_VERSION_LOCAL="$("$PHP" -r 'echo PHP_MAJOR_VERSION . "." . PHP_MINOR_VERSION;')"
|
||||||
|
|
||||||
|
if [ "$VERSION" != "$BUILD_VERSION" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but Pico indicates $BUILD_VERSION" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ -n "$GIT_LOCAL_CLEAN" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but the working tree is not clean" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ -z "$GIT_LOCAL_TAG" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but no matching local Git tag was found" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$GIT_LOCAL_HEAD" != "$GIT_LOCAL_TAG" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but the matching Git tag is not checked out" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ -z "$GIT_REMOTE_TAG" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but no matching remote Git tag was found" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$GIT_LOCAL_TAG" != "$GIT_REMOTE_TAG" ]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but the matching local and remote Git tags differ" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ "$PHP_VERSION_LOCAL" != "$PHP_VERSION" ]; then
|
||||||
|
echo "Unable to build Pico: Refusing to build Pico with PHP $PHP_VERSION_LOCAL, expecting PHP $PHP_VERSION" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ -n "$PICO_COMPOSER_DIR" ] || [ -n "$PICO_THEME_DIR" ] || [ -n "$PICO_DEPRECATED_DIR" ]; then
|
||||||
|
echo "Unable to build Pico: Refusing to build a non-dev version with local dependencies" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if [ -z "$NOCHECK" ] && [[ "$VERSION" != "$BUILD_VERSION"* ]]; then
|
||||||
|
echo "Unable to build Pico: Building $VERSION, but Pico indicates $BUILD_VERSION" >&2
|
||||||
|
exit 1
|
||||||
|
elif [ -n "$PUBLISH" ]; then
|
||||||
|
echo "Unable to build Pico: Refusing to publish a dev version" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# build in progress...
|
||||||
|
APP_DIR="$PWD"
|
||||||
|
|
||||||
|
BUILD_DIR="$(mktemp -d)"
|
||||||
|
[ -n "$NOCLEAN" ] || trap "rm -rf ${BUILD_DIR@Q}" ERR EXIT
|
||||||
|
|
||||||
|
echo "Building Pico $BUILD_VERSION ($VERSION)..."
|
||||||
|
[ -z "$NOCLEAN" ] || echo "Build directory: $BUILD_DIR"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# prepare dev versions of components
|
||||||
|
if [ "$VERSION_STABILITY" == "dev" ]; then
|
||||||
|
# copy dev version of Pico
|
||||||
|
echo "Creating clean working tree copy of '$BUILD_PROJECT'..."
|
||||||
|
rsync -a \
|
||||||
|
--exclude="/.build" \
|
||||||
|
--exclude="/.git" \
|
||||||
|
--exclude="/.github" \
|
||||||
|
--exclude="/assets/.gitignore" \
|
||||||
|
--exclude="/config/.gitignore" \
|
||||||
|
--exclude="/content/.gitignore" \
|
||||||
|
--exclude="/plugins/.gitignore" \
|
||||||
|
--exclude="/themes/.gitignore" \
|
||||||
|
--exclude="/.gitattributes" \
|
||||||
|
--exclude="/.gitignore" \
|
||||||
|
--exclude="/.phpcs.xml" \
|
||||||
|
--exclude="/.phpdoc.xml" \
|
||||||
|
--exclude-from=<(git ls-files --exclude-standard -oi --directory) \
|
||||||
|
./ "$BUILD_DIR/$BUILD_NAME/"
|
||||||
|
|
||||||
|
# copy dev version of Composer starter project
|
||||||
|
if [ -n "$PICO_COMPOSER_DIR" ]; then
|
||||||
|
echo "Creating clean working tree copy of '$PICO_COMPOSER_PROJECT'..."
|
||||||
|
rsync -a \
|
||||||
|
--exclude="/.git" \
|
||||||
|
--exclude="/assets/.gitignore" \
|
||||||
|
--exclude="/config/.gitignore" \
|
||||||
|
--exclude="/content/.gitignore" \
|
||||||
|
--exclude="/plugins/.gitignore" \
|
||||||
|
--exclude="/themes/.gitignore" \
|
||||||
|
--exclude="/.gitattributes" \
|
||||||
|
--exclude="/.gitignore" \
|
||||||
|
--exclude-from=<(git -C "$PICO_COMPOSER_DIR" ls-files --exclude-standard -oi --directory) \
|
||||||
|
"$PICO_COMPOSER_DIR/" "$BUILD_DIR/$PICO_COMPOSER_NAME/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy dev version of default theme
|
||||||
|
if [ -n "$PICO_THEME_DIR" ]; then
|
||||||
|
echo "Creating clean working tree copy of '$PICO_THEME_PROJECT'..."
|
||||||
|
rsync -a \
|
||||||
|
--exclude="/.git" \
|
||||||
|
--exclude="/.github" \
|
||||||
|
--exclude="/.gitattributes" \
|
||||||
|
--exclude="/.gitignore" \
|
||||||
|
--exclude-from=<(git -C "$PICO_THEME_DIR" ls-files --exclude-standard -oi --directory) \
|
||||||
|
"$PICO_THEME_DIR/" "$BUILD_DIR/$PICO_THEME_NAME/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# copy dev version of PicoDeprecated
|
||||||
|
if [ -n "$PICO_DEPRECATED_DIR" ]; then
|
||||||
|
echo "Creating clean working tree copy of '$PICO_DEPRECATED_PROJECT'..."
|
||||||
|
rsync -a \
|
||||||
|
--exclude="/.build" \
|
||||||
|
--exclude="/.git" \
|
||||||
|
--exclude="/.github" \
|
||||||
|
--exclude="/.gitattributes" \
|
||||||
|
--exclude="/.gitignore" \
|
||||||
|
--exclude="/.phpcs.xml" \
|
||||||
|
--exclude-from=<(git -C "$PICO_DEPRECATED_DIR" ls-files --exclude-standard -oi --directory) \
|
||||||
|
"$PICO_DEPRECATED_DIR/" "$BUILD_DIR/$PICO_DEPRECATED_NAME/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# download Composer starter project
|
||||||
|
if [ "$VERSION_STABILITY" != "dev" ] || [ -z "$PICO_COMPOSER_DIR" ]; then
|
||||||
|
PICO_COMPOSER_VERSION="$DEPENDENCY_VERSION"
|
||||||
|
[[ "$PICO_COMPOSER_VERSION" == "dev-"* ]] || PICO_COMPOSER_VERSION="$VERSION_MAJOR.$VERSION_MINOR"
|
||||||
|
|
||||||
|
echo "Setting up Pico's Composer starter project (version '$PICO_COMPOSER_VERSION')..."
|
||||||
|
"$COMPOSER" create-project --no-install "$PICO_COMPOSER_PROJECT" \
|
||||||
|
"$BUILD_DIR/$PICO_COMPOSER_NAME" \
|
||||||
|
"$PICO_COMPOSER_VERSION"
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# switch to build dir...
|
||||||
|
cd "$BUILD_DIR/$PICO_COMPOSER_NAME"
|
||||||
|
|
||||||
|
# inject local component copies
|
||||||
|
if [ "$VERSION_STABILITY" == "dev" ]; then
|
||||||
|
function composer_repo_config {
|
||||||
|
jq -nc --arg PACKAGE "$1" --arg VERSION "$2" --arg URL "$3" \
|
||||||
|
'{"type": "path", "url": $URL, options: {"symlink": false, "versions": {($PACKAGE): $VERSION}}}'
|
||||||
|
}
|
||||||
|
|
||||||
|
echo "Adding Composer repository for '$BUILD_PROJECT'..."
|
||||||
|
"$COMPOSER" config repositories."$BUILD_NAME" \
|
||||||
|
"$(composer_repo_config "$BUILD_PROJECT" "$DEPENDENCY_VERSION" "$BUILD_DIR/$BUILD_NAME")"
|
||||||
|
|
||||||
|
if [ -n "$PICO_THEME_DIR" ]; then
|
||||||
|
echo "Adding Composer repository for '$PICO_THEME_PROJECT'..."
|
||||||
|
"$COMPOSER" config repositories."$PICO_THEME_NAME" \
|
||||||
|
"$(composer_repo_config "$PICO_THEME_PROJECT" "$DEPENDENCY_VERSION" "$BUILD_DIR/$PICO_THEME_NAME")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -n "$PICO_DEPRECATED_DIR" ]; then
|
||||||
|
echo "Adding Composer repository for '$PICO_DEPRECATED_PROJECT'..."
|
||||||
|
"$COMPOSER" config repositories."$PICO_DEPRECATED_NAME" \
|
||||||
|
"$(composer_repo_config "$PICO_DEPRECATED_PROJECT" "$DEPENDENCY_VERSION" "$BUILD_DIR/$PICO_DEPRECATED_NAME")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
fi
|
||||||
|
|
||||||
|
# update build version constraints
|
||||||
|
echo "Updating Composer dependency version constraints..."
|
||||||
|
"$COMPOSER" require --no-update \
|
||||||
|
"$BUILD_PROJECT $DEPENDENCY_VERSION" \
|
||||||
|
"$PICO_THEME_PROJECT $DEPENDENCY_VERSION" \
|
||||||
|
"$PICO_DEPRECATED_PROJECT $DEPENDENCY_VERSION"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# 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 "Installing Composer dependencies..."
|
||||||
|
"$COMPOSER" install --no-dev --optimize-autoloader
|
||||||
|
echo
|
||||||
|
|
||||||
|
# prepare release
|
||||||
|
echo "Replacing 'index.php'..."
|
||||||
|
cp "vendor/$BUILD_PROJECT/index.php.dist" index.php
|
||||||
|
|
||||||
|
echo "Adding 'README.md', 'CONTRIBUTING.md', 'CHANGELOG.md', 'SECURITY.md'..."
|
||||||
|
cp "vendor/$BUILD_PROJECT/README.md" README.md
|
||||||
|
cp "vendor/$BUILD_PROJECT/CONTRIBUTING.md" CONTRIBUTING.md
|
||||||
|
cp "vendor/$BUILD_PROJECT/CHANGELOG.md" CHANGELOG.md
|
||||||
|
cp "vendor/$BUILD_PROJECT/SECURITY.md" SECURITY.md
|
||||||
|
|
||||||
|
echo "Removing '.git' directory..."
|
||||||
|
rm -rf .git
|
||||||
|
|
||||||
|
echo "Removing '.git' directories of dependencies..."
|
||||||
|
find vendor/ -type d -path 'vendor/*/*/.git' -print0 | xargs -0 rm -rf
|
||||||
|
|
||||||
|
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 "Removing 'index.php' and 'index.php.dist' from 'vendor/$BUILD_PROJECT'"
|
||||||
|
rm -f "vendor/$BUILD_PROJECT/index.php"
|
||||||
|
rm -f "vendor/$BUILD_PROJECT/index.php.dist"
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# restore composer.json
|
||||||
|
echo "Restoring Composer dependency version constraints..."
|
||||||
|
"$COMPOSER" require --no-update \
|
||||||
|
"$BUILD_PROJECT ^$VERSION_MAJOR.$VERSION_MINOR" \
|
||||||
|
"$PICO_THEME_PROJECT ^$VERSION_MAJOR.$VERSION_MINOR" \
|
||||||
|
"$PICO_DEPRECATED_PROJECT ^$VERSION_MAJOR.$VERSION_MINOR"
|
||||||
|
|
||||||
|
if [ "$VERSION_STABILITY" == "dev" ]; then
|
||||||
|
echo "Removing Composer repositories..."
|
||||||
|
"$COMPOSER" config --unset repositories."$BUILD_NAME"
|
||||||
|
|
||||||
|
if [ -n "$PICO_THEME_DIR" ]; then
|
||||||
|
"$COMPOSER" config --unset repositories."$PICO_THEME_NAME"
|
||||||
|
fi
|
||||||
|
if [ -n "$PICO_DEPRECATED_DIR" ]; then
|
||||||
|
"$COMPOSER" config --unset repositories."$PICO_DEPRECATED_NAME"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo
|
||||||
|
|
||||||
|
# create release archives
|
||||||
|
ARCHIVE_FILENAME="$BUILD_NAME-release-$VERSION"
|
||||||
|
|
||||||
|
echo "Creating release archive '$ARCHIVE_FILENAME.tar.gz'..."
|
||||||
|
find . -mindepth 1 -maxdepth 1 -printf '%f\0' \
|
||||||
|
| xargs -0 -- tar -czf "$APP_DIR/$ARCHIVE_FILENAME.tar.gz" --
|
||||||
|
|
||||||
|
echo "Creating release archive '$ARCHIVE_FILENAME.zip'..."
|
||||||
|
zip -q -r "$APP_DIR/$ARCHIVE_FILENAME.zip" .
|
||||||
|
|
||||||
|
# publish release
|
||||||
|
if [ -n "$PUBLISH" ]; then
|
||||||
|
echo
|
||||||
|
|
||||||
|
# switch to app dir
|
||||||
|
cd "$APP_DIR"
|
||||||
|
|
||||||
|
# create GitHub release and upload release archives
|
||||||
|
echo "Creating GitHub release and uploading release archives..."
|
||||||
|
|
||||||
|
GITHUB_PRERELEASE=
|
||||||
|
[ "$VERSION_STABILITY" == "stable" ] || GITHUB_PRERELEASE="--prerelease"
|
||||||
|
|
||||||
|
gh release create "$VERSION" \
|
||||||
|
--title "Version $VERSION_FULL" \
|
||||||
|
--generate-notes \
|
||||||
|
"$GITHUB_PRERELEASE" \
|
||||||
|
"$APP_DIR/$ARCHIVE_FILENAME.tar.gz" \
|
||||||
|
"$APP_DIR/$ARCHIVE_FILENAME.zip"
|
||||||
|
fi
|
|
@ -1,25 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,44 +0,0 @@
|
||||||
#!/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"
|
|
|
@ -1,119 +0,0 @@
|
||||||
#!/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"
|
|
|
@ -1,19 +0,0 @@
|
||||||
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
|
|
|
@ -1,40 +0,0 @@
|
||||||
#!/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
|
|
|
@ -1,91 +0,0 @@
|
||||||
#!/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"
|
|
1
.gitattributes
vendored
1
.gitattributes
vendored
|
@ -9,4 +9,3 @@
|
||||||
/.gitignore export-ignore
|
/.gitignore export-ignore
|
||||||
/.phpcs.xml export-ignore
|
/.phpcs.xml export-ignore
|
||||||
/.phpdoc.xml export-ignore
|
/.phpdoc.xml export-ignore
|
||||||
/.travis.yml export-ignore
|
|
||||||
|
|
77
.github/actions/install/action.yml
vendored
Normal file
77
.github/actions/install/action.yml
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
name: Install Pico CMS
|
||||||
|
description: Install Pico CMS to the current working directory
|
||||||
|
|
||||||
|
inputs:
|
||||||
|
path:
|
||||||
|
description: Install Pico CMS in directory.
|
||||||
|
required: false
|
||||||
|
default: .
|
||||||
|
php-version:
|
||||||
|
description: PHP version to setup.
|
||||||
|
required: true
|
||||||
|
php-tools:
|
||||||
|
description: Setup additional PHP tools.
|
||||||
|
required: false
|
||||||
|
|
||||||
|
runs:
|
||||||
|
using: "composite"
|
||||||
|
steps:
|
||||||
|
- name: Setup PHP ${{ inputs.php-version }}
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ inputs.php-version }}
|
||||||
|
tools: composer, ${{ inputs.php-tools }}
|
||||||
|
|
||||||
|
- name: Setup Composer auth
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.path }}
|
||||||
|
run: |
|
||||||
|
composer config --global github-oauth.github.com "${{ github.token }}"
|
||||||
|
|
||||||
|
- name: Get Composer cache directory
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.path }}
|
||||||
|
run: |
|
||||||
|
COMPOSER_CACHE_DIR="$(composer config --global cache-dir)"
|
||||||
|
echo "COMPOSER_CACHE_DIR=$COMPOSER_CACHE_DIR" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Restore Composer cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ${{ env.COMPOSER_CACHE_DIR }}
|
||||||
|
key: ${{ runner.os }}-composer-php${{ inputs.php-version }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-composer-
|
||||||
|
|
||||||
|
- name: Setup Composer root version
|
||||||
|
if: ${{ github.ref_type == 'branch' }}
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.path }}
|
||||||
|
run: |
|
||||||
|
COMPOSER_ROOT_VERSION=
|
||||||
|
|
||||||
|
COMPOSER_ROOT_VERSION="$(composer config \
|
||||||
|
extra.branch-alias."dev-${GITHUB_HEAD_REF:-$GITHUB_REF_NAME}" \
|
||||||
|
2> /dev/null || true)"
|
||||||
|
|
||||||
|
if [ -z "$COMPOSER_ROOT_VERSION" ]; then
|
||||||
|
COMPOSER_ROOT_VERSION="$(php -r "
|
||||||
|
require('./lib/Pico.php');
|
||||||
|
echo preg_replace('/\.[0-9]+-dev$/', '.x-dev', Pico::VERSION);
|
||||||
|
")"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "COMPOSER_ROOT_VERSION=$COMPOSER_ROOT_VERSION" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Install Composer dependencies
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.path }}
|
||||||
|
run: |
|
||||||
|
composer install
|
||||||
|
|
||||||
|
- name: Read Pico version
|
||||||
|
shell: bash
|
||||||
|
working-directory: ${{ inputs.path }}
|
||||||
|
run: |
|
||||||
|
PICO_VERSION="$(php -r 'require("./lib/Pico.php"); echo Pico::VERSION;')"
|
||||||
|
echo "PICO_VERSION=$PICO_VERSION" | tee -a "$GITHUB_ENV"
|
97
.github/workflows/deploy-branch.yml
vendored
Normal file
97
.github/workflows/deploy-branch.yml
vendored
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
name: Git branch deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
- 'pico-3.0'
|
||||||
|
|
||||||
|
env:
|
||||||
|
WEBSITE_REPO_SLUG: picocms/picocms.github.io
|
||||||
|
WEBSITE_REPO_BRANCH: master
|
||||||
|
CI_TOOLS_SETUP: https://raw.githubusercontent.com/picocms/ci-tools/master/setup.sh
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
website:
|
||||||
|
name: Update website for branch updates
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
PHP_VERSION: '7.4'
|
||||||
|
BUILD_DIR: ./build
|
||||||
|
WEBSITE_DIR: ./website
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup CI tools
|
||||||
|
run: |
|
||||||
|
. <(curl -fsS -L "$CI_TOOLS_SETUP")
|
||||||
|
echo "CI_TOOLS_PATH=$CI_TOOLS_PATH" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
|
- name: Install Pico CMS
|
||||||
|
uses: ./build/.github/actions/install
|
||||||
|
with:
|
||||||
|
path: ${{ env.BUILD_DIR }}
|
||||||
|
php-version: ${{ env.PHP_VERSION }}
|
||||||
|
php-tools: phpdoc
|
||||||
|
|
||||||
|
- name: Read Pico milestone
|
||||||
|
working-directory: ${{ env.BUILD_DIR }}
|
||||||
|
run: |
|
||||||
|
PICO_VERSION_MILESTONE="$(php -r 'require("./lib/Pico.php"); preg_match("/^([0-9]+\.[0-9]+)\./", Pico::VERSION, $m); echo $m[1];')"
|
||||||
|
echo "PICO_VERSION_MILESTONE=$PICO_VERSION_MILESTONE" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Checkout website repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_REPO_SLUG }}
|
||||||
|
ref: ${{ env.WEBSITE_REPO_BRANCH }}
|
||||||
|
path: ${{ env.WEBSITE_DIR }}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update phpDoc class docs
|
||||||
|
#
|
||||||
|
|
||||||
|
- name: Update phpDoc class docs
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/generate-phpdoc.sh" \
|
||||||
|
"$BUILD_DIR/.phpdoc.xml" \
|
||||||
|
"$WEBSITE_DIR/phpDoc/$GITHUB_REF_NAME" \
|
||||||
|
"$WEBSITE_DIR/phpDoc/$GITHUB_REF_NAME.cache" \
|
||||||
|
"Pico $PICO_VERSION_MILESTONE API Documentation ($GITHUB_REF_NAME branch)"
|
||||||
|
|
||||||
|
- name: Check for phpDoc class docs updates
|
||||||
|
run: |
|
||||||
|
PHPDOC_UPDATED="$([ -n "$(git -C "$WEBSITE_DIR" status --porcelain "phpDoc/$GITHUB_REF_NAME.cache")" ] && echo "yes" || echo "no")"
|
||||||
|
echo "PHPDOC_UPDATED=$PHPDOC_UPDATED" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Update phpDoc class docs list
|
||||||
|
if: ${{ env.PHPDOC_UPDATED == 'yes' }}
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/update-phpdoc-list.sh" \
|
||||||
|
"$WEBSITE_DIR/_data/phpDoc.yml" \
|
||||||
|
"$GITHUB_REF_NAME" "branch" \
|
||||||
|
"<code>$GITHUB_REF_NAME</code> branch" "$(date +%s)"
|
||||||
|
|
||||||
|
- name: Commit phpDoc class docs updates
|
||||||
|
if: ${{ env.PHPDOC_UPDATED == 'yes' }}
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_DIR }}
|
||||||
|
file_pattern: >-
|
||||||
|
phpDoc/${{ github.ref_name }}
|
||||||
|
phpDoc/${{ github.ref_name }}.cache
|
||||||
|
_data/phpDoc.yml
|
||||||
|
commit_user_name: Pico CMS Bot
|
||||||
|
commit_user_email: bot@picocms.org
|
||||||
|
commit_message: >-
|
||||||
|
Update phpDocumentor class docs
|
||||||
|
for ${{ github.ref_name }} branch
|
||||||
|
@ ${{ github.sha }}
|
172
.github/workflows/deploy-release.yml
vendored
Normal file
172
.github/workflows/deploy-release.yml
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
name: Git release deployment
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [ 'published' ]
|
||||||
|
|
||||||
|
env:
|
||||||
|
WEBSITE_REPO_SLUG: picocms/picocms.github.io
|
||||||
|
WEBSITE_REPO_BRANCH: master
|
||||||
|
CI_TOOLS_SETUP: https://raw.githubusercontent.com/picocms/ci-tools/master/setup.sh
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
website:
|
||||||
|
name: Update website for new releases
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
PHP_VERSION: '7.4'
|
||||||
|
BUILD_DIR: ./build
|
||||||
|
WEBSITE_DIR: ./website
|
||||||
|
CLOC_SOURCE: https://github.com/AlDanial/cloc/releases/download/1.92/cloc-1.92.pl
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Setup CI tools
|
||||||
|
run: |
|
||||||
|
. <(curl -fsS -L "$CI_TOOLS_SETUP")
|
||||||
|
echo "CI_TOOLS_PATH=$CI_TOOLS_PATH" | tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: ${{ env.BUILD_DIR }}
|
||||||
|
|
||||||
|
- name: Install Pico CMS
|
||||||
|
uses: ./build/.github/actions/install
|
||||||
|
with:
|
||||||
|
path: ${{ env.BUILD_DIR }}
|
||||||
|
php-version: ${{ env.PHP_VERSION }}
|
||||||
|
php-tools: phpdoc
|
||||||
|
|
||||||
|
- name: Parse Pico version
|
||||||
|
run: |
|
||||||
|
. "$CI_TOOLS_PATH/parse_version.inc.sh"
|
||||||
|
|
||||||
|
if ! parse_version "$GITHUB_REF_NAME"; then
|
||||||
|
echo "Invalid version string: $GITHUB_REF_NAME" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf '%s=%s\n' \
|
||||||
|
"PICO_VERSION_FULL" "$VERSION_FULL" \
|
||||||
|
"PICO_VERSION_STABILITY" "$VERSION_STABILITY" \
|
||||||
|
"PICO_VERSION_MILESTONE" "$VERSION_MILESTONE" \
|
||||||
|
| tee -a "$GITHUB_ENV"
|
||||||
|
|
||||||
|
- name: Checkout website repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_REPO_SLUG }}
|
||||||
|
ref: ${{ env.WEBSITE_REPO_BRANCH }}
|
||||||
|
path: ${{ env.WEBSITE_DIR }}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update phpDoc class docs
|
||||||
|
#
|
||||||
|
|
||||||
|
- name: Update phpDoc class docs
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/generate-phpdoc.sh" \
|
||||||
|
"$BUILD_DIR/.phpdoc.xml" \
|
||||||
|
"$WEBSITE_DIR/phpDoc/$GITHUB_REF_NAME" \
|
||||||
|
"$WEBSITE_DIR/phpDoc/$GITHUB_REF_NAME/cache" \
|
||||||
|
"Pico $PICO_VERSION_MILESTONE API Documentation ($GITHUB_REF_NAME)"
|
||||||
|
|
||||||
|
- name: Update phpDoc class docs list
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/update-phpdoc-list.sh" \
|
||||||
|
"$WEBSITE_DIR/_data/phpDoc.yml" \
|
||||||
|
"$GITHUB_REF_NAME" "version" \
|
||||||
|
"Pico $PICO_VERSION_FULL" "$(date +%s)"
|
||||||
|
|
||||||
|
- name: Commit phpDoc class docs updates
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_DIR }}
|
||||||
|
file_pattern: >-
|
||||||
|
phpDoc/${{ github.ref_name }}
|
||||||
|
_data/phpDoc.yml
|
||||||
|
commit_user_name: Pico CMS Bot
|
||||||
|
commit_user_email: bot@picocms.org
|
||||||
|
commit_message: >-
|
||||||
|
Update phpDocumentor class docs
|
||||||
|
for ${{ github.ref_name }}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update version badge
|
||||||
|
#
|
||||||
|
|
||||||
|
- name: Generate version badge
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/generate-badge.sh" \
|
||||||
|
"$WEBSITE_DIR/badges/pico-version.svg" \
|
||||||
|
"release" "$PICO_VERSION_FULL" "blue"
|
||||||
|
|
||||||
|
- name: Commit version badge
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_DIR }}
|
||||||
|
file_pattern: >-
|
||||||
|
badges/pico-version.svg
|
||||||
|
commit_user_name: Pico CMS Bot
|
||||||
|
commit_user_email: bot@picocms.org
|
||||||
|
commit_message: >-
|
||||||
|
Update version badge for ${{ github.ref_name }}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update version file
|
||||||
|
#
|
||||||
|
|
||||||
|
- name: Update version file
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/update-version-file.sh" \
|
||||||
|
"$WEBSITE_DIR/_data/version.yml" \
|
||||||
|
"$PICO_VERSION_FULL"
|
||||||
|
|
||||||
|
- name: Commit version file
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_DIR }}
|
||||||
|
file_pattern: >-
|
||||||
|
_data/version.yml
|
||||||
|
commit_user_name: Pico CMS Bot
|
||||||
|
commit_user_email: bot@picocms.org
|
||||||
|
commit_message: >-
|
||||||
|
Update version file for ${{ github.ref_name }}
|
||||||
|
|
||||||
|
#
|
||||||
|
# Update cloc statistics
|
||||||
|
#
|
||||||
|
|
||||||
|
- name: Install cloc
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
run: |
|
||||||
|
sudo curl -fsS -L -o "/usr/local/bin/cloc" "$CLOC_SOURCE"
|
||||||
|
sudo chmod +x "/usr/local/bin/cloc"
|
||||||
|
|
||||||
|
- name: Update cloc statistics
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
run: |
|
||||||
|
"$CI_TOOLS_PATH/update-cloc-stats.sh" \
|
||||||
|
"$WEBSITE_DIR/_data/cloc.yml" \
|
||||||
|
"$BUILD_DIR/lib" \
|
||||||
|
"$BUILD_DIR/index.php"
|
||||||
|
|
||||||
|
- name: Commit cloc statistics
|
||||||
|
if: ${{ env.PICO_VERSION_STABILITY == 'stable' }}
|
||||||
|
uses: stefanzweifel/git-auto-commit-action@v4
|
||||||
|
with:
|
||||||
|
repository: ${{ env.WEBSITE_DIR }}
|
||||||
|
file_pattern: >-
|
||||||
|
_data/cloc.yml
|
||||||
|
commit_user_name: Pico CMS Bot
|
||||||
|
commit_user_email: bot@picocms.org
|
||||||
|
commit_message: >-
|
||||||
|
Update cloc statistics for ${{ github.ref_name }}
|
13
.github/workflows/stale.yml
vendored
13
.github/workflows/stale.yml
vendored
|
@ -1,15 +1,21 @@
|
||||||
name: "Mark or close stale issues and PRs"
|
name: Mark or close stale issues and PRs
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "0 12 * * *"
|
- cron: "0 */6 * * *"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
stale:
|
stale:
|
||||||
|
name: Mark or close stale issues and PRs
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v3
|
- uses: actions/stale@v3
|
||||||
with:
|
with:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
days-before-stale: 7
|
days-before-stale: 7
|
||||||
days-before-close: 2
|
days-before-close: 2
|
||||||
stale-issue-message: >
|
stale-issue-message: >
|
||||||
|
@ -25,4 +31,3 @@ jobs:
|
||||||
exempt-issue-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned"
|
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"
|
exempt-pr-labels: "type: Bug,type: Enhancement,type: Feature,type: Idea,type: Release,info: Pinned"
|
||||||
remove-stale-when-updated: true
|
remove-stale-when-updated: true
|
||||||
|
|
||||||
|
|
27
.github/workflows/test-pr.yml
vendored
Normal file
27
.github/workflows/test-pr.yml
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
name: Test Pico CMS pull request
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: Test Pico CMS
|
||||||
|
uses: ./.github/workflows/test.yml
|
||||||
|
|
||||||
|
bouncer:
|
||||||
|
name: Bouncer
|
||||||
|
|
||||||
|
needs: test
|
||||||
|
if: ${{ always() }}
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions: {}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Check build matrix status
|
||||||
|
if: ${{ needs.test.result != 'success' }}
|
||||||
|
run: |
|
||||||
|
:
|
||||||
|
echo "Some tests of Pico CMS failed." >&2
|
||||||
|
echo "Please check the GitHub workflow logs for details." >&2
|
||||||
|
exit 1
|
52
.github/workflows/test.yml
vendored
Normal file
52
.github/workflows/test.yml
vendored
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
name: Test Pico CMS
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- 'master'
|
||||||
|
- 'pico-3.0'
|
||||||
|
tags: [ 'v*.*.*' ]
|
||||||
|
workflow_call: {}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: PHP ${{ matrix.PHP_VERSION }}
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
PHP_VERSION:
|
||||||
|
- '7.2'
|
||||||
|
- '7.3'
|
||||||
|
- '7.4'
|
||||||
|
- '8.0'
|
||||||
|
- '8.1'
|
||||||
|
- 'nightly'
|
||||||
|
fail-fast: false
|
||||||
|
|
||||||
|
continue-on-error: ${{ matrix.PHP_VERSION == 'nightly' }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
PHP_VERSION: ${{ matrix.PHP_VERSION }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install Pico CMS
|
||||||
|
uses: ./.github/actions/install
|
||||||
|
with:
|
||||||
|
php-version: ${{ env.PHP_VERSION }}
|
||||||
|
php-tools: phpcs
|
||||||
|
|
||||||
|
- name: Check Pico version
|
||||||
|
if: ${{ github.ref_type == 'tag' }}
|
||||||
|
run: |
|
||||||
|
[ "$GITHUB_REF_NAME" == "v$PICO_VERSION" ]
|
||||||
|
|
||||||
|
- name: Run PHP_CodeSniffer
|
||||||
|
run: |
|
||||||
|
phpcs --standard=.phpcs.xml
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -15,9 +15,6 @@ desktop.ini
|
||||||
/vendor
|
/vendor
|
||||||
|
|
||||||
# Build system
|
# Build system
|
||||||
/.build/build
|
|
||||||
/.build/deploy
|
|
||||||
/.build/ci-tools
|
|
||||||
/pico-release-*.tar.gz
|
/pico-release-*.tar.gz
|
||||||
/pico-release-*.zip
|
/pico-release-*.zip
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
# Deny access to internal dirs and files by passing the URL to Pico
|
# Deny access to internal dirs and files by passing the URL to Pico
|
||||||
RewriteRule ^(config|content|content-sample|lib|vendor)(/|$) index.php [L]
|
RewriteRule ^(config|content|content-sample|lib|vendor)(/|$) index.php [L]
|
||||||
RewriteRule ^(CHANGELOG\.md|composer\.(json|lock|phar))(/|$) index.php [L]
|
RewriteRule ^(CHANGELOG\.md|SECURITY.md|composer\.(json|lock|phar))(/|$) index.php [L]
|
||||||
RewriteRule (^\.|/\.)(?!well-known(/|$)) index.php [L]
|
RewriteRule (^\.|/\.)(?!well-known(/|$)) index.php [L]
|
||||||
|
|
||||||
# Enable URL rewriting
|
# Enable URL rewriting
|
||||||
|
|
61
.phpdoc.xml
61
.phpdoc.xml
|
@ -1,33 +1,32 @@
|
||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
<phpdocumentor>
|
<phpdocumentor
|
||||||
<title><![CDATA[Pico API Documentation]]></title>
|
configVersion="3"
|
||||||
<parser>
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
<target>.build/phpdoc.cache</target>
|
xmlns="https://www.phpdoc.org"
|
||||||
</parser>
|
xsi:noNamespaceSchemaLocation="data/xsd/phpdoc.xsd"
|
||||||
<transformer>
|
>
|
||||||
<target>.build/phpdoc</target>
|
<paths>
|
||||||
</transformer>
|
<output>.build/phpdoc</output>
|
||||||
<transformations>
|
<cache>.build/phpdoc.cache</cache>
|
||||||
<template name="clean"/>
|
</paths>
|
||||||
</transformations>
|
<version number="3.0.0">
|
||||||
<files>
|
<api>
|
||||||
<directory>.</directory>
|
<source dsn=".">
|
||||||
<file>index.php</file>
|
<path>.</path>
|
||||||
<file>index.php.dist</file>
|
</source>
|
||||||
|
<ignore hidden="true" symlinks="true">
|
||||||
<!-- exclude .build and .github directories -->
|
<path>.build/**/*</path>
|
||||||
<ignore>.build/*</ignore>
|
<path>.github/**/*</path>
|
||||||
<ignore>.github/*</ignore>
|
<path>vendor/**/*</path>
|
||||||
|
</ignore>
|
||||||
<!-- exclude user config -->
|
<extensions>
|
||||||
<ignore>config/*</ignore>
|
<extension>php</extension>
|
||||||
<file>config/config.yml.template</file>
|
<extension>php.dist</extension>
|
||||||
|
</extensions>
|
||||||
<!-- exclude all plugins -->
|
<visibility>public</visibility>
|
||||||
<ignore>plugins/*</ignore>
|
<include-source>true</include-source>
|
||||||
<file>plugins/DummyPlugin.php</file>
|
<default-package-name>Pico</default-package-name>
|
||||||
|
</api>
|
||||||
<!-- exclude vendor dir -->
|
</version>
|
||||||
<ignore>vendor/*</ignore>
|
<template name="default"/>
|
||||||
</files>
|
|
||||||
</phpdocumentor>
|
</phpdocumentor>
|
||||||
|
|
82
.travis.yml
82
.travis.yml
|
@ -1,82 +0,0 @@
|
||||||
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"
|
|
64
CHANGELOG.md
64
CHANGELOG.md
|
@ -16,6 +16,59 @@ Pico Changelog
|
||||||
`PicoDeprecated`'s changelog. Please note that BC-breaking changes
|
`PicoDeprecated`'s changelog. Please note that BC-breaking changes
|
||||||
are only possible with a new major version.
|
are only possible with a new major version.
|
||||||
|
|
||||||
|
### Version 3.0.0-beta.1
|
||||||
|
Released: -
|
||||||
|
|
||||||
|
```
|
||||||
|
* [New] Pico 3.0 is a major release, but comes with relatively small changes
|
||||||
|
to Pico's core; its major change are updated dependencies (see below)
|
||||||
|
* [New] Introduce API version 4 (with barely noticable changes, see below)
|
||||||
|
* [New] Add new continous integration (CI) pipeline using GitHub Actions
|
||||||
|
* [New] Add new build script and Makefile to simplify Pico's build and release
|
||||||
|
process; see `CONTRIBUTING.md` for details
|
||||||
|
* [New] Add `%page_id%`, `%page_url%` and `%page_path%` Markdown placeholders
|
||||||
|
to replace the current page's ID, URL, and containing directory resp.
|
||||||
|
* [New] `Pico::prepareFileContent()` and `Pico::substituteFileContent()` both
|
||||||
|
now receive the (optional) `$pageId` argument for the new `%page_*%`
|
||||||
|
Markdown placeholders
|
||||||
|
* [New] Add `page()` Twig function to access a page's data
|
||||||
|
* [New] Enhance `pages_order_by_meta` functionality to allow sorting by
|
||||||
|
nested meta values using '.' notation (e.g., 'author.info')
|
||||||
|
* [Changed] ! Pico now requires PHP 7.2.5 or later (this includes full PHP 8
|
||||||
|
support, also see #528, #534, #608)
|
||||||
|
* [Changed] ! Pico now depends on Twig 3.3, skipping Twig 2.x altogether; this
|
||||||
|
is a BC-breaking change, as Twig 2.x and 3.x changed and removed
|
||||||
|
some commonly used features; check out Twig's changelog and
|
||||||
|
deprecation notices for details
|
||||||
|
* [Changed] ! Pico now depends on Symfony YAML 5.4, skipping various milestones
|
||||||
|
in between; this is a BC-breaking change, because Symfony YAML
|
||||||
|
changed its behaviour multiple times in between; check out Symfony
|
||||||
|
YAML's changelog for details
|
||||||
|
* [Changed] ! Pico downgrades to Parsedown 1.7.4 and Parsedown Extra 0.8.1;
|
||||||
|
this is a BC-breaking change in theory, but shouldn't have much of
|
||||||
|
an impact in real-life scenarios
|
||||||
|
* [Changed] #603: Pico's `markdown` Twig filter now raises an error if an
|
||||||
|
invalid variable type (e.g. an array) is passed
|
||||||
|
* [Changed] Enable PHP strict typing for Pico's internal classes; Pico's
|
||||||
|
`PicoPluginInterface` interface and `AbstractPicoPlugin` class
|
||||||
|
don't use strict typing to maintain BC, but you can (and should)
|
||||||
|
enable it for your plugin (see `DummyPlugin` for an example)
|
||||||
|
* [Changed] Various other code improvements due to the upgrade to PHP 7.2
|
||||||
|
* [Fixed] #602: Fix contents and meta data of meta pages (pages starting with
|
||||||
|
an `_`) getting replaced by the 404 page when being requested
|
||||||
|
* [Fixed] Add a proper error message for a missing theme directory
|
||||||
|
* [Removed] ! Remove Pico's `map` Twig filter; it conflicts with Twig's `map`
|
||||||
|
filter and can be replaced by Twig's `column` or `map` filter
|
||||||
|
```
|
||||||
|
|
||||||
|
### Version 3.0.0-alpha.2
|
||||||
|
Released: 2020-12-24
|
||||||
|
|
||||||
|
```
|
||||||
|
* [Changed] Merge all fixes of Pico v2.1.2 to v2.1.4
|
||||||
|
* [Fixed] #575: Update Symfony YAML v3.4 to support PHP 8.0+
|
||||||
|
```
|
||||||
|
|
||||||
### Version 2.1.4
|
### Version 2.1.4
|
||||||
Released: 2020-08-29
|
Released: 2020-08-29
|
||||||
|
|
||||||
|
@ -40,6 +93,17 @@ Released: 2020-04-10
|
||||||
* [Fixed] Fix DummyPlugin declaring API version 3
|
* [Fixed] Fix DummyPlugin declaring API version 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Version 3.0.0-alpha.1
|
||||||
|
Released: 2020-03-29
|
||||||
|
|
||||||
|
```
|
||||||
|
* [New] Kick-start development of Pico 3.0
|
||||||
|
* [Changed] Require PHP 7.0.8+
|
||||||
|
* [Changed] Update dependencies: Twig 2.12, Symfony YAML 3.4, Parsedown 1.7.4
|
||||||
|
and Parsedown Extra 0.8.1; this is just an interim step, we'll
|
||||||
|
update to Twig 3.0+ and Symfony YAML 5.0+ later
|
||||||
|
```
|
||||||
|
|
||||||
### Version 2.1.1
|
### Version 2.1.1
|
||||||
Released: 2019-12-31
|
Released: 2019-12-31
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ Please describe your issue as clear as possible and always include the *Pico ver
|
||||||
Contributing
|
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.
|
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](https://picocms.org/development/) of our website.
|
||||||
|
|
||||||
### Developer Certificate of Origin
|
### Developer Certificate of Origin
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
OTHER DEALINGS IN THE SOFTWARE.
|
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!
|
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 an [OSI-approved open source license](https://opensource.org/licenses). After all, Pico is open source, too!
|
||||||
|
|
||||||
### Prevent `merge-hell`
|
### Prevent `merge-hell`
|
||||||
|
|
||||||
|
@ -108,9 +108,9 @@ Please keep in mind that pull requests should be small (i.e. one feature per req
|
||||||
|
|
||||||
### Coding Standards
|
### 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/).
|
Pico uses the [PSR-2 Coding Standard](https://www.php-fig.org/psr/psr-2/) as defined by the [PHP Framework Interoperability Group (PHP-FIG)](https://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.
|
For historical reasons we don't use formal namespaces.
|
||||||
|
|
||||||
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:
|
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:
|
||||||
|
|
||||||
|
@ -122,18 +122,18 @@ With this command you can specify a file or folder to limit which files it will
|
||||||
|
|
||||||
Pico accepts the problems of having redundant documentation on different places (concretely Pico's inline user docs, the `README.md` and the website) for the sake of a better user experience. When updating the docs, please make sure to keep them in sync.
|
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.
|
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](https://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](https://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
|
Versioning
|
||||||
----------
|
----------
|
||||||
|
|
||||||
Pico follows [Semantic Versioning 2.0](http://semver.org) and uses version numbers like `MAJOR`.`MINOR`.`PATCH`. We will increment the:
|
Pico follows [Semantic Versioning 2.0](https://semver.org) and uses version numbers like `MAJOR`.`MINOR`.`PATCH`. We will increment the:
|
||||||
|
|
||||||
- `MAJOR` version when we make incompatible API changes,
|
- `MAJOR` version when we make incompatible API changes,
|
||||||
- `MINOR` version when we add functionality in a backwards-compatible manner, and
|
- `MINOR` version when we add functionality in a backwards-compatible manner, and
|
||||||
- `PATCH` version when we make backwards-compatible bug fixes.
|
- `PATCH` version when we make backwards-compatible bug fixes.
|
||||||
|
|
||||||
For more information please refer to the http://semver.org website.
|
For more information please refer to the https://semver.org website.
|
||||||
|
|
||||||
Branching
|
Branching
|
||||||
---------
|
---------
|
||||||
|
@ -153,9 +153,13 @@ As soon as development reaches a point where feedback is appreciated, a pull req
|
||||||
Build & Release process
|
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.
|
We use [GitHub Actions](https://github.com/picocms/Pico/actions) to automate the test, build & release process of Pico - also called [continous integration](https://en.wikipedia.org/wiki/Continuous_integration), or CI. With our CI pipeline we perform various tests on every push, including code style checks (powered by [PHP_CodeSniffer](https://github.com/squizlabs/PHP_CodeSniffer)). Due to historical reasons we don't have any unit or integration tests, so you must manually test your changes. Pull requests adding unit or integration tests are very welcome though! Please refer to the [`test.yml` workflow](https://github.com/picocms/Pico/blob/master/.github/workflows/test.yml) 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:
|
With our CI pipeline we furthermore generate and deploy a [PHP class documentation](https://picocms.org/phpDoc/) (powered by [phpDoc](https://phpdoc.org)) for new releases and on every push to the `master` branch. Our CI pipeline also prepares new releases by generating 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 the [`deploy-branch.yml`](https://github.com/picocms/Pico/blob/master/.github/workflows/deploy-branch.yml) and [`deploy-release.yml`](https://github.com/picocms/Pico/blob/master/.github/workflows/deploy-release.yml) workflows for details, as well as the [`picocms/ci-tools` repo](https://github.com/picocms/ci-tools).
|
||||||
|
|
||||||
|
To build a release package or publish a new release, use Pico's [Makefile](https://github.com/picocms/Pico/blob/master/Makefile) (see [Wikipedia](https://en.wikipedia.org/wiki/Make_(software)) for details), which is more or less a wrapper for Pico's [`.build/build.sh` script](https://github.com/picocms/Pico/blob/master/.build/build.sh). You can build both development versions (like `v1.0.0-dev`) and "actual" releases (both stable and pre-releases, like `v1.0.0` or `v1.0.0-beta.1`). The `build` target builds a development version by default; to build a release, pass the `version` argument (e.g. `make build version=v1.0.0`). Please note that the build script will perform a sophisticated list of sanity checks before actually building a non-development version of Pico (e.g. your Git working tree must be clean, and the Git tag matching the version to build must be checked out). To publish a new release, run the `publish` target. It will build the release packages and push them to GitHub, creating a new release there and triggering the previously mentioned workflow for new releases. You must then manually add the changelog to the release description.
|
||||||
|
|
||||||
|
As insinuated above, it is important that each commit to `master` is deployable. Once development of a new Pico release is finished, publish the new release using `make publish version=v1.0.0`. The matching Git tag should reference a (usually empty) commit on `master`, whose message should adhere to the following template:
|
||||||
|
|
||||||
```
|
```
|
||||||
Version 1.0.0
|
Version 1.0.0
|
||||||
|
@ -171,39 +175,39 @@ Before pushing a new Git tag, make sure to update the `Pico::VERSION` and `Pico:
|
||||||
|
|
||||||
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.
|
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.
|
The latest Pico version is always available at https://github.com/picocms/Pico/releases/latest, so please make sure to reference this URL rather than version-specific URLs. [Packagist](https://packagist.org/packages/picocms/pico) will be updated automatically.
|
||||||
|
|
||||||
Labeling of Issues & Pull Requests
|
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.
|
Pico makes use of GitHub's label and milestone features, to aid 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!
|
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:
|
- 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`. 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. `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: Resolved` is used when the issue has been resolved (used with issues only).
|
||||||
- `status: Conflict` indicates a conflict with another issue or behavior of Pico, making it impossible to resolve the problem at the moment.
|
- `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: 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.
|
- `status: Rejected` is used when the issue was rejected for another reason (used with issues only).
|
||||||
|
|
||||||
- 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: 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. They might also be labeled with `status: Work In Progress`. 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: 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: 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: 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 discussions 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: 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 `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, unless the report isn't rather considered a support request (also see `type: Support`).
|
||||||
|
|
||||||
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.
|
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 an 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.
|
After resolving an 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, the [GitHub Actions](https://github.com/picocms/Pico/actions/workflows/stale.yml) 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 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 provide the necessary information, unless it is automatically closed due to inactivity.
|
||||||
|
|
||||||
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`.
|
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).
|
If an 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](https://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).
|
||||||
|
|
55
Makefile
Normal file
55
Makefile
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
# Pico -- Makefile
|
||||||
|
# Makefile to build new Pico releases using './.build/build.sh'.
|
||||||
|
#
|
||||||
|
# This file is part of Pico, a stupidly simple, blazing fast, flat file CMS.
|
||||||
|
# Visit us at https://picocms.org/ for more info.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2022 Daniel Rudolf <https://www.daniel-rudolf.de>
|
||||||
|
#
|
||||||
|
# This work is licensed under the terms of the MIT license.
|
||||||
|
# For a copy, see LICENSE file or <https://opensource.org/licenses/MIT>.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# License-Filename: LICENSE
|
||||||
|
|
||||||
|
version?=
|
||||||
|
nocheck?=false
|
||||||
|
publish=false
|
||||||
|
|
||||||
|
php?=php
|
||||||
|
composer?=composer
|
||||||
|
|
||||||
|
app_name=pico
|
||||||
|
archive_tar=$(app_name)-release-*.tar.gz
|
||||||
|
archive_zip=$(app_name)-release-*.zip
|
||||||
|
export=$(app_name)-export.tar.gz
|
||||||
|
|
||||||
|
all: clean build
|
||||||
|
|
||||||
|
clean: clean-build clean-export
|
||||||
|
|
||||||
|
clean-build:
|
||||||
|
find "." -name "$(archive_tar)" -exec rm -f {} \;
|
||||||
|
find "." -name "$(archive_zip)" -exec rm -f {} \;
|
||||||
|
|
||||||
|
clean-export:
|
||||||
|
rm -f "./$(export)"
|
||||||
|
|
||||||
|
build: export PHP=$(php)
|
||||||
|
build: export COMPOSER=$(composer)
|
||||||
|
build:
|
||||||
|
./.build/build.sh$(if $(filter true,$(publish)), --publish,)$(if $(filter true,$(nocheck)), --no-check,)$(if $(version), "$(version)",)
|
||||||
|
|
||||||
|
export:
|
||||||
|
git archive --prefix "$(app_name)/" -o "./$(export)" HEAD
|
||||||
|
|
||||||
|
publish: publish=true
|
||||||
|
publish: build
|
||||||
|
|
||||||
|
composer:
|
||||||
|
$(composer) install --optimize-autoloader --no-dev
|
||||||
|
|
||||||
|
.PHONY: all \
|
||||||
|
clean clean-build clean-export \
|
||||||
|
build export publish \
|
||||||
|
composer
|
44
README.md
44
README.md
|
@ -9,23 +9,7 @@ Pico
|
||||||
|
|
||||||
Pico is a stupidly simple, blazing fast, flat file CMS.
|
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.
|
Visit us at https://picocms.org/ and see https://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
|
Screenshot
|
||||||
----------
|
----------
|
||||||
|
@ -159,7 +143,7 @@ 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!
|
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.
|
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 appropriate 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].
|
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].
|
||||||
|
|
||||||
|
@ -197,11 +181,11 @@ Getting Help
|
||||||
|
|
||||||
#### Getting Help as a user
|
#### 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.
|
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 to a new Pico version. You can find officially supported [plugins][OfficialPlugins] and [themes][OfficialThemes] on our website. A greater choice of third-party plugins can be found in our [Wiki][WikiPlugins]. 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
|
#### 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].
|
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, check out Pico's [`DummyPlugin`][PicoDummyPlugin], and [Pico's default theme][PicoThemeGit].
|
||||||
|
|
||||||
#### You still need help or experience a problem with Pico?
|
#### You still need help or experience a problem with Pico?
|
||||||
|
|
||||||
|
@ -214,7 +198,7 @@ Contributing
|
||||||
|
|
||||||
You want to contribute to Pico? We really appreciate that! You can help make Pico better by [contributing code][PullRequests] or [reporting issues][Issues], but please take note of our [contribution guidelines][ContributionGuidelines]. In general you can contribute in three different areas:
|
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!
|
1. Plugins & Themes: You're a plugin developer or theme designer? We love you folks! To get you started with creating a plugin or theme, check out Pico's [`DummyPlugin`][PicoDummyPlugin], and [Pico's default theme][PicoThemeGit]. If you have created a plugin or theme, please add it to our [Wiki][] and [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].
|
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].
|
||||||
|
|
||||||
|
@ -243,26 +227,26 @@ Official Pico Contributors won't claim bounties on their own behalf, Pico will n
|
||||||
[PicoThemeGit]: https://github.com/picocms/pico-theme
|
[PicoThemeGit]: https://github.com/picocms/pico-theme
|
||||||
[PicoDeprecatedGit]: https://github.com/picocms/pico-deprecated
|
[PicoDeprecatedGit]: https://github.com/picocms/pico-deprecated
|
||||||
[PicoComposerGit]: https://github.com/picocms/pico-composer
|
[PicoComposerGit]: https://github.com/picocms/pico-composer
|
||||||
|
[PicoDummyPlugin]: https://github.com/picocms/Pico/blob/master/plugins/DummyPlugin.php
|
||||||
[Packagist]: https://packagist.org/
|
[Packagist]: https://packagist.org/
|
||||||
[PicoPackagist]: https://packagist.org/packages/picocms/pico
|
[PicoPackagist]: https://packagist.org/packages/picocms/pico
|
||||||
[PicoThemePackagist]: https://packagist.org/packages/picocms/pico-theme
|
[PicoThemePackagist]: https://packagist.org/packages/picocms/pico-theme
|
||||||
[PicoDeprecatedPackagist]: https://packagist.org/packages/picocms/pico-deprecated
|
[PicoDeprecatedPackagist]: https://packagist.org/packages/picocms/pico-deprecated
|
||||||
[PicoComposerPackagist]: https://packagist.org/packages/picocms/pico-composer
|
[PicoComposerPackagist]: https://packagist.org/packages/picocms/pico-composer
|
||||||
[SemVer]: http://semver.org
|
[SemVer]: https://semver.org
|
||||||
[HelpFork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo
|
[HelpFork]: https://help.github.com/en/github/getting-started-with-github/fork-a-repo
|
||||||
[HelpUpgrade]: http://picocms.org/in-depth/upgrade/
|
[HelpUpgrade]: https://picocms.org/in-depth/upgrade/
|
||||||
[HelpUserDocs]: http://picocms.org/docs/
|
[HelpUserDocs]: https://picocms.org/docs/
|
||||||
[HelpDevDocs]: http://picocms.org/development/
|
[HelpDevDocs]: https://picocms.org/development/
|
||||||
[Submit]: http://picocms.org/in-depth/submission_guidelines
|
[Submit]: https://picocms.org/in-depth/submission_guidelines
|
||||||
[OfficialPlugins]: http://picocms.org/plugins/
|
[OfficialPlugins]: https://picocms.org/plugins/
|
||||||
[OfficialThemes]: http://picocms.org/themes/
|
[OfficialThemes]: https://picocms.org/themes/
|
||||||
[Wiki]: https://github.com/picocms/Pico/wiki
|
[Wiki]: https://github.com/picocms/Pico/wiki
|
||||||
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins
|
[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
|
[Issues]: https://github.com/picocms/Pico/issues
|
||||||
[IssuesSearch]: https://github.com/picocms/Pico/search?type=Issues
|
[IssuesSearch]: https://github.com/picocms/Pico/search?type=Issues
|
||||||
[LiberaChat]: https://web.libera.chat/#picocms
|
[LiberaChat]: https://web.libera.chat/#picocms
|
||||||
[LiberaChatLogs]: http://picocms.org/irc-logs
|
[LiberaChatLogs]: https://picocms.org/irc-logs
|
||||||
[PullRequests]: https://github.com/picocms/Pico/pulls
|
[PullRequests]: https://github.com/picocms/Pico/pulls
|
||||||
[PullRequestsWebsite]: https://github.com/picocms/picocms.github.io/pulls
|
[PullRequestsWebsite]: https://github.com/picocms/picocms.github.io/pulls
|
||||||
[ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md
|
[ContributionGuidelines]: https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"type": "library",
|
"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.",
|
"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" ],
|
"keywords": ["pico", "picocms", "pico-cms", "simple", "flat-file", "cms", "content-management", "website", "markdown-to-html", "php", "markdown", "yaml", "twig" ],
|
||||||
"homepage": "http://picocms.org/",
|
"homepage": "https://picocms.org/",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "The Pico Community",
|
"name": "The Pico Community",
|
||||||
"homepage": "http://picocms.org/"
|
"homepage": "https://picocms.org/"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Contributors",
|
"name": "Contributors",
|
||||||
|
@ -26,17 +26,17 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"support": {
|
"support": {
|
||||||
"docs": "http://picocms.org/docs",
|
"docs": "https://picocms.org/docs",
|
||||||
"issues": "https://github.com/picocms/Pico/issues",
|
"issues": "https://github.com/picocms/Pico/issues",
|
||||||
"source": "https://github.com/picocms/Pico"
|
"source": "https://github.com/picocms/Pico"
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=5.3.6",
|
"php": ">=7.2.5",
|
||||||
"ext-mbstring": "*",
|
"ext-mbstring": "*",
|
||||||
"twig/twig": "^1.36",
|
"twig/twig": "^3.3.8",
|
||||||
"symfony/yaml" : "^2.8",
|
"symfony/yaml" : "^5.4.3",
|
||||||
"erusev/parsedown": "1.8.0-beta-7",
|
"erusev/parsedown": "1.7.4",
|
||||||
"erusev/parsedown-extra": "0.8.0-beta-1"
|
"erusev/parsedown-extra": "0.8.1"
|
||||||
},
|
},
|
||||||
"suggest": {
|
"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-theme": "Pico requires a theme to actually display the contents of your website. This is Pico's official default theme.",
|
||||||
|
@ -44,13 +44,14 @@
|
||||||
"picocms/composer-installer": "This Composer plugin is responsible for installing Pico plugins and themes using the Composer package manager."
|
"picocms/composer-installer": "This Composer plugin is responsible for installing Pico plugins and themes using the Composer package manager."
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"psr-0": {
|
"psr-4": {
|
||||||
"Pico": "lib/",
|
"": "lib/"
|
||||||
"PicoPluginInterface": "lib/",
|
|
||||||
"AbstractPicoPlugin": "lib/"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"extra": {
|
"extra": {
|
||||||
|
"allow-plugins": {
|
||||||
|
"picocms/*": true
|
||||||
|
},
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
"dev-master": "2.1.x-dev",
|
"dev-master": "2.1.x-dev",
|
||||||
"dev-pico-3.0": "3.0.x-dev"
|
"dev-pico-3.0": "3.0.x-dev"
|
||||||
|
|
|
@ -28,9 +28,10 @@ twig_config: # Twig template engine config
|
||||||
##
|
##
|
||||||
# Content
|
# Content
|
||||||
#
|
#
|
||||||
date_format: %D %T # Pico's default date format;
|
date_format: "%D %T" # Pico's default date format;
|
||||||
# See https://php.net/manual/en/function.strftime.php for more info
|
# 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_meta: author # Sort pages by meta value "author" (set "pages_order_by" to "meta")
|
||||||
|
# Use '.' notation for nested meta keys (e.g. 'author.info')
|
||||||
pages_order_by: alpha # Change how Pico sorts pages ("alpha" for alphabetical order, "date", or "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
|
pages_order: asc # Sort pages in ascending ("asc") or descending ("desc") order
|
||||||
content_dir: ~ # The path to Pico's content directory
|
content_dir: ~ # The path to Pico's content directory
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
Logo: %theme_url%/img/pico-white.svg
|
Logo: "%theme_url%/img/pico-white.svg"
|
||||||
Tagline: Making the web easy.
|
Tagline: Making the web easy.
|
||||||
Social:
|
Social:
|
||||||
- title: Visit us on GitHub
|
- title: Visit us on GitHub
|
||||||
|
|
|
@ -5,29 +5,15 @@ Description: Pico is a stupidly simple, blazing fast, flat file CMS.
|
||||||
|
|
||||||
## Welcome to Pico
|
## Welcome to Pico
|
||||||
|
|
||||||
Congratulations, you have successfully installed [Pico][] %version%.
|
Congratulations, you have successfully installed [Pico][] %version%. %meta.description% <!-- replaced by the above Description header -->
|
||||||
%meta.description% <!-- replaced by the above Description header -->
|
|
||||||
|
|
||||||
## Creating Content
|
## Creating Content
|
||||||
|
|
||||||
Pico is a flat file CMS. This means there is no administration backend or
|
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.
|
||||||
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
|
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!
|
||||||
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
|
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:
|
||||||
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;">
|
<table style="width: 100%; max-width: 40em;">
|
||||||
<thead>
|
<thead>
|
||||||
|
@ -67,35 +53,17 @@ Below we've shown some examples of locations and their corresponding URLs:
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
If a file cannot be found, the file `content/404.md` will be shown. You can add
|
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`.
|
||||||
`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
|
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.
|
||||||
`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
|
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. an image) in one of your content files, use Pico's `assets` folder. You can then access them in your Markdown using the <code>%assets_url%</code> placeholder, for example: <code>!\[Image Title\](%assets_url%/image.png)</code>
|
||||||
(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>%assets_url%</code> placeholder, for example:
|
|
||||||
<code>!\[Image Title\](%assets_url%/image.png)</code>
|
|
||||||
|
|
||||||
### Text File Markup
|
### Text File Markup
|
||||||
|
|
||||||
Text files are marked up using [Markdown][] and [Markdown Extra][MarkdownExtra].
|
Text files are marked up using [Markdown][] and [Markdown Extra][MarkdownExtra]. They can also contain regular HTML.
|
||||||
They can also contain regular HTML.
|
|
||||||
|
|
||||||
At the top of text files you can place a block comment and specify certain meta
|
At the top of text files you can place a block comment and specify certain meta attributes of the page using [YAML][] (the "YAML Front Matter", or "YAML header"). For example:
|
||||||
attributes of the page using [YAML][] (the "YAML header"). For example:
|
|
||||||
|
|
||||||
---
|
---
|
||||||
Title: Welcome
|
Title: Welcome
|
||||||
|
@ -106,113 +74,71 @@ attributes of the page using [YAML][] (the "YAML header"). For example:
|
||||||
Template: index
|
Template: index
|
||||||
---
|
---
|
||||||
|
|
||||||
These values will be contained in the `{{ meta }}` variable in themes (see
|
These values will be contained in the `{{ meta }}` variable in themes (see below). Meta headers can sometimes have special functions. For example:
|
||||||
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
|
- `Date` tells Pico when the page was created, letting you sort your pages not just alphabetically, but by date. Pico furthermore not only passes through the `Date` meta header, but rather evaluates it to really "understand" when this page was created.
|
||||||
inline CSS in your Markdown files. You should rather add appropriate CSS
|
- `Template` controls what Twig template Pico uses to display the page. For example, if you add `Template: blog`, Pico uses `blog.twig` to render this page instead of the default `index.twig`.
|
||||||
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.
|
You can even create your own meta attributes and use them in your content or when modifying a theme. For example, if you create an `Order` attribute, you can set `pages_order_by_meta: Order` and `pages_order_by: meta ` in `config.yml` to sort pages in the navigation menu in a custom order.
|
||||||
`img.small { width: 80%; }`). You can then use these CSS classes in your
|
|
||||||
Markdown files, for example:
|
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\](%assets_url%/image.png) {.small}</code>
|
||||||
<code>!\[Image Title\](%assets_url%/image.png) {.small}</code>
|
|
||||||
|
|
||||||
There are also certain variables that you can use in your text files:
|
There are also certain variables that you can use in your text files:
|
||||||
|
|
||||||
* <code>%site_title%</code> - The title of your Pico site
|
* <code>%site_title%</code> - The title of your Pico site
|
||||||
* <code>%base_url%</code> - The URL to your Pico site; internal links
|
* <code>%base_url%</code> - The URL to your Pico site; internal links can be specified using <code>%base_url%?sub/page</code>
|
||||||
can be specified using <code>%base_url%?sub/page</code>
|
|
||||||
* <code>%theme_url%</code> - The URL to the currently used theme
|
* <code>%theme_url%</code> - The URL to the currently used theme
|
||||||
* <code>%assets_url%</code> - The URL to Pico's `assets` directory
|
* <code>%assets_url%</code> - The URL to Pico's `assets` directory
|
||||||
* <code>%themes_url%</code> - The URL to Pico's `themes` directory;
|
* <code>%themes_url%</code> - The URL to Pico's `themes` directory; don't confuse this with <code>%theme_url%</code>
|
||||||
don't confuse this with <code>%theme_url%</code>
|
|
||||||
* <code>%plugins_url%</code> - The URL to Pico's `plugins` directory
|
* <code>%plugins_url%</code> - The URL to Pico's `plugins` directory
|
||||||
* <code>%version%</code> - Pico's current version string (e.g. `2.0.0`)
|
* <code>%version%</code> - Pico's current version string (e.g. `2.0.0`)
|
||||||
* <code>%meta.*%</code> - Access any meta variable of the current
|
* <code>%page_id%</code>, <code>%page_url%</code>, and <code>%page_path%</code> - The current page's ID (e.g. `sub/index` for `content/sub/index.md`, `sub/page` for `content/sub/page.md`, …), its URL (`sub` resp. `sub/page` in our examples), or its directory path (`sub` in both examples) respectively
|
||||||
page, e.g. <code>%meta.author%</code> is replaced with `Joe Bloggs`
|
* <code>%meta.*%</code> - Access any meta variable of the current page, e.g. <code>%meta.author%</code> is replaced with `Joe Bloggs`
|
||||||
* <code>%config.*%</code> - Access any scalar config variable,
|
* <code>%config.*%</code> - Access any scalar config variable, e.g. <code>%config.theme%</code> is replaced by `default`
|
||||||
e.g. <code>%config.theme%</code> is replaced with `default`
|
|
||||||
|
|
||||||
### Blogging
|
### Blogging
|
||||||
|
|
||||||
Pico is not blogging software - but makes it very easy for you to use it as a
|
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 "Plugins" section below for details.
|
||||||
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
|
If you want to use Pico as a blogging software, you probably want to do something like the following:
|
||||||
something like the following:
|
|
||||||
|
|
||||||
1. Put all your blog articles in a separate `blog` folder in your `content`
|
1. Put all your blog articles in a separate `blog` folder in your `content` directory. All these articles should have a `Date` meta header.
|
||||||
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` to the YAML header of this page. It will later show a list of all your blog articles (see step 3).
|
||||||
2. Create a `blog.md` or `blog/index.md` in your `content` directory. Add
|
3. Create the new Twig template `blog.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.twig` near `{{ content }}`:
|
||||||
`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 %}
|
{% for page in pages("blog")|sort_by("time")|reverse %}
|
||||||
|
{% if not page.hidden %}
|
||||||
<div class="post">
|
<div class="post">
|
||||||
<h3><a href="{{ page.url }}">{{ page.title }}</a></h3>
|
<h3><a href="{{ page.url }}">{{ page.title }}</a></h3>
|
||||||
<p class="date">{{ page.date_formatted }}</p>
|
<p class="date">{{ page.date_formatted }}</p>
|
||||||
<p class="excerpt">{{ page.description }}</p>
|
<p class="excerpt">{{ page.description }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Customization
|
## Customization
|
||||||
|
|
||||||
Pico is highly customizable in two different ways: On the one hand you can
|
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.
|
||||||
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
|
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.
|
||||||
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
|
### Themes
|
||||||
|
|
||||||
You can create themes for your Pico installation in the `themes` folder. Pico
|
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.
|
||||||
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
|
[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].
|
||||||
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
|
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.
|
||||||
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
|
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.
|
||||||
that URLs (e.g. `{{ base_url }}`) never include a trailing slash.
|
|
||||||
|
|
||||||
* `{{ site_title }}` - Shortcut to the site title (see `config/config.yml`)
|
* `{{ site_title }}` - Shortcut to the site title (see `config/config.yml`)
|
||||||
* `{{ config }}` - Contains the values you set in `config/config.yml`
|
* `{{ config }}` - Contains the values you set in `config/config.yml` (e.g. `{{ config.theme }}` becomes `default`)
|
||||||
(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
|
||||||
* `{{ 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
|
* `{{ theme_url }}` - The URL to the currently active theme
|
||||||
* `{{ assets_url }}` - The URL to Pico's `assets` directory
|
* `{{ assets_url }}` - The URL to Pico's `assets` directory
|
||||||
* `{{ themes_url }}` - The URL to Pico's `themes` directory; don't confuse this
|
* `{{ themes_url }}` - The URL to Pico's `themes` directory; don't confuse this with `{{ theme_url }}`
|
||||||
with `{{ theme_url }}`
|
|
||||||
* `{{ plugins_url }}` - The URL to Pico's `plugins` directory
|
* `{{ plugins_url }}` - The URL to Pico's `plugins` directory
|
||||||
* `{{ version }}` - Pico's current version string (e.g. `%version%`)
|
* `{{ version }}` - Pico's current version string (e.g. `%version%`)
|
||||||
* `{{ meta }}` - Contains the meta values of the current page
|
* `{{ meta }}` - Contains the meta values of the current page
|
||||||
|
@ -220,44 +146,22 @@ that URLs (e.g. `{{ base_url }}`) never include a trailing slash.
|
||||||
* `{{ meta.description }}` - The `Description` YAML header
|
* `{{ meta.description }}` - The `Description` YAML header
|
||||||
* `{{ meta.author }}` - The `Author` YAML header
|
* `{{ meta.author }}` - The `Author` YAML header
|
||||||
* `{{ meta.date }}` - The `Date` YAML header
|
* `{{ meta.date }}` - The `Date` YAML header
|
||||||
* `{{ meta.date_formatted }}` - The formatted date of the page as specified
|
* `{{ meta.date_formatted }}` - The formatted date of the page as specified by the `date_format` parameter in your `config/config.yml`
|
||||||
by the `date_format` parameter in your
|
* `{{ meta.time }}` - The [Unix timestamp][UnixTimestamp] derived from the `Date` YAML header
|
||||||
`config/config.yml`
|
|
||||||
* `{{ meta.time }}` - The [Unix timestamp][UnixTimestamp] derived from the
|
|
||||||
`Date` YAML header
|
|
||||||
* `{{ meta.robots }}` - The `Robots` YAML header
|
* `{{ meta.robots }}` - The `Robots` YAML header
|
||||||
* ...
|
* ...
|
||||||
* `{{ content }}` - The content of the current page after it has been processed
|
* `{{ content }}` - The content of the current page after it has been processed through Markdown
|
||||||
through Markdown
|
* `{{ previous_page }}` - The data of the previous page, relative to `current_page`
|
||||||
* `{{ previous_page }}` - The data of the previous page, relative to
|
* `{{ current_page }}` - The data of the current page; refer to the "Pages" section below for details
|
||||||
`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`
|
* `{{ 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
|
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.
|
||||||
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
|
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.
|
||||||
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
|
#### Dealing with pages
|
||||||
|
|
||||||
There are several ways to access Pico's pages list. You can access the current
|
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:
|
||||||
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)
|
* `{{ id }}` - The relative path to the content file (unique ID)
|
||||||
* `{{ url }}` - The URL to the page
|
* `{{ url }}` - The URL to the page
|
||||||
|
@ -265,192 +169,77 @@ you access a page, it will always consist of the following data:
|
||||||
* `{{ description }}` - The description of the page (`Description` YAML header)
|
* `{{ description }}` - The description of the page (`Description` YAML header)
|
||||||
* `{{ author }}` - The author of the page (`Author` YAML header)
|
* `{{ author }}` - The author of the page (`Author` YAML header)
|
||||||
* `{{ date }}` - The date of the page (`Date` YAML header)
|
* `{{ date }}` - The date of the page (`Date` YAML header)
|
||||||
* `{{ date_formatted }}` - The formatted date of the page as specified by the
|
* `{{ date_formatted }}` - The formatted date of the page as specified by the `date_format` parameter in your `config/config.yml`
|
||||||
`date_format` parameter in your `config/config.yml`
|
* `{{ time }}` - The [Unix timestamp][UnixTimestamp] derived from the page's date
|
||||||
* `{{ time }}` - The [Unix timestamp][UnixTimestamp] derived from the page's
|
* `{{ 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 }}`)
|
||||||
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)
|
* `{{ meta }}` - The meta values of the page (see global `{{ meta }}` above)
|
||||||
* `{{ prev_page }}` - The data of the respective previous page
|
* `{{ prev_page }}` - The data of the respective previous page
|
||||||
* `{{ next_page }}` - The data of the respective next 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
|
* `{{ tree_node }}` - The page's node in Pico's page tree; check out Pico's [page tree documentation][FeaturesPageTree] for details
|
||||||
[page tree documentation][FeaturesPageTree] for details
|
|
||||||
|
|
||||||
Pico's `pages()` function is the best way to access all of your site's pages.
|
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:
|
||||||
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">
|
<section class="articles">
|
||||||
{% for page in pages(current_page.id) if not page.hidden %}
|
{% for page in pages(current_page.id) %}
|
||||||
|
{% if not page.hidden %}
|
||||||
<article>
|
<article>
|
||||||
<h2><a href="{{ page.url }}">{{ page.title }}</a></h2>
|
<h2><a href="{{ page.url }}">{{ page.title }}</a></h2>
|
||||||
{{ page.id|content }}
|
{{ page.id|content }}
|
||||||
</article>
|
</article>
|
||||||
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
The `pages()` function is very powerful and also allows you to return not just
|
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].
|
||||||
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`
|
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 %}`).
|
||||||
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
|
#### Twig filters and functions
|
||||||
|
|
||||||
Additional to [Twig][]'s extensive list of filters, functions and tags, Pico
|
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.
|
||||||
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
|
* 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`).
|
||||||
(e.g. `{{ "sub/page"|link }}` gets `%base_url%?sub/page`).
|
* You can replace URL placeholders (like <code>%base_url%</code>) in arbitrary strings using the `url` filter. This is helpful together with meta variables, e.g. if you add <code>image: "%assets_url%/stock.jpg"</code> to the YAML header of a page, `{{ meta.image|url }}` will return `%assets_url%/stock.jpg`.
|
||||||
* You can replace URL placeholders (like <code>%base_url%</code>) in
|
* To get the parsed contents of a page, pass its unique ID to the `content` filter (e.g. `{{ "sub/page"|content }}`).
|
||||||
arbitrary strings using the `url` filter. This is helpful together with meta
|
* 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>%meta.*%</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) }}`).
|
||||||
variables, e.g. if you add <code>image: %assets_url%/stock.jpg</code>
|
* 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.
|
||||||
to the YAML header of a page, `{{ meta.image|url }}` will return
|
* 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.
|
||||||
`%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>%meta.*%</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
|
||||||
|
|
||||||
#### Plugins for users
|
#### Plugins for users
|
||||||
|
|
||||||
Officially tested plugins can be found at http://picocms.org/plugins/, but
|
Officially tested plugins can be found at https://picocms.org/plugins/, but there are many awesome third-party plugins out there! A good start point for discovery is [our Wiki][WikiPlugins].
|
||||||
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
|
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. 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
|
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`.
|
||||||
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
|
#### Plugins for developers
|
||||||
|
|
||||||
You're a plugin developer? We love you guys! You can find tons of information
|
You're a plugin developer? We love you people! Check out Pico's `DummyPlugin` for the complete list of events Pico provides. If you've developed a plugin before and want to upgrade it to Pico's latest version, refer to the upgrade docs.
|
||||||
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
|
## Config
|
||||||
|
|
||||||
Configuring Pico really is stupidly simple: Just create a `config/config.yml`
|
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.
|
||||||
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
|
But we didn't stop there. Rather than having just a single config file, you can use an 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`).
|
||||||
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
|
Please note that Pico loads config files in a special way you should be aware of. 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".
|
||||||
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
|
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.
|
||||||
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
|
### URL Rewriting
|
||||||
|
|
||||||
Pico's default URLs (e.g. %base_url%/?sub/page) already are very user-friendly.
|
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.
|
||||||
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
|
#### Apache
|
||||||
|
|
||||||
If you're using the Apache web server, URL rewriting probably already is
|
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).
|
||||||
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
|
#### Nginx
|
||||||
|
|
||||||
If you're using Nginx, you can use the following config to enable URL rewriting
|
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].
|
||||||
(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(/|$))) {
|
location ~ ^/pico/((config|content|vendor|composer\.(json|lock|phar))(/|$)|(.+/)?\.(?!well-known(/|$))) {
|
||||||
|
@ -465,12 +254,7 @@ location /pico/ {
|
||||||
|
|
||||||
#### Lighttpd
|
#### Lighttpd
|
||||||
|
|
||||||
Pico runs smoothly on Lighttpd. You can use the following config to enable URL
|
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.
|
||||||
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 = (
|
url.rewrite-once = (
|
||||||
|
@ -501,7 +285,6 @@ For more help have a look at the Pico documentation at https://picocms.org/docs/
|
||||||
[FeaturesPagesFunction]: https://picocms.org/in-depth/features/pages-function/
|
[FeaturesPagesFunction]: https://picocms.org/in-depth/features/pages-function/
|
||||||
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins
|
[WikiPlugins]: https://github.com/picocms/Pico/wiki/Pico-Plugins
|
||||||
[OfficialThemes]: https://picocms.org/themes/
|
[OfficialThemes]: https://picocms.org/themes/
|
||||||
[PluginUpgrade]: https://picocms.org/development/#migrating-plugins
|
|
||||||
[ModRewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
|
[ModRewrite]: https://httpd.apache.org/docs/current/mod/mod_rewrite.html
|
||||||
[AllowOverride]: https://httpd.apache.org/docs/current/mod/core.html#allowoverride
|
[AllowOverride]: https://httpd.apache.org/docs/current/mod/core.html#allowoverride
|
||||||
[NginxConfig]: https://picocms.org/in-depth/nginx/
|
[NginxConfig]: https://picocms.org/in-depth/nginx/
|
||||||
|
|
|
@ -34,7 +34,7 @@ $pico = new Pico(
|
||||||
);
|
);
|
||||||
|
|
||||||
// override configuration?
|
// override configuration?
|
||||||
//$pico->setConfig(array());
|
//$pico->setConfig([]);
|
||||||
|
|
||||||
// run application
|
// run application
|
||||||
echo $pico->run();
|
echo $pico->run();
|
||||||
|
|
|
@ -11,8 +11,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// check PHP platform requirements
|
// check PHP platform requirements
|
||||||
if (PHP_VERSION_ID < 50306) {
|
if (PHP_VERSION_ID < 70205) {
|
||||||
die('Pico requires PHP 5.3.6 or above to run');
|
die('Pico requires PHP 7.2.5 or above to run');
|
||||||
}
|
}
|
||||||
if (!extension_loaded('dom')) {
|
if (!extension_loaded('dom')) {
|
||||||
die("Pico requires the PHP extension 'dom' to run");
|
die("Pico requires the PHP extension 'dom' to run");
|
||||||
|
@ -33,7 +33,7 @@ $pico = new Pico(
|
||||||
);
|
);
|
||||||
|
|
||||||
// override configuration?
|
// override configuration?
|
||||||
//$pico->setConfig(array());
|
//$pico->setConfig([]);
|
||||||
|
|
||||||
// run application
|
// run application
|
||||||
echo $pico->run();
|
echo $pico->run();
|
||||||
|
|
|
@ -10,18 +10,20 @@
|
||||||
* License-Filename: LICENSE
|
* License-Filename: LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to extend from when implementing a Pico plugin
|
* Abstract class to extend from when implementing a Pico plugin
|
||||||
*
|
*
|
||||||
* Please refer to {@see PicoPluginInterface} for more information about how
|
* Please refer to {@see PicoPluginInterface} for more information about how to
|
||||||
* to develop a plugin for Pico.
|
* develop a plugin for Pico.
|
||||||
*
|
*
|
||||||
* @see PicoPluginInterface
|
* @see PicoPluginInterface
|
||||||
*
|
*
|
||||||
* @author Daniel Rudolf
|
* @author Daniel Rudolf
|
||||||
* @link http://picocms.org
|
* @link https://picocms.org
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
* @license https://opensource.org/licenses/MIT The MIT License
|
||||||
* @version 2.1
|
* @version 3.0
|
||||||
*/
|
*/
|
||||||
abstract class AbstractPicoPlugin implements PicoPluginInterface
|
abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
{
|
{
|
||||||
|
@ -65,7 +67,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
* @see PicoPluginInterface::getDependencies()
|
* @see PicoPluginInterface::getDependencies()
|
||||||
* @var string[]
|
* @var string[]
|
||||||
*/
|
*/
|
||||||
protected $dependsOn = array();
|
protected $dependsOn = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of plugin which depend on this plugin
|
* List of plugin which depend on this plugin
|
||||||
|
@ -98,7 +100,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
|
|
||||||
if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) {
|
if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) {
|
||||||
if (method_exists($this, $eventName)) {
|
if (method_exists($this, $eventName)) {
|
||||||
call_user_func_array(array($this, $eventName), $params);
|
call_user_func_array([ $this, $eventName ], $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +110,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
*/
|
*/
|
||||||
protected function configEnabled()
|
protected function configEnabled()
|
||||||
{
|
{
|
||||||
$pluginEnabled = $this->getPico()->getConfig(get_called_class() . '.enabled');
|
$pluginEnabled = $this->getPico()->getConfig(static::class . '.enabled');
|
||||||
if ($pluginEnabled !== null) {
|
if ($pluginEnabled !== null) {
|
||||||
$this->setEnabled($pluginEnabled);
|
$this->setEnabled($pluginEnabled);
|
||||||
} else {
|
} else {
|
||||||
|
@ -184,7 +186,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
*/
|
*/
|
||||||
public function getPluginConfig($configName = null, $default = null)
|
public function getPluginConfig($configName = null, $default = null)
|
||||||
{
|
{
|
||||||
$pluginConfig = $this->getPico()->getConfig(get_called_class(), array());
|
$pluginConfig = $this->getPico()->getConfig(static::class, []);
|
||||||
|
|
||||||
if ($configName === null) {
|
if ($configName === null) {
|
||||||
return $pluginConfig;
|
return $pluginConfig;
|
||||||
|
@ -213,7 +215,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
|
|
||||||
throw new BadMethodCallException(
|
throw new BadMethodCallException(
|
||||||
'Call to undefined method ' . get_class($this->getPico()) . '::' . $methodName . '() '
|
'Call to undefined method ' . get_class($this->getPico()) . '::' . $methodName . '() '
|
||||||
. 'through ' . get_called_class() . '::__call()'
|
. 'through ' . static::class . '::__call()'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,7 +235,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
$plugin = $this->getPico()->getPlugin($pluginName);
|
$plugin = $this->getPico()->getPlugin($pluginName);
|
||||||
} catch (RuntimeException $e) {
|
} catch (RuntimeException $e) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to enable plugin '" . get_called_class() . "': "
|
"Unable to enable plugin '" . static::class . "': "
|
||||||
. "Required plugin '" . $pluginName . "' not found"
|
. "Required plugin '" . $pluginName . "' not found"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -245,13 +247,13 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
$plugin->setEnabled(true, true, true);
|
$plugin->setEnabled(true, true, true);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to enable plugin '" . get_called_class() . "': "
|
"Unable to enable plugin '" . static::class . "': "
|
||||||
. "Required plugin '" . $pluginName . "' was disabled manually"
|
. "Required plugin '" . $pluginName . "' was disabled manually"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to enable plugin '" . get_called_class() . "': "
|
"Unable to enable plugin '" . static::class . "': "
|
||||||
. "Required plugin '" . $pluginName . "' is disabled"
|
. "Required plugin '" . $pluginName . "' is disabled"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -287,7 +289,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
$plugin->setEnabled(false, true, true);
|
$plugin->setEnabled(false, true, true);
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to disable plugin '" . get_called_class() . "': "
|
"Unable to disable plugin '" . static::class . "': "
|
||||||
. "Required by manually enabled plugin '" . $pluginName . "'"
|
. "Required by manually enabled plugin '" . $pluginName . "'"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -297,7 +299,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
$dependantsList = 'plugin' . ((count($dependants) > 1) ? 's' : '') . ' '
|
$dependantsList = 'plugin' . ((count($dependants) > 1) ? 's' : '') . ' '
|
||||||
. "'" . implode("', '", array_keys($dependants)) . "'";
|
. "'" . implode("', '", array_keys($dependants)) . "'";
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to disable plugin '" . get_called_class() . "': "
|
"Unable to disable plugin '" . static::class . "': "
|
||||||
. "Required by " . $dependantsList
|
. "Required by " . $dependantsList
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -310,12 +312,12 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
public function getDependants()
|
public function getDependants()
|
||||||
{
|
{
|
||||||
if ($this->dependants === null) {
|
if ($this->dependants === null) {
|
||||||
$this->dependants = array();
|
$this->dependants = [];
|
||||||
foreach ($this->getPico()->getPlugins() as $pluginName => $plugin) {
|
foreach ($this->getPico()->getPlugins() as $pluginName => $plugin) {
|
||||||
// only plugins which implement PicoPluginInterface support dependencies
|
// only plugins which implement PicoPluginInterface support dependencies
|
||||||
if ($plugin instanceof PicoPluginInterface) {
|
if ($plugin instanceof PicoPluginInterface) {
|
||||||
$dependencies = $plugin->getDependencies();
|
$dependencies = $plugin->getDependencies();
|
||||||
if (in_array(get_called_class(), $dependencies)) {
|
if (in_array(static::class, $dependencies)) {
|
||||||
$this->dependants[$pluginName] = $plugin;
|
$this->dependants[$pluginName] = $plugin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -349,7 +351,7 @@ abstract class AbstractPicoPlugin implements PicoPluginInterface
|
||||||
|
|
||||||
if (!$this->nativePlugin && ($pluginApiVersion > $picoApiVersion)) {
|
if (!$this->nativePlugin && ($pluginApiVersion > $picoApiVersion)) {
|
||||||
throw new RuntimeException(
|
throw new RuntimeException(
|
||||||
"Unable to enable plugin '" . get_called_class() . "': The plugin's API (version "
|
"Unable to enable plugin '" . static::class . "': The plugin's API (version "
|
||||||
. $pluginApiVersion . ") isn't compatible with Pico's API (version " . $picoApiVersion . ")"
|
. $pluginApiVersion . ") isn't compatible with Pico's API (version " . $picoApiVersion . ")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
510
lib/Pico.php
510
lib/Pico.php
File diff suppressed because it is too large
Load diff
|
@ -10,6 +10,8 @@
|
||||||
* License-Filename: LICENSE
|
* License-Filename: LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Common interface for Pico plugins
|
* Common interface for Pico plugins
|
||||||
*
|
*
|
||||||
|
@ -24,9 +26,9 @@
|
||||||
* to update your plugin to use Pico's latest API version.
|
* to update your plugin to use Pico's latest API version.
|
||||||
*
|
*
|
||||||
* @author Daniel Rudolf
|
* @author Daniel Rudolf
|
||||||
* @link http://picocms.org
|
* @link https://picocms.org
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
* @license https://opensource.org/licenses/MIT The MIT License
|
||||||
* @version 2.1
|
* @version 3.0
|
||||||
*/
|
*/
|
||||||
interface PicoPluginInterface
|
interface PicoPluginInterface
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,15 +10,23 @@
|
||||||
* License-Filename: LICENSE
|
* License-Filename: LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Twig\Error\RuntimeError as TwigRuntimeError;
|
||||||
|
use Twig\Extension\AbstractExtension as AbstractTwigExtension;
|
||||||
|
use Twig\Extension\ExtensionInterface as TwigExtensionInterface;
|
||||||
|
use Twig\TwigFilter;
|
||||||
|
use Twig\TwigFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pico's Twig extension to implement additional filters
|
* Pico's Twig extension to implement additional filters
|
||||||
*
|
*
|
||||||
* @author Daniel Rudolf
|
* @author Daniel Rudolf
|
||||||
* @link http://picocms.org
|
* @link https://picocms.org
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
* @license https://opensource.org/licenses/MIT The MIT License
|
||||||
* @version 2.1
|
* @version 3.0
|
||||||
*/
|
*/
|
||||||
class PicoTwigExtension extends Twig_Extension
|
class PicoTwigExtension extends AbstractTwigExtension
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Current instance of Pico
|
* Current instance of Pico
|
||||||
|
@ -45,7 +53,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
*
|
*
|
||||||
* @return Pico the extension's instance of Pico
|
* @return Pico the extension's instance of Pico
|
||||||
*/
|
*/
|
||||||
public function getPico()
|
public function getPico(): Pico
|
||||||
{
|
{
|
||||||
return $this->pico;
|
return $this->pico;
|
||||||
}
|
}
|
||||||
|
@ -53,11 +61,11 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
/**
|
/**
|
||||||
* Returns the name of the extension
|
* Returns the name of the extension
|
||||||
*
|
*
|
||||||
* @see Twig_ExtensionInterface::getName()
|
* @see TwigExtensionInterface::getName()
|
||||||
*
|
*
|
||||||
* @return string the extension name
|
* @return string the extension name
|
||||||
*/
|
*/
|
||||||
public function getName()
|
public function getName(): string
|
||||||
{
|
{
|
||||||
return 'PicoTwigExtension';
|
return 'PicoTwigExtension';
|
||||||
}
|
}
|
||||||
|
@ -65,39 +73,35 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
/**
|
/**
|
||||||
* Returns a list of Pico-specific Twig filters
|
* Returns a list of Pico-specific Twig filters
|
||||||
*
|
*
|
||||||
* @see Twig_ExtensionInterface::getFilters()
|
* @see TwigExtensionInterface::getFilters()
|
||||||
*
|
*
|
||||||
* @return Twig_SimpleFilter[] array of Pico's Twig filters
|
* @return TwigFilter[] array of Pico's Twig filters
|
||||||
*/
|
*/
|
||||||
public function getFilters()
|
public function getFilters(): array
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'markdown' => new Twig_SimpleFilter(
|
'markdown' => new TwigFilter('markdown', [ $this, 'markdownFilter' ], [ 'is_safe' => [ 'html' ] ]),
|
||||||
'markdown',
|
'sort_by' => new TwigFilter('sort_by', [ $this, 'sortByFilter' ]),
|
||||||
array($this, 'markdownFilter'),
|
'link' => new TwigFilter('link', [ $this->pico, 'getPageUrl' ]),
|
||||||
array('is_safe' => array('html'))
|
'url' => new TwigFilter('url', [ $this->pico, 'substituteUrl' ]),
|
||||||
),
|
];
|
||||||
'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
|
* Returns a list of Pico-specific Twig functions
|
||||||
*
|
*
|
||||||
* @see Twig_ExtensionInterface::getFunctions()
|
* @see TwigExtensionInterface::getFunctions()
|
||||||
*
|
*
|
||||||
* @return Twig_SimpleFunction[] array of Pico's Twig functions
|
* @return TwigFunction[] array of Pico's Twig functions
|
||||||
*/
|
*/
|
||||||
public function getFunctions()
|
public function getFunctions(): array
|
||||||
{
|
{
|
||||||
return array(
|
return [
|
||||||
'url_param' => new Twig_SimpleFunction('url_param', array($this, 'urlParamFunction')),
|
'url_param' => new TwigFunction('url_param', [ $this, 'urlParamFunction' ]),
|
||||||
'form_param' => new Twig_SimpleFunction('form_param', array($this, 'formParamFunction')),
|
'form_param' => new TwigFunction('form_param', [ $this, 'formParamFunction' ]),
|
||||||
'pages' => new Twig_SimpleFunction('pages', array($this, 'pagesFunction'))
|
'page' => new TwigFunction('page', [ $this, 'pageFunction' ]),
|
||||||
);
|
'pages' => new TwigFunction('pages', [ $this, 'pagesFunction' ]),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -111,50 +115,18 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
* @see Pico::substituteFileContent()
|
* @see Pico::substituteFileContent()
|
||||||
* @see Pico::parseFileContent()
|
* @see Pico::parseFileContent()
|
||||||
*
|
*
|
||||||
* @param string $markdown markdown to parse
|
* @param string|null $markdown markdown to parse
|
||||||
* @param array $meta meta data to use for %meta.*% replacement
|
* @param array $meta meta data to use for %meta.*% replacement
|
||||||
* @param bool $singleLine whether to parse just a single line of markup
|
* @param bool $singleLine whether to parse a single line of markup
|
||||||
*
|
*
|
||||||
* @return string parsed HTML
|
* @return string parsed HTML
|
||||||
*/
|
*/
|
||||||
public function markdownFilter($markdown, array $meta = array(), $singleLine = false)
|
public function markdownFilter(?string $markdown, array $meta = [], bool $singleLine = false): string
|
||||||
{
|
{
|
||||||
$markdown = $this->getPico()->substituteFileContent($markdown, $meta);
|
$markdown = $this->getPico()->substituteFileContent($markdown ?? '', $meta);
|
||||||
return $this->getPico()->parseFileContent($markdown, $singleLine);
|
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
|
* Sorts an array by one of its keys or a arbitrary deep sub-key
|
||||||
*
|
*
|
||||||
|
@ -178,27 +150,27 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
*
|
*
|
||||||
* @return array sorted array
|
* @return array sorted array
|
||||||
*
|
*
|
||||||
* @throws Twig_Error_Runtime
|
* @throws TwigRuntimeError
|
||||||
*/
|
*/
|
||||||
public function sortByFilter($var, $sortKeyPath, $fallback = 'bottom')
|
public function sortByFilter($var, $sortKeyPath, string $fallback = 'bottom'): array
|
||||||
{
|
{
|
||||||
if (is_object($var) && ($var instanceof Traversable)) {
|
if (is_object($var) && ($var instanceof Traversable)) {
|
||||||
$var = iterator_to_array($var, true);
|
$var = iterator_to_array($var, true);
|
||||||
} elseif (!is_array($var)) {
|
} elseif (!is_array($var)) {
|
||||||
throw new Twig_Error_Runtime(sprintf(
|
throw new TwigRuntimeError(sprintf(
|
||||||
'The sort_by filter only works with arrays or "Traversable", got "%s"',
|
'The sort_by filter only works with arrays or "Traversable", got "%s"',
|
||||||
is_object($var) ? get_class($var) : gettype($var)
|
is_object($var) ? get_class($var) : gettype($var)
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if (($fallback !== 'top') && ($fallback !== 'bottom') && ($fallback !== 'keep') && ($fallback !== "remove")) {
|
if (($fallback !== 'top') && ($fallback !== 'bottom') && ($fallback !== 'keep') && ($fallback !== "remove")) {
|
||||||
throw new Twig_Error_Runtime(
|
throw new TwigRuntimeError(
|
||||||
'The sort_by filter only supports the "top", "bottom", "keep" and "remove" fallbacks'
|
'The sort_by filter only supports the "top", "bottom", "keep" and "remove" fallbacks'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$twigExtension = $this;
|
$twigExtension = $this;
|
||||||
$varKeys = array_keys($var);
|
$varKeys = array_keys($var);
|
||||||
$removeItems = array();
|
$removeItems = [];
|
||||||
uksort($var, function ($a, $b) use ($twigExtension, $var, $varKeys, $sortKeyPath, $fallback, &$removeItems) {
|
uksort($var, function ($a, $b) use ($twigExtension, $var, $varKeys, $sortKeyPath, $fallback, &$removeItems) {
|
||||||
$aSortValue = $twigExtension->getKeyOfVar($var[$a], $sortKeyPath);
|
$aSortValue = $twigExtension->getKeyOfVar($var[$a], $sortKeyPath);
|
||||||
$aSortValueNull = ($aSortValue === null);
|
$aSortValueNull = ($aSortValue === null);
|
||||||
|
@ -245,8 +217,8 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
*
|
*
|
||||||
* @param array|Traversable|ArrayAccess|object $var base variable
|
* @param array|Traversable|ArrayAccess|object $var base variable
|
||||||
* @param mixed $keyPath scalar key or a
|
* @param mixed $keyPath scalar key or a
|
||||||
* array interpreted as key path (when passing e.g. ['foo', 'bar'],
|
* array interpreted as key path (when passing e.g. ['foo', 'bar'], the
|
||||||
* the method will return $var['foo']['bar']) specifying the value
|
* method will return $var['foo']['bar']) specifying the value
|
||||||
*
|
*
|
||||||
* @return mixed the requested value or NULL when the given key or key path
|
* @return mixed the requested value or NULL when the given key or key path
|
||||||
* didn't match
|
* didn't match
|
||||||
|
@ -256,7 +228,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
if (!$keyPath) {
|
if (!$keyPath) {
|
||||||
return null;
|
return null;
|
||||||
} elseif (!is_array($keyPath)) {
|
} elseif (!is_array($keyPath)) {
|
||||||
$keyPath = array($keyPath);
|
$keyPath = [ $keyPath ];
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($keyPath as $key) {
|
foreach ($keyPath as $key) {
|
||||||
|
@ -268,9 +240,9 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
} elseif (isset($var->{$key})) {
|
} elseif (isset($var->{$key})) {
|
||||||
$var = $var->{$key};
|
$var = $var->{$key};
|
||||||
continue;
|
continue;
|
||||||
} elseif (is_callable(array($var, 'get' . ucfirst($key)))) {
|
} elseif (is_callable([ $var, 'get' . ucfirst($key) ])) {
|
||||||
try {
|
try {
|
||||||
$var = call_user_func(array($var, 'get' . ucfirst($key)));
|
$var = call_user_func([ $var, 'get' . ucfirst($key) ]);
|
||||||
continue;
|
continue;
|
||||||
} catch (BadMethodCallException $e) {
|
} catch (BadMethodCallException $e) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -312,7 +284,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
* NULL if the URL GET parameter doesn't exist and no default value is
|
* NULL if the URL GET parameter doesn't exist and no default value is
|
||||||
* given
|
* given
|
||||||
*/
|
*/
|
||||||
public function urlParamFunction($name, $filter = '', $options = null, $flags = null)
|
public function urlParamFunction(string $name, $filter = '', $options = null, $flags = null)
|
||||||
{
|
{
|
||||||
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
|
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
|
||||||
if (!$filter || ($filter === FILTER_CALLBACK)) {
|
if (!$filter || ($filter === FILTER_CALLBACK)) {
|
||||||
|
@ -341,7 +313,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
* NULL if the HTTP POST parameter doesn't exist and no default value
|
* NULL if the HTTP POST parameter doesn't exist and no default value
|
||||||
* is given
|
* is given
|
||||||
*/
|
*/
|
||||||
public function formParamFunction($name, $filter = '', $options = null, $flags = null)
|
public function formParamFunction(string $name, $filter = '', $options = null, $flags = null)
|
||||||
{
|
{
|
||||||
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
|
$filter = $filter ? (is_string($filter) ? filter_id($filter) : (int) $filter) : false;
|
||||||
if (!$filter || ($filter === FILTER_CALLBACK)) {
|
if (!$filter || ($filter === FILTER_CALLBACK)) {
|
||||||
|
@ -351,6 +323,19 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
return $this->pico->getFormParameter($name, $filter, $options, $flags);
|
return $this->pico->getFormParameter($name, $filter, $options, $flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the data of a single page
|
||||||
|
*
|
||||||
|
* @param string $id identifier of the page to return
|
||||||
|
*
|
||||||
|
* @return array|null the data of the page, or NULL
|
||||||
|
*/
|
||||||
|
public function pageFunction(string $id): ?array
|
||||||
|
{
|
||||||
|
$pages = $this->getPico()->getPages();
|
||||||
|
return $pages[$id] ?? null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns all pages within a particular branch of Pico's page tree
|
* Returns all pages within a particular branch of Pico's page tree
|
||||||
*
|
*
|
||||||
|
@ -399,7 +384,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
* returns Pico's full pages array.
|
* returns Pico's full pages array.
|
||||||
*
|
*
|
||||||
* If `$depth` is negative after taking `$offset` into consideration, the
|
* If `$depth` is negative after taking `$offset` into consideration, the
|
||||||
* function will throw a {@see Twig_Error_Runtime} exception, since this
|
* function will throw a {@see TwigRuntimeError} exception, since this
|
||||||
* would simply make no sense and is likely an error. Passing a negative
|
* would simply make no sense and is likely an error. Passing a negative
|
||||||
* `$depthOffset` is equivalent to passing `$depthOffset = 0`.
|
* `$depthOffset` is equivalent to passing `$depthOffset = 0`.
|
||||||
*
|
*
|
||||||
|
@ -421,9 +406,9 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
*
|
*
|
||||||
* @return array[] the data of the matched pages
|
* @return array[] the data of the matched pages
|
||||||
*
|
*
|
||||||
* @throws Twig_Error_Runtime
|
* @throws TwigRuntimeError
|
||||||
*/
|
*/
|
||||||
public function pagesFunction($start = '', $depth = 0, $depthOffset = 0, $offset = 1)
|
public function pagesFunction(string $start = '', ?int $depth = 0, int $depthOffset = 0, int $offset = 1): array
|
||||||
{
|
{
|
||||||
$start = (string) $start;
|
$start = (string) $start;
|
||||||
if (basename($start) === 'index') {
|
if (basename($start) === 'index') {
|
||||||
|
@ -431,7 +416,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; $offset < 0; $offset++) {
|
for (; $offset < 0; $offset++) {
|
||||||
if (in_array($start, array('', '.', '/'), true)) {
|
if (in_array($start, [ '', '.', '/' ], true)) {
|
||||||
$offset = 0;
|
$offset = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -443,11 +428,11 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
$depthOffset = $depthOffset + $offset;
|
$depthOffset = $depthOffset + $offset;
|
||||||
|
|
||||||
if (($depth !== null) && ($depth < 0)) {
|
if (($depth !== null) && ($depth < 0)) {
|
||||||
throw new Twig_Error_Runtime('The pages function doesn\'t support negative depths');
|
throw new TwigRuntimeError('The pages function doesn\'t support negative depths');
|
||||||
}
|
}
|
||||||
|
|
||||||
$pageTree = $this->getPico()->getPageTree();
|
$pageTree = $this->getPico()->getPageTree();
|
||||||
if (in_array($start, array('', '.', '/'), true)) {
|
if (in_array($start, [ '', '.', '/' ], true)) {
|
||||||
if (($depth === null) && ($depthOffset <= 0)) {
|
if (($depth === null) && ($depthOffset <= 0)) {
|
||||||
return $this->getPico()->getPages();
|
return $this->getPico()->getPages();
|
||||||
}
|
}
|
||||||
|
@ -461,11 +446,11 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$startNode) {
|
if (!$startNode) {
|
||||||
return array();
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$getPagesClosure = function ($nodes, $depth, $depthOffset) use (&$getPagesClosure) {
|
$getPagesClosure = function ($nodes, $depth, $depthOffset) use (&$getPagesClosure) {
|
||||||
$pages = array();
|
$pages = [];
|
||||||
foreach ($nodes as $node) {
|
foreach ($nodes as $node) {
|
||||||
if (isset($node['page']) && ($depthOffset <= 0)) {
|
if (isset($node['page']) && ($depthOffset <= 0)) {
|
||||||
$pages[$node['page']['id']] = &$node['page'];
|
$pages[$node['page']['id']] = &$node['page'];
|
||||||
|
@ -479,7 +464,7 @@ class PicoTwigExtension extends Twig_Extension
|
||||||
};
|
};
|
||||||
|
|
||||||
return $getPagesClosure(
|
return $getPagesClosure(
|
||||||
array($startNode),
|
[ $startNode ],
|
||||||
($depth !== null) ? $depth : INF,
|
($depth !== null) ? $depth : INF,
|
||||||
$depthOffset
|
$depthOffset
|
||||||
);
|
);
|
||||||
|
|
|
@ -10,6 +10,11 @@
|
||||||
* License-Filename: LICENSE
|
* License-Filename: LICENSE
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
use Symfony\Component\Yaml\Parser as YamlParser;
|
||||||
|
use Twig\Environment as TwigEnvironment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pico dummy plugin - a template for plugins
|
* Pico dummy plugin - a template for plugins
|
||||||
*
|
*
|
||||||
|
@ -17,9 +22,9 @@
|
||||||
* Simply remove the events you don't need and add your own logic.
|
* Simply remove the events you don't need and add your own logic.
|
||||||
*
|
*
|
||||||
* @author Daniel Rudolf
|
* @author Daniel Rudolf
|
||||||
* @link http://picocms.org
|
* @link https://picocms.org
|
||||||
* @license http://opensource.org/licenses/MIT The MIT License
|
* @license https://opensource.org/licenses/MIT The MIT License
|
||||||
* @version 2.1
|
* @version 3.0
|
||||||
*/
|
*/
|
||||||
class DummyPlugin extends AbstractPicoPlugin
|
class DummyPlugin extends AbstractPicoPlugin
|
||||||
{
|
{
|
||||||
|
@ -28,7 +33,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
const API_VERSION = 3;
|
public const API_VERSION = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This plugin is disabled by default
|
* This plugin is disabled by default
|
||||||
|
@ -36,8 +41,8 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* Usually you should remove this class property (or set it to NULL) to
|
* 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
|
* 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
|
* default up to Pico. If all the plugin's dependenies are fulfilled (see
|
||||||
* {@see DummyPlugin::$dependsOn}), Pico enables the plugin by default.
|
* {@see self::$dependsOn}), Pico enables the plugin by default. Otherwise
|
||||||
* Otherwise the plugin is silently disabled.
|
* the plugin is silently disabled.
|
||||||
*
|
*
|
||||||
* If this plugin should never be disabled *silently* (e.g. when dealing
|
* If this plugin should never be disabled *silently* (e.g. when dealing
|
||||||
* with security-relevant stuff like access control, or similar), set this
|
* with security-relevant stuff like access control, or similar), set this
|
||||||
|
@ -80,7 +85,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param object[] $plugins loaded plugin instances
|
* @param object[] $plugins loaded plugin instances
|
||||||
*/
|
*/
|
||||||
public function onPluginsLoaded(array $plugins)
|
public function onPluginsLoaded(array $plugins): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -94,7 +99,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param object $plugin loaded plugin instance
|
* @param object $plugin loaded plugin instance
|
||||||
*/
|
*/
|
||||||
public function onPluginManuallyLoaded($plugin)
|
public function onPluginManuallyLoaded(object $plugin): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -108,7 +113,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param array &$config array of config variables
|
* @param array &$config array of config variables
|
||||||
*/
|
*/
|
||||||
public function onConfigLoaded(array &$config)
|
public function onConfigLoaded(array &$config): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -121,7 +126,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$theme name of current theme
|
* @param string &$theme name of current theme
|
||||||
*/
|
*/
|
||||||
public function onThemeLoading(&$theme)
|
public function onThemeLoading(string &$theme): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -137,7 +142,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @param int $themeApiVersion API version of the theme
|
* @param int $themeApiVersion API version of the theme
|
||||||
* @param array &$themeConfig config array of the theme
|
* @param array &$themeConfig config array of the theme
|
||||||
*/
|
*/
|
||||||
public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig)
|
public function onThemeLoaded(string $theme, int $themeApiVersion, array &$themeConfig): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -149,7 +154,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$url part of the URL describing the requested contents
|
* @param string &$url part of the URL describing the requested contents
|
||||||
*/
|
*/
|
||||||
public function onRequestUrl(&$url)
|
public function onRequestUrl(string &$url): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -162,7 +167,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$file absolute path to the content file to serve
|
* @param string &$file absolute path to the content file to serve
|
||||||
*/
|
*/
|
||||||
public function onRequestFile(&$file)
|
public function onRequestFile(string &$file): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -173,7 +178,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @see Pico::loadFileContent()
|
* @see Pico::loadFileContent()
|
||||||
* @see DummyPlugin::onContentLoaded()
|
* @see DummyPlugin::onContentLoaded()
|
||||||
*/
|
*/
|
||||||
public function onContentLoading()
|
public function onContentLoading(): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -184,7 +189,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @see Pico::load404Content()
|
* @see Pico::load404Content()
|
||||||
* @see DummyPlugin::on404ContentLoaded()
|
* @see DummyPlugin::on404ContentLoaded()
|
||||||
*/
|
*/
|
||||||
public function on404ContentLoading()
|
public function on404ContentLoading(): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -198,7 +203,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$rawContent raw file contents
|
* @param string &$rawContent raw file contents
|
||||||
*/
|
*/
|
||||||
public function on404ContentLoaded(&$rawContent)
|
public function on404ContentLoaded(string &$rawContent): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -216,7 +221,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$rawContent raw file contents
|
* @param string &$rawContent raw file contents
|
||||||
*/
|
*/
|
||||||
public function onContentLoaded(&$rawContent)
|
public function onContentLoaded(string &$rawContent): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -227,7 +232,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @see Pico::parseFileMeta()
|
* @see Pico::parseFileMeta()
|
||||||
* @see DummyPlugin::onMetaParsed()
|
* @see DummyPlugin::onMetaParsed()
|
||||||
*/
|
*/
|
||||||
public function onMetaParsing()
|
public function onMetaParsing(): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -240,7 +245,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string[] &$meta parsed meta data
|
* @param string[] &$meta parsed meta data
|
||||||
*/
|
*/
|
||||||
public function onMetaParsed(array &$meta)
|
public function onMetaParsed(array &$meta): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -253,7 +258,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @see DummyPlugin::onContentPrepared()
|
* @see DummyPlugin::onContentPrepared()
|
||||||
* @see DummyPlugin::onContentParsed()
|
* @see DummyPlugin::onContentParsed()
|
||||||
*/
|
*/
|
||||||
public function onContentParsing()
|
public function onContentParsing(): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -267,7 +272,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$markdown Markdown contents of the requested page
|
* @param string &$markdown Markdown contents of the requested page
|
||||||
*/
|
*/
|
||||||
public function onContentPrepared(&$markdown)
|
public function onContentPrepared(string &$markdown): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -281,7 +286,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$content parsed contents (HTML) of the requested page
|
* @param string &$content parsed contents (HTML) of the requested page
|
||||||
*/
|
*/
|
||||||
public function onContentParsed(&$content)
|
public function onContentParsed(string &$content): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -292,7 +297,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @see DummyPlugin::onPagesDiscovered()
|
* @see DummyPlugin::onPagesDiscovered()
|
||||||
* @see DummyPlugin::onPagesLoaded()
|
* @see DummyPlugin::onPagesLoaded()
|
||||||
*/
|
*/
|
||||||
public function onPagesLoading()
|
public function onPagesLoading(): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -313,7 +318,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @param bool|null $skipPage set this to TRUE to remove this page from the
|
* @param bool|null $skipPage set this to TRUE to remove this page from the
|
||||||
* pages array, otherwise leave it unchanged
|
* pages array, otherwise leave it unchanged
|
||||||
*/
|
*/
|
||||||
public function onSinglePageLoading($id, &$skipPage)
|
public function onSinglePageLoading(string $id, ?bool &$skipPage): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -331,7 +336,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @param string $id relative path to the content file
|
* @param string $id relative path to the content file
|
||||||
* @param string &$rawContent raw file contents
|
* @param string &$rawContent raw file contents
|
||||||
*/
|
*/
|
||||||
public function onSinglePageContent($id, &$rawContent)
|
public function onSinglePageContent(string $id, string &$rawContent): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -347,7 +352,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param array &$pageData data of the loaded page
|
* @param array &$pageData data of the loaded page
|
||||||
*/
|
*/
|
||||||
public function onSinglePageLoaded(array &$pageData)
|
public function onSinglePageLoaded(array &$pageData): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -365,7 +370,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param array[] &$pages list of all known pages
|
* @param array[] &$pages list of all known pages
|
||||||
*/
|
*/
|
||||||
public function onPagesDiscovered(array &$pages)
|
public function onPagesDiscovered(array &$pages): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -383,7 +388,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param array[] &$pages sorted list of all known pages
|
* @param array[] &$pages sorted list of all known pages
|
||||||
*/
|
*/
|
||||||
public function onPagesLoaded(array &$pages)
|
public function onPagesLoaded(array &$pages): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -408,7 +413,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
array &$currentPage = null,
|
array &$currentPage = null,
|
||||||
array &$previousPage = null,
|
array &$previousPage = null,
|
||||||
array &$nextPage = null
|
array &$nextPage = null
|
||||||
) {
|
): void {
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,7 +427,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param array &$pageTree page tree
|
* @param array &$pageTree page tree
|
||||||
*/
|
*/
|
||||||
public function onPageTreeBuilt(array &$pageTree)
|
public function onPageTreeBuilt(array &$pageTree): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -435,7 +440,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* @param string &$templateName file name of the template
|
* @param string &$templateName file name of the template
|
||||||
* @param array &$twigVariables template variables
|
* @param array &$twigVariables template variables
|
||||||
*/
|
*/
|
||||||
public function onPageRendering(&$templateName, array &$twigVariables)
|
public function onPageRendering(string &$templateName, array &$twigVariables): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -447,7 +452,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param string &$output contents which will be sent to the user
|
* @param string &$output contents which will be sent to the user
|
||||||
*/
|
*/
|
||||||
public function onPageRendered(&$output)
|
public function onPageRendered(string &$output): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -461,7 +466,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
* key specifies the YAML key to search for, the array value is later
|
* key specifies the YAML key to search for, the array value is later
|
||||||
* used to access the found value
|
* used to access the found value
|
||||||
*/
|
*/
|
||||||
public function onMetaHeaders(array &$headers)
|
public function onMetaHeaders(array &$headers): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -471,9 +476,9 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @see Pico::getYamlParser()
|
* @see Pico::getYamlParser()
|
||||||
*
|
*
|
||||||
* @param \Symfony\Component\Yaml\Parser &$yamlParser YAML parser instance
|
* @param YamlParser &$yamlParser YAML parser instance
|
||||||
*/
|
*/
|
||||||
public function onYamlParserRegistered(\Symfony\Component\Yaml\Parser &$yamlParser)
|
public function onYamlParserRegistered(YamlParser &$yamlParser): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -485,7 +490,7 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @param Parsedown &$parsedown Parsedown instance
|
* @param Parsedown &$parsedown Parsedown instance
|
||||||
*/
|
*/
|
||||||
public function onParsedownRegistered(Parsedown &$parsedown)
|
public function onParsedownRegistered(Parsedown &$parsedown): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
@ -495,9 +500,9 @@ class DummyPlugin extends AbstractPicoPlugin
|
||||||
*
|
*
|
||||||
* @see Pico::getTwig()
|
* @see Pico::getTwig()
|
||||||
*
|
*
|
||||||
* @param Twig_Environment &$twig Twig instance
|
* @param TwigEnvironment &$twig Twig instance
|
||||||
*/
|
*/
|
||||||
public function onTwigRegistered(Twig_Environment &$twig)
|
public function onTwigRegistered(TwigEnvironment &$twig): void
|
||||||
{
|
{
|
||||||
// your code
|
// your code
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue