From a2c7b01cb7610744a4fc9b060eadee57afce64e1 Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Thu, 6 Apr 2023 08:33:23 -0600 Subject: [PATCH] Release 1.2.3 (#223) * [CMS-1033] Add GH action for deployments to wp.org (#203) * Cleanup distignore * Link readme files to new contrib doc * Add CONTRIBUTING.md, add automation for wp.org * distignore behat.yml * add CODEOWNERS and distignore * Add assets * Fix GH action (#205) * Make dependabot target develop branch (#209) * Bump dealerdirect/phpcodesniffer-composer-installer from 0.7.2 to 1.0.0 Bumps [dealerdirect/phpcodesniffer-composer-installer](https://github.com/Dealerdirect/phpcodesniffer-composer-installer) from 0.7.2 to 1.0.0. - [Release notes](https://github.com/Dealerdirect/phpcodesniffer-composer-installer/releases) - [Changelog](https://github.com/PHPCSStandards/composer-installer/blob/main/.github_changelog_generator) - [Commits](https://github.com/Dealerdirect/phpcodesniffer-composer-installer/compare/v0.7.2...v1.0.0) --- updated-dependencies: - dependency-name: dealerdirect/phpcodesniffer-composer-installer dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Bump dealerdirect/phpcodesniffer-composer-installer from 0.7.2 to 1.0.0 Bumps [dealerdirect/phpcodesniffer-composer-installer](https://github.com/Dealerdirect/phpcodesniffer-composer-installer) from 0.7.2 to 1.0.0. - [Release notes](https://github.com/Dealerdirect/phpcodesniffer-composer-installer/releases) - [Changelog](https://github.com/PHPCSStandards/composer-installer/blob/main/.github_changelog_generator) - [Commits](https://github.com/Dealerdirect/phpcodesniffer-composer-installer/compare/v0.7.2...v1.0.0) --- updated-dependencies: - dependency-name: dealerdirect/phpcodesniffer-composer-installer dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * handle models that are not instances of the Model class * Bump grunt from 1.5.3 to 1.6.1 Bumps [grunt](https://github.com/gruntjs/grunt) from 1.5.3 to 1.6.1. - [Release notes](https://github.com/gruntjs/grunt/releases) - [Changelog](https://github.com/gruntjs/grunt/blob/main/CHANGELOG) - [Commits](https://github.com/gruntjs/grunt/compare/v1.5.3...v1.6.1) --- updated-dependencies: - dependency-name: grunt dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] * Bump yoast/phpunit-polyfills from 1.0.3 to 1.0.4 Bumps [yoast/phpunit-polyfills](https://github.com/Yoast/PHPUnit-Polyfills) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/Yoast/PHPUnit-Polyfills/releases) - [Changelog](https://github.com/Yoast/PHPUnit-Polyfills/blob/develop/CHANGELOG.md) - [Commits](https://github.com/Yoast/PHPUnit-Polyfills/compare/1.0.3...1.0.4) --- updated-dependencies: - dependency-name: yoast/phpunit-polyfills dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Test more versions of PHP (#218) * add our coding standards * ignore tests/ * phpcbf changes * ignore the rule that doesn't matter * ignore nonce check * sanitization fixes * ignore missing param tags in docblocks for cli commands * ignore sniffs for unused variables while the variables aren't used, the functions that are extended might still expect the param to exist, so we're just going to ignore the sniff * spacing * ignore some annoying sniffs * explain why we are ignoring sniffs at the file level * use php 8.1 image for linting * use php8.0 image for linting * return type must be void * ignore platform requirements for composer install don't error for < php8.0 when running 7.4 tests * Release 1.2.2 (#219) * Bump yoast/phpunit-polyfills from 1.0.3 to 1.0.4 Bumps [yoast/phpunit-polyfills](https://github.com/Yoast/PHPUnit-Polyfills) from 1.0.3 to 1.0.4. - [Release notes](https://github.com/Yoast/PHPUnit-Polyfills/releases) - [Changelog](https://github.com/Yoast/PHPUnit-Polyfills/blob/develop/CHANGELOG.md) - [Commits](https://github.com/Yoast/PHPUnit-Polyfills/compare/1.0.3...1.0.4) --- updated-dependencies: - dependency-name: yoast/phpunit-polyfills dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Test more versions of PHP (#218) * Release 1.2.2 --------- Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * bump version * add chris and john to contributors * add cms-platform to codeowners * update changelog * update the lockfile --------- Signed-off-by: dependabot[bot] Co-authored-by: John Spellman Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .circleci/config.yml | 4 +- CODEOWNERS | 2 +- README.md | 13 +- composer.json | 8 +- composer.lock | 713 ++++++++++++----- inc/class-cli.php | 7 +- inc/class-emitter.php | 67 +- inc/class-purger.php | 45 +- inc/class-user-interface.php | 36 +- pantheon-advanced-page-cache.php | 51 +- readme.txt | 718 +++++++++--------- ...-pantheon-advanced-page-cache-testcase.php | 134 ++-- 12 files changed, 1067 insertions(+), 731 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index e572b858..747b25b4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -41,7 +41,7 @@ jobs: lint: working_directory: ~/pantheon-systems/pantheon-advanced-page-cache docker: - - image: quay.io/pantheon-public/build-tools-ci:8.x-php8.2 + - image: quay.io/pantheon-public/build-tools-ci:8.x-php8.0 steps: - checkout - restore_cache: @@ -122,7 +122,7 @@ jobs: - restore_cache: keys: - test-phpunit-dependencies-{{ checksum "composer.json" }} - - run: composer install -n --prefer-dist + - run: composer install -n --prefer-dist --ignore-platform-reqs - save_cache: key: test-phpunit-dependencies-{{ checksum "composer.json" }} paths: diff --git a/CODEOWNERS b/CODEOWNERS index fb22ed56..6ed271b0 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @pantheon-systems/cms-ecosystem \ No newline at end of file +* @pantheon-systems/cms-platform @pantheon-systems/cms-ecosystem diff --git a/README.md b/README.md index fe445490..0b33a0a9 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ # Pantheon Advanced Page Cache # -**Contributors:** [getpantheon](https://profiles.wordpress.org/getpantheon), [danielbachhuber](https://profiles.wordpress.org/danielbachhuber), [kporras07](https://profiles.wordpress.org/kporras07) -**Tags:** pantheon, cdn, cache +**Contributors:** [getpantheon](https://profiles.wordpress.org/getpantheon), [danielbachhuber](https://profiles.wordpress.org/danielbachhuber), [kporras07](https://profiles.wordpress.org/kporras07) [jspellman](https://profiles.wordpress.org/jspellman/) [jazzs3quence](https://profiles.wordpress.org/jazzs3quence/) +**Tags:** pantheon, cdn, cache **Requires at least:** 4.7 -**Tested up to:** 6.1 -**Stable tag:** 1.2.2 +**Tested up to:** 6.2 +**Stable tag:** 1.2.3 **License:** GPLv2 or later -**License URI:** http://www.gnu.org/licenses/gpl-2.0.html +**License URI:** http://www.gnu.org/licenses/gpl-2.0.html Automatically clear related pages from Pantheon's Edge when you update content. High TTL. Fresh content. Visitors never wait. @@ -304,6 +304,9 @@ See [CONTRIBUTING.md](https://github.com/pantheon-systems/pantheon-advanced-page ## Changelog ## +## 1.2.3 (April 5, 2023) ## +* Bump tested up to version to 6.2 + ## 1.2.2 (March 14, 2023) ## * Adds PHP 8.2 compatibility [[#218](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/218)]. * Bump dependencies [[#204](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/204)]. diff --git a/composer.json b/composer.json index c1414b07..6df7c4f0 100644 --- a/composer.json +++ b/composer.json @@ -12,15 +12,15 @@ "behat/mink-extension": "^2.2", "behat/mink-goutte-driver": "^1.2", "pantheon-systems/pantheon-wordpress-upstream-tests": "dev-master", - "wp-coding-standards/wpcs": "dev-develop as 2.3.1", - "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", "phpunit/phpunit": "^9", "phpcompatibility/php-compatibility": "^9.3", - "yoast/phpunit-polyfills": "^1.0" + "yoast/phpunit-polyfills": "^1.0", + "pantheon-systems/pantheon-wp-coding-standards": "^1.0" }, "scripts": { "lint": "@phpcs", - "phpcs": "vendor/bin/phpcs", + "phpcs": "vendor/bin/phpcs --ignore=tests/* -s --standard=Pantheon-WP .", + "phpcbf": "vendor/bin/phpcbf --ignore=tests/* --standard=Pantheon-WP .", "phpunit": "vendor/bin/phpunit", "test": "@phpunit" }, diff --git a/composer.lock b/composer.lock index 30802d9b..5c8b136a 100644 --- a/composer.lock +++ b/composer.lock @@ -4,9 +4,61 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3a8e6d8dc4592eea1ab23132ed21b539", + "content-hash": "a1afbabe299db7d40326742d80991334", "packages": [], "packages-dev": [ + { + "name": "automattic/vipwpcs", + "version": "2.3.3", + "source": { + "type": "git", + "url": "https://github.com/Automattic/VIP-Coding-Standards.git", + "reference": "6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Automattic/VIP-Coding-Standards/zipball/6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b", + "reference": "6cd0a6a82bc0ac988dbf9d6a7c2e293dc8ac640b", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7", + "php": ">=5.4", + "sirbrillig/phpcs-variable-analysis": "^2.11.1", + "squizlabs/php_codesniffer": "^3.5.5", + "wp-coding-standards/wpcs": "^2.3" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^0.5", + "php-parallel-lint/php-parallel-lint": "^1.0", + "phpcompatibility/php-compatibility": "^9", + "phpcsstandards/phpcsdevtools": "^1.0", + "phpunit/phpunit": "^4 || ^5 || ^6 || ^7" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Contributors", + "homepage": "https://github.com/Automattic/VIP-Coding-Standards/graphs/contributors" + } + ], + "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress VIP minimum coding conventions", + "keywords": [ + "phpcs", + "standards", + "wordpress" + ], + "support": { + "issues": "https://github.com/Automattic/VIP-Coding-Standards/issues", + "source": "https://github.com/Automattic/VIP-Coding-Standards", + "wiki": "https://github.com/Automattic/VIP-Coding-Standards/wiki" + }, + "time": "2021-09-29T16:20:23+00:00" + }, { "name": "behat/behat", "version": "v3.12.0", @@ -456,38 +508,35 @@ }, { "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.0.0", + "version": "v0.7.2", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "4be43904336affa5c2f70744a348312336afd0da" + "url": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer.git", + "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", - "reference": "4be43904336affa5c2f70744a348312336afd0da", + "url": "https://api.github.com/repos/Dealerdirect/phpcodesniffer-composer-installer/zipball/1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", + "reference": "1c968e542d8843d7cd71de3c5c9c3ff3ad71a1db", "shasum": "" }, "require": { "composer-plugin-api": "^1.0 || ^2.0", - "php": ">=5.4", + "php": ">=5.3", "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, "require-dev": { "composer/composer": "*", - "ext-json": "*", - "ext-zip": "*", "php-parallel-lint/php-parallel-lint": "^1.3.1", - "phpcompatibility/php-compatibility": "^9.0", - "yoast/phpunit-polyfills": "^1.0" + "phpcompatibility/php-compatibility": "^9.0" }, "type": "composer-plugin", "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" + "class": "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", @@ -503,7 +552,7 @@ }, { "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" + "homepage": "https://github.com/Dealerdirect/phpcodesniffer-composer-installer/graphs/contributors" } ], "description": "PHP_CodeSniffer Standards Composer Installer Plugin", @@ -527,10 +576,10 @@ "tests" ], "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "source": "https://github.com/PHPCSStandards/composer-installer" + "issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues", + "source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer" }, - "time": "2023-01-05T11:28:13+00:00" + "time": "2022-02-04T12:51:07+00:00" }, { "name": "doctrine/instantiator", @@ -659,8 +708,65 @@ "issues": "https://github.com/FriendsOfPHP/Goutte/issues", "source": "https://github.com/FriendsOfPHP/Goutte/tree/v3.3.1" }, + "abandoned": "symfony/browser-kit", "time": "2020-11-01T09:30:18+00:00" }, + { + "name": "fig-r/psr2r-sniffer", + "version": "1.5.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig-rectified/psr2r-sniffer.git", + "reference": "53ca1ecd62b0dc2ab8ea48635f583cb361c5e8f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig-rectified/psr2r-sniffer/zipball/53ca1ecd62b0dc2ab8ea48635f583cb361c5e8f2", + "reference": "53ca1ecd62b0dc2ab8ea48635f583cb361c5e8f2", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "slevomat/coding-standard": "^7.2.0 || ^8.3.0", + "spryker/code-sniffer": "^0.17.1", + "squizlabs/php_codesniffer": "^3.7.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.0.0" + }, + "bin": [ + "bin/tokenize", + "bin/sniff" + ], + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "PSR2R\\": "PSR2R/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Scherer", + "homepage": "https://www.dereuromark.de", + "role": "Contributor" + } + ], + "description": "Code-Sniffer, Auto-Fixer and Tokenizer for PSR2-R", + "keywords": [ + "codesniffer", + "cs", + "static analysis" + ], + "support": { + "issues": "https://github.com/php-fig-rectified/psr2r-sniffer/issues", + "source": "https://github.com/php-fig-rectified/psr2r-sniffer/tree/1.5.0" + }, + "time": "2023-01-01T15:31:05+00:00" + }, { "name": "guzzlehttp/guzzle", "version": "6.5.8", @@ -1124,6 +1230,48 @@ }, "time": "2020-04-17T11:46:11+00:00" }, + { + "name": "pantheon-systems/pantheon-wp-coding-standards", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/pantheon-systems/Pantheon-WP-Coding-Standards.git", + "reference": "9555c8e63b521380b4630fe16674ef7c97dd8873" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/pantheon-systems/Pantheon-WP-Coding-Standards/zipball/9555c8e63b521380b4630fe16674ef7c97dd8873", + "reference": "9555c8e63b521380b4630fe16674ef7c97dd8873", + "shasum": "" + }, + "require": { + "automattic/vipwpcs": "^2.3", + "fig-r/psr2r-sniffer": "^1.5", + "phpcompatibility/phpcompatibility-wp": "^2.1", + "wp-coding-standards/wpcs": "^2.3" + }, + "require-dev": { + "phpunit/phpunit": "9.6.x-dev", + "yoast/phpunit-polyfills": "1.x-dev" + }, + "type": "phpcodesniffer-standard", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Pantheon", + "email": "noreply@pantheon.io" + } + ], + "description": "PHPCS Rulesets for WordPress projects on Pantheon.", + "support": { + "issues": "https://github.com/pantheon-systems/Pantheon-WP-Coding-Standards/issues", + "source": "https://github.com/pantheon-systems/Pantheon-WP-Coding-Standards/tree/1.0.0" + }, + "time": "2023-02-17T16:16:30+00:00" + }, { "name": "phar-io/manifest", "version": "2.0.3", @@ -1298,141 +1446,161 @@ "time": "2019-12-27T09:44:58+00:00" }, { - "name": "phpcsstandards/phpcsextra", - "version": "1.0.2", + "name": "phpcompatibility/phpcompatibility-paragonie", + "version": "1.3.2", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "a077c4ad65b906768ed2f820701958b57f605be0" + "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", + "reference": "bba5a9dfec7fcfbd679cfaf611d86b4d3759da26" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/a077c4ad65b906768ed2f820701958b57f605be0", - "reference": "a077c4ad65b906768ed2f820701958b57f605be0", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/bba5a9dfec7fcfbd679cfaf611d86b4d3759da26", + "reference": "bba5a9dfec7fcfbd679cfaf611d86b4d3759da26", "shasum": "" }, "require": { - "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.0", - "squizlabs/php_codesniffer": "^3.7.1" + "phpcompatibility/php-compatibility": "^9.0" }, "require-dev": { - "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpcsstandards/phpcsdevcs": "^1.1.5", - "phpcsstandards/phpcsdevtools": "^1.2.0", - "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "paragonie/random_compat": "dev-master", + "paragonie/sodium_compat": "dev-master" }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-stable": "1.x-dev", - "dev-develop": "1.x-dev" - } + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, + "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", "license": [ "LGPL-3.0-or-later" ], "authors": [ { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", + "name": "Wim Godden", "role": "lead" }, { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" + "name": "Juliette Reinders Folmer", + "role": "lead" } ], - "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", + "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", + "homepage": "http://phpcompatibility.com/", "keywords": [ - "PHP_CodeSniffer", - "phpcbf", - "phpcodesniffer-standard", + "compatibility", + "paragonie", "phpcs", + "polyfill", "standards", "static analysis" ], "support": { - "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", - "source": "https://github.com/PHPCSStandards/PHPCSExtra" + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" }, - "time": "2023-01-09T22:15:31+00:00" + "time": "2022-10-25T01:46:02+00:00" }, { - "name": "phpcsstandards/phpcsutils", - "version": "1.0.1", + "name": "phpcompatibility/phpcompatibility-wp", + "version": "2.1.4", "source": { "type": "git", - "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "4fd2e30c7465112ca2e3646037bfb9e6f0f4d4f3" + "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", + "reference": "b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/4fd2e30c7465112ca2e3646037bfb9e6f0f4d4f3", - "reference": "4fd2e30c7465112ca2e3646037bfb9e6f0f4d4f3", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5", + "reference": "b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.7.1 || 4.0.x-dev@dev" + "phpcompatibility/php-compatibility": "^9.0", + "phpcompatibility/phpcompatibility-paragonie": "^1.0" }, "require-dev": { - "ext-filter": "*", - "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", - "phpcsstandards/phpcsdevcs": "^1.1.3", - "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.3", - "yoast/phpunit-polyfills": "^1.0.1" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7" }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-stable": "1.x-dev", - "dev-develop": "1.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPCSUtils/" - ] + "suggest": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", + "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, + "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", "license": [ "LGPL-3.0-or-later" ], "authors": [ { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", + "name": "Wim Godden", "role": "lead" }, { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" + "name": "Juliette Reinders Folmer", + "role": "lead" } ], - "description": "A suite of utility functions for use with PHP_CodeSniffer", - "homepage": "https://phpcsutils.com/", + "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", + "homepage": "http://phpcompatibility.com/", "keywords": [ - "PHP_CodeSniffer", - "phpcbf", - "phpcodesniffer-standard", + "compatibility", "phpcs", - "phpcs3", "standards", "static analysis", - "tokens", - "utility" + "wordpress" + ], + "support": { + "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", + "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" + }, + "time": "2022-10-24T09:00:36+00:00" + }, + { + "name": "phpstan/phpdoc-parser", + "version": "1.17.1", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpdoc-parser.git", + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "reference": "d3753fcb3abc6f78f5de6f72153d4b9c99c72dee", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.5", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.0", + "phpunit/phpunit": "^9.5", + "symfony/process": "^5.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "PHPStan\\PhpDocParser\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" ], + "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { - "docs": "https://phpcsutils.com/", - "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", - "source": "https://github.com/PHPCSStandards/PHPCSUtils" + "issues": "https://github.com/phpstan/phpdoc-parser/issues", + "source": "https://github.com/phpstan/phpdoc-parser/tree/1.17.1" }, - "time": "2023-01-05T12:08:37+00:00" + "time": "2023-04-04T11:11:22+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1754,16 +1922,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.5", + "version": "9.6.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5" + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/86e761949019ae83f49240b2f2123fb5ab3b2fc5", - "reference": "86e761949019ae83f49240b2f2123fb5ab3b2fc5", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b65d59a059d3004a040c16a82e07bbdf6cfdd115", + "reference": "b65d59a059d3004a040c16a82e07bbdf6cfdd115", "shasum": "" }, "require": { @@ -1836,7 +2004,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.5" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.6" }, "funding": [ { @@ -1852,7 +2021,7 @@ "type": "tidelift" } ], - "time": "2023-03-09T06:34:10+00:00" + "time": "2023-03-27T11:43:46+00:00" }, { "name": "psr/container", @@ -1954,25 +2123,25 @@ }, { "name": "psr/http-message", - "version": "1.0.1", + "version": "1.1", "source": { "type": "git", "url": "https://github.com/php-fig/http-message.git", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363" + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363", - "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/cb6ce4845ce34a8ad9e68117c10ee90a29919eba", + "reference": "cb6ce4845ce34a8ad9e68117c10ee90a29919eba", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "1.1.x-dev" } }, "autoload": { @@ -2001,9 +2170,9 @@ "response" ], "support": { - "source": "https://github.com/php-fig/http-message/tree/master" + "source": "https://github.com/php-fig/http-message/tree/1.1" }, - "time": "2016-08-06T14:39:51+00:00" + "time": "2023-04-04T09:50:52+00:00" }, { "name": "ralouphie/getallheaders", @@ -3013,6 +3182,187 @@ ], "time": "2020-09-28T06:39:44+00:00" }, + { + "name": "sirbrillig/phpcs-variable-analysis", + "version": "v2.11.16", + "source": { + "type": "git", + "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", + "reference": "dc5582dc5a93a235557af73e523c389aac9a8e88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/dc5582dc5a93a235557af73e523c389aac9a8e88", + "reference": "dc5582dc5a93a235557af73e523c389aac9a8e88", + "shasum": "" + }, + "require": { + "php": ">=5.4.0", + "squizlabs/php_codesniffer": "^3.5.6" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || ^1.0", + "phpcsstandards/phpcsdevcs": "^1.1", + "phpstan/phpstan": "^1.7", + "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.5 || ^7.0 || ^8.0 || ^9.0", + "sirbrillig/phpcs-import-detection": "^1.1", + "vimeo/psalm": "^0.2 || ^0.3 || ^1.1 || ^4.24 || ^5.0@beta" + }, + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "VariableAnalysis\\": "VariableAnalysis/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-2-Clause" + ], + "authors": [ + { + "name": "Sam Graham", + "email": "php-codesniffer-variableanalysis@illusori.co.uk" + }, + { + "name": "Payton Swick", + "email": "payton@foolord.com" + } + ], + "description": "A PHPCS sniff to detect problems with variables.", + "keywords": [ + "phpcs", + "static analysis" + ], + "support": { + "issues": "https://github.com/sirbrillig/phpcs-variable-analysis/issues", + "source": "https://github.com/sirbrillig/phpcs-variable-analysis", + "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" + }, + "time": "2023-03-31T16:46:32+00:00" + }, + { + "name": "slevomat/coding-standard", + "version": "8.9.2", + "source": { + "type": "git", + "url": "https://github.com/slevomat/coding-standard.git", + "reference": "c9b39061ebd5c58b71ecae26042eb7b054c380dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/c9b39061ebd5c58b71ecae26042eb7b054c380dd", + "reference": "c9b39061ebd5c58b71ecae26042eb7b054c380dd", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.0", + "php": "^7.2 || ^8.0", + "phpstan/phpdoc-parser": ">=1.16.0 <1.18.0", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "phing/phing": "2.17.4", + "php-parallel-lint/php-parallel-lint": "1.3.2", + "phpstan/phpstan": "1.4.10|1.10.11", + "phpstan/phpstan-deprecation-rules": "1.1.3", + "phpstan/phpstan-phpunit": "1.0.0|1.3.11", + "phpstan/phpstan-strict-rules": "1.5.1", + "phpunit/phpunit": "7.5.20|8.5.21|9.6.6" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-master": "8.x-dev" + } + }, + "autoload": { + "psr-4": { + "SlevomatCodingStandard\\": "SlevomatCodingStandard/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Slevomat Coding Standard for PHP_CodeSniffer complements Consistence Coding Standard by providing sniffs with additional checks.", + "keywords": [ + "dev", + "phpcs" + ], + "support": { + "issues": "https://github.com/slevomat/coding-standard/issues", + "source": "https://github.com/slevomat/coding-standard/tree/8.9.2" + }, + "funding": [ + { + "url": "https://github.com/kukulich", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/slevomat/coding-standard", + "type": "tidelift" + } + ], + "time": "2023-04-05T06:23:58+00:00" + }, + { + "name": "spryker/code-sniffer", + "version": "0.17.18", + "source": { + "type": "git", + "url": "https://github.com/spryker/code-sniffer.git", + "reference": "5fb8b573abc4a906d0d364a4a03abd38e565ba29" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spryker/code-sniffer/zipball/5fb8b573abc4a906d0d364a4a03abd38e565ba29", + "reference": "5fb8b573abc4a906d0d364a4a03abd38e565ba29", + "shasum": "" + }, + "require": { + "php": ">=7.4", + "slevomat/coding-standard": "^7.2.0 || ^8.0.1", + "squizlabs/php_codesniffer": "^3.6.2" + }, + "require-dev": { + "phpstan/phpstan": "^1.0.0", + "phpunit/phpunit": "^9.5" + }, + "bin": [ + "bin/tokenize" + ], + "type": "phpcodesniffer-standard", + "autoload": { + "psr-4": { + "Spryker\\": "Spryker/", + "SprykerStrict\\": "SprykerStrict/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Spryker", + "homepage": "https://spryker.com" + } + ], + "description": "Spryker Code Sniffer Standards", + "homepage": "https://spryker.com", + "keywords": [ + "codesniffer", + "framework", + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/spryker/code-sniffer/issues", + "source": "https://github.com/spryker/code-sniffer" + }, + "time": "2023-01-03T16:08:22+00:00" + }, { "name": "squizlabs/php_codesniffer", "version": "3.7.2", @@ -3222,16 +3572,16 @@ }, { "name": "symfony/console", - "version": "v5.4.21", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9" + "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/c77433ddc6cdc689caf48065d9ea22ca0853fbd9", - "reference": "c77433ddc6cdc689caf48065d9ea22ca0853fbd9", + "url": "https://api.github.com/repos/symfony/console/zipball/3cd51fd2e6c461ca678f84d419461281bd87a0a8", + "reference": "3cd51fd2e6c461ca678f84d419461281bd87a0a8", "shasum": "" }, "require": { @@ -3296,12 +3646,12 @@ "homepage": "https://symfony.com", "keywords": [ "cli", - "command line", + "command-line", "console", "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.21" + "source": "https://github.com/symfony/console/tree/v5.4.22" }, "funding": [ { @@ -3317,7 +3667,7 @@ "type": "tidelift" } ], - "time": "2023-02-25T16:59:41+00:00" + "time": "2023-03-25T09:27:28+00:00" }, { "name": "symfony/css-selector", @@ -3473,25 +3823,25 @@ }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", + "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.0.2" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -3520,7 +3870,7 @@ "description": "A generic function and convention to trigger deprecation notices", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.2" }, "funding": [ { @@ -3536,7 +3886,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-01-02T09:55:41+00:00" }, { "name": "symfony/dom-crawler", @@ -3614,16 +3964,16 @@ }, { "name": "symfony/event-dispatcher", - "version": "v5.4.21", + "version": "v5.4.22", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "f0ae1383a8285dfc6752b8d8602790953118ff5a" + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/f0ae1383a8285dfc6752b8d8602790953118ff5a", - "reference": "f0ae1383a8285dfc6752b8d8602790953118ff5a", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/1df20e45d56da29a4b1d8259dd6e950acbf1b13f", + "reference": "1df20e45d56da29a4b1d8259dd6e950acbf1b13f", "shasum": "" }, "require": { @@ -3679,7 +4029,7 @@ "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.21" + "source": "https://github.com/symfony/event-dispatcher/tree/v5.4.22" }, "funding": [ { @@ -3695,24 +4045,24 @@ "type": "tidelift" } ], - "time": "2023-02-14T08:03:56+00:00" + "time": "2023-03-17T11:31:58+00:00" }, { "name": "symfony/event-dispatcher-contracts", - "version": "v2.5.2", + "version": "v3.0.2", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1" + "reference": "7bc61cc2db649b4637d331240c5346dcc7708051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/f98b54df6ad059855739db6fcbc2d36995283fe1", - "reference": "f98b54df6ad059855739db6fcbc2d36995283fe1", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7bc61cc2db649b4637d331240c5346dcc7708051", + "reference": "7bc61cc2db649b4637d331240c5346dcc7708051", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "psr/event-dispatcher": "^1" }, "suggest": { @@ -3721,7 +4071,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.0-dev" }, "thanks": { "name": "symfony/contracts", @@ -3758,7 +4108,7 @@ "standards" ], "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v2.5.2" + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.0.2" }, "funding": [ { @@ -3774,7 +4124,7 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2022-01-02T09:55:41+00:00" }, { "name": "symfony/filesystem", @@ -4659,34 +5009,33 @@ }, { "name": "symfony/string", - "version": "v5.4.21", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f" + "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/edac10d167b78b1d90f46a80320d632de0bd9f2f", - "reference": "edac10d167b78b1d90f46a80320d632de0bd9f2f", + "url": "https://api.github.com/repos/symfony/string/zipball/d9e72497367c23e08bf94176d2be45b00a9d232a", + "reference": "d9e72497367c23e08bf94176d2be45b00a9d232a", "shasum": "" }, "require": { - "php": ">=7.2.5", + "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-intl-grapheme": "~1.0", "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "~1.15" + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "symfony/translation-contracts": ">=3.0" + "symfony/translation-contracts": "<2.0" }, "require-dev": { - "symfony/error-handler": "^4.4|^5.0|^6.0", - "symfony/http-client": "^4.4|^5.0|^6.0", - "symfony/translation-contracts": "^1.1|^2", - "symfony/var-exporter": "^4.4|^5.0|^6.0" + "symfony/error-handler": "^5.4|^6.0", + "symfony/http-client": "^5.4|^6.0", + "symfony/translation-contracts": "^2.0|^3.0", + "symfony/var-exporter": "^5.4|^6.0" }, "type": "library", "autoload": { @@ -4725,7 +5074,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.21" + "source": "https://github.com/symfony/string/tree/v6.0.19" }, "funding": [ { @@ -4741,7 +5090,7 @@ "type": "tidelift" } ], - "time": "2023-02-22T08:00:55+00:00" + "time": "2023-01-01T08:36:10+00:00" }, { "name": "symfony/translation", @@ -4912,28 +5261,27 @@ }, { "name": "symfony/yaml", - "version": "v5.4.21", + "version": "v6.0.19", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "3713e20d93e46e681e51605d213027e48dab3469" + "reference": "deec3a812a0305a50db8ae689b183f43d915c884" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/3713e20d93e46e681e51605d213027e48dab3469", - "reference": "3713e20d93e46e681e51605d213027e48dab3469", + "url": "https://api.github.com/repos/symfony/yaml/zipball/deec3a812a0305a50db8ae689b183f43d915c884", + "reference": "deec3a812a0305a50db8ae689b183f43d915c884", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.0.2", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.3" + "symfony/console": "<5.4" }, "require-dev": { - "symfony/console": "^5.3|^6.0" + "symfony/console": "^5.4|^6.0" }, "suggest": { "symfony/console": "For validating YAML files using the lint command" @@ -4967,7 +5315,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.21" + "source": "https://github.com/symfony/yaml/tree/v6.0.19" }, "funding": [ { @@ -4983,7 +5331,7 @@ "type": "tidelift" } ], - "time": "2023-02-21T19:46:44+00:00" + "time": "2023-01-11T11:50:03+00:00" }, { "name": "theseer/tokenizer", @@ -5037,36 +5385,31 @@ }, { "name": "wp-coding-standards/wpcs", - "version": "dev-develop", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "f4d4ff58ddfe1ca79575e60c552543966a5ed7b2" + "reference": "7da1894633f168fe244afc6de00d141f27517b62" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/f4d4ff58ddfe1ca79575e60c552543966a5ed7b2", - "reference": "f4d4ff58ddfe1ca79575e60c552543966a5ed7b2", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", + "reference": "7da1894633f168fe244afc6de00d141f27517b62", "shasum": "" }, "require": { - "ext-filter": "*", "php": ">=5.4", - "phpcsstandards/phpcsextra": "^1.0", - "phpcsstandards/phpcsutils": "^1.0", - "squizlabs/php_codesniffer": "^3.7.1" + "squizlabs/php_codesniffer": "^3.3.1" }, "require-dev": { - "php-parallel-lint/php-console-highlighter": "^1.0.0", - "php-parallel-lint/php-parallel-lint": "^1.3.2", + "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.2.0", + "phpcsstandards/phpcsdevtools": "^1.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { - "ext-mbstring": "For improved results" + "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." }, - "default-branch": true, "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", "license": [ @@ -5082,7 +5425,6 @@ "keywords": [ "phpcs", "standards", - "static analysis", "wordpress" ], "support": { @@ -5090,20 +5432,20 @@ "source": "https://github.com/WordPress/WordPress-Coding-Standards", "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" }, - "time": "2023-03-07T17:51:30+00:00" + "time": "2020-05-13T23:57:56+00:00" }, { "name": "yoast/phpunit-polyfills", - "version": "1.0.4", + "version": "1.0.5", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "3c621ff5429d2b1ff96dc5808ad6cde99d31ea4c" + "reference": "3b59adeef77fb1c03ff5381dbb9d68b0aaff3171" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/3c621ff5429d2b1ff96dc5808ad6cde99d31ea4c", - "reference": "3c621ff5429d2b1ff96dc5808ad6cde99d31ea4c", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/3b59adeef77fb1c03ff5381dbb9d68b0aaff3171", + "reference": "3b59adeef77fb1c03ff5381dbb9d68b0aaff3171", "shasum": "" }, "require": { @@ -5111,13 +5453,12 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.2.1" + "yoast/yoastcs": "^2.3.0" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "1.x-dev", - "dev-develop": "1.x-dev" + "dev-main": "2.x-dev" } }, "autoload": { @@ -5151,21 +5492,13 @@ "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2022-11-16T09:07:52+00:00" - } - ], - "aliases": [ - { - "package": "wp-coding-standards/wpcs", - "version": "dev-develop", - "alias": "2.3.1", - "alias_normalized": "2.3.1.0" + "time": "2023-03-30T23:39:05+00:00" } ], + "aliases": [], "minimum-stability": "stable", "stability-flags": { - "pantheon-systems/pantheon-wordpress-upstream-tests": 20, - "wp-coding-standards/wpcs": 20 + "pantheon-systems/pantheon-wordpress-upstream-tests": 20 }, "prefer-stable": false, "prefer-lowest": false, diff --git a/inc/class-cli.php b/inc/class-cli.php index 3658f13a..8c3433d8 100644 --- a/inc/class-cli.php +++ b/inc/class-cli.php @@ -3,6 +3,12 @@ * WP-CLI commands for managing the Pantheon Advanced Page Cache. * * @package Pantheon_Advanced_Page_Cache + * + * This file handles the PAPC WP-CLI commands. WP-CLI uses docblocks + * to define functionality. As such, we are disabling the sniffs that + * warn about missing parameter tags. + * + * @phpcs:disable Squiz.Commenting.FunctionComment.MissingParamTag */ namespace Pantheon_Advanced_Page_Cache; @@ -13,7 +19,6 @@ * Manage the Pantheon Advanced Page Cache. */ class CLI { - /** * Purge one or more surrogate keys from cache. * diff --git a/inc/class-emitter.php b/inc/class-emitter.php index f487bbce..a9ba5949 100644 --- a/inc/class-emitter.php +++ b/inc/class-emitter.php @@ -3,6 +3,20 @@ * Generates and emits surrogate keys based on the current request. * * @package Pantheon_Advanced_Page_Cache + * + * This file handles the PAPC surrogate key emitter. Surrogate keys are added to + * response headers and make use of HTTP response APIs. There are a few + * occasions where we are using functions that include a $response parameter, + * but we are not using it. We are disabling the sniffs that warn about unused + * parameters because the functions that are being hooked into might expect + * those parameters to exist. + * @phpcs:disable VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + * + * This file also handles surrogate keys for GraphQL requests. The GraphQL + * API uses a different naming convention for its variables than the REST API + * and values might come back in camelCase instead of snake_case. We are + * disabling the sniff that warns about this. + * @phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase */ namespace Pantheon_Advanced_Page_Cache; @@ -11,7 +25,6 @@ * Generates and emits surrogate keys based on the current request. */ class Emitter { - /** * Current instance when set. * @@ -24,21 +37,21 @@ class Emitter { * * @var array */ - private $rest_api_surrogate_keys = array(); + private $rest_api_surrogate_keys = []; /** * GraphQL surrogate keys to emit. * * @var array */ - private $graphql_surrogate_keys = array(); + private $graphql_surrogate_keys = []; /** * REST API collection endpoints. * * @var array */ - private $rest_api_collection_endpoints = array(); + private $rest_api_collection_endpoints = []; /** * Header key. @@ -70,12 +83,9 @@ private static function get_instance() { * Render surrogate keys after the main query has run */ public static function action_wp() { - $keys = self::get_main_query_surrogate_keys(); if ( ! empty( $keys ) ) { - // @codingStandardsIgnoreStart - @header( self::HEADER_KEY . ': ' . implode( ' ', $keys ) ); - // @codingStandardsIgnoreEnd + @header( self::HEADER_KEY . ': ' . implode( ' ', $keys ) ); // phpcs:ignore } } @@ -83,30 +93,20 @@ public static function action_wp() { * Register filters to sniff surrogate keys out of REST API responses. */ public static function action_rest_api_init() { - foreach ( get_post_types( - array( - 'show_in_rest' => true, - ), - 'objects' - ) as $post_type ) { - add_filter( "rest_prepare_{$post_type->name}", array( __CLASS__, 'filter_rest_prepare_post' ), 10, 3 ); + foreach ( get_post_types( [ 'show_in_rest' => true ], 'objects' ) as $post_type ) { + add_filter( "rest_prepare_{$post_type->name}", [ __CLASS__, 'filter_rest_prepare_post' ], 10, 3 ); $base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; self::get_instance()->rest_api_collection_endpoints[ '/wp/v2/' . $base ] = $post_type->name; } - foreach ( get_taxonomies( - array( - 'show_in_rest' => true, - ), - 'objects' - ) as $taxonomy ) { - add_filter( "rest_prepare_{$taxonomy->name}", array( __CLASS__, 'filter_rest_prepare_term' ), 10, 3 ); + foreach ( get_taxonomies( [ 'show_in_rest' => true ], 'objects' ) as $taxonomy ) { + add_filter( "rest_prepare_{$taxonomy->name}", [ __CLASS__, 'filter_rest_prepare_term' ], 10, 3 ); $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; self::get_instance()->rest_api_collection_endpoints[ '/wp/v2/' . $base ] = $taxonomy->name; } - add_filter( 'rest_prepare_comment', array( __CLASS__, 'filter_rest_prepare_comment' ), 10, 3 ); + add_filter( 'rest_prepare_comment', [ __CLASS__, 'filter_rest_prepare_comment' ], 10, 3 ); self::get_instance()->rest_api_collection_endpoints['/wp/v2/comments'] = 'comment'; - add_filter( 'rest_prepare_user', array( __CLASS__, 'filter_rest_prepare_user' ), 10, 3 ); - add_filter( 'rest_pre_get_setting', array( __CLASS__, 'filter_rest_pre_get_setting' ), 10, 2 ); + add_filter( 'rest_prepare_user', [ __CLASS__, 'filter_rest_prepare_user' ], 10, 3 ); + add_filter( 'rest_pre_get_setting', [ __CLASS__, 'filter_rest_pre_get_setting' ], 10, 2 ); self::get_instance()->rest_api_collection_endpoints['/wp/v2/users'] = 'user'; } @@ -131,7 +131,6 @@ public static function filter_rest_pre_dispatch( $result, $server, $request ) { * @param WP_REST_Server $server Server instance. */ public static function filter_rest_post_dispatch( $result, $server ) { - $keys = self::get_rest_api_surrogate_keys(); if ( ! empty( $keys ) ) { $server->send_header( self::HEADER_KEY, implode( ' ', $keys ) ); @@ -211,7 +210,7 @@ public static function filter_rest_pre_get_setting( $result, $name ) { public static function get_main_query_surrogate_keys() { global $wp_query; - $keys = array(); + $keys = []; if ( is_front_page() ) { $keys[] = 'front'; } @@ -282,7 +281,7 @@ public static function get_main_query_surrogate_keys() { // Don't emit surrogate keys in the admin, unless defined by the filter. if ( is_admin() ) { - $keys = array(); + $keys = []; } /** @@ -323,7 +322,7 @@ public static function get_rest_api_surrogate_keys() { * Reset surrogate keys stored on the instance. */ public static function reset_rest_api_surrogate_keys() { - self::get_instance()->rest_api_surrogate_keys = array(); + self::get_instance()->rest_api_surrogate_keys = []; } /** @@ -339,7 +338,7 @@ public static function filter_huge_surrogate_keys_list( $keys ) { return $keys; } - $keycats = array(); + $keycats = []; foreach ( $keys as $k ) { $p = strrpos( $k, '-' ); if ( false === $p ) { @@ -365,8 +364,8 @@ function( $a, $b ) { $cats = array_keys( $keycats ); foreach ( $cats as $c ) { - $keycats[ $c ] = array( $c . 'huge' ); - $keyout = array(); + $keycats[ $c ] = [ $c . 'huge' ]; + $keyout = []; foreach ( $keycats as $v ) { $keyout = array_merge( $keyout, $v ); } @@ -393,10 +392,8 @@ public static function filter_graphql_dataloader_get_model( $model ) { $class_short_name = $reflect->getShortName(); $surrogate_key_prefix = strtolower( $class_short_name ); if ( isset( $model->id ) ) { - // @codingStandardsIgnoreStart - if (!empty($model->databaseId)) { + if ( ! empty( $model->databaseId ) ) { self::get_instance()->graphql_surrogate_keys[] = $surrogate_key_prefix . '-' . $model->databaseId; - // @codingStandardsIgnoreEnd } } return $model; diff --git a/inc/class-purger.php b/inc/class-purger.php index c7a49e03..bd595cc4 100644 --- a/inc/class-purger.php +++ b/inc/class-purger.php @@ -11,7 +11,6 @@ * Purges the appropriate surrogate key based on the event. */ class Purger { - /** * Purge surrogate keys associated with a post being updated. * @@ -70,12 +69,12 @@ public static function action_clean_post_cache( $post_id ) { if ( $type && 'revision' === $type ) { return; } - $keys = array( + $keys = [ 'post-' . $post_id, 'rest-post-' . $post_id, 'post-huge', 'rest-post-huge', - ); + ]; /** * Surrogate keys purged when clearing post cache. * @@ -95,9 +94,7 @@ public static function action_clean_post_cache( $post_id ) { */ public static function action_created_term( $term_id, $tt_id, $taxonomy ) { self::purge_term( $term_id ); - $keys = array( - 'rest-' . $taxonomy . '-collection', - ); + $keys = [ 'rest-' . $taxonomy . '-collection' ]; /** * Surrogate keys purged when creating a new term. * @@ -134,8 +131,8 @@ public static function action_delete_term( $term_id ) { * @param integer $term_ids One or more IDs of modified terms. */ public static function action_clean_term_cache( $term_ids ) { - $keys = array(); - $term_ids = is_array( $term_ids ) ? $term_ids : array( $term_ids ); + $keys = []; + $term_ids = is_array( $term_ids ) ? $term_ids : [ $term_ids ]; foreach ( $term_ids as $term_id ) { $keys[] = 'term-' . $term_id; $keys[] = 'rest-term-' . $term_id; @@ -162,11 +159,11 @@ public static function action_wp_insert_comment( $id, $comment ) { if ( 1 !== (int) $comment->comment_approved ) { return; } - $keys = array( + $keys = [ 'rest-comment-' . $comment->comment_ID, 'rest-comment-collection', 'rest-comment-huge', - ); + ]; /** * Surrogate keys purged when inserting a new comment. * @@ -186,11 +183,11 @@ public static function action_wp_insert_comment( $id, $comment ) { * @param object $comment The comment data. */ public static function action_transition_comment_status( $new_status, $old_status, $comment ) { - $keys = array( + $keys = [ 'rest-comment-' . $comment->comment_ID, 'rest-comment-collection', 'rest-comment-huge', - ); + ]; /** * Surrogate keys purged when transitioning a comment status. * @@ -209,10 +206,10 @@ public static function action_transition_comment_status( $new_status, $old_statu * @param integer $comment_id Modified comment id. */ public static function action_clean_comment_cache( $comment_id ) { - $keys = array( + $keys = [ 'rest-comment-' . $comment_id, 'rest-comment-huge', - ); + ]; /** * Surrogate keys purged when cleaning comment cache. * @@ -233,14 +230,14 @@ private static function purge_post_with_related( $post ) { if ( 'revision' === $post->post_type ) { return; } - $keys = array( + $keys = [ 'home', 'front', '404', 'feed', 'post-' . $post->ID, 'post-huge', - ); + ]; $keys[] = 'rest-' . $post->post_type . '-collection'; if ( post_type_supports( $post->post_type, 'author' ) ) { $keys[] = 'user-' . $post->post_author; @@ -252,9 +249,7 @@ private static function purge_post_with_related( $post ) { } $taxonomies = wp_list_filter( get_object_taxonomies( $post->post_type, 'objects' ), - array( - 'public' => true, - ) + [ 'public' => true ] ); foreach ( $taxonomies as $taxonomy ) { $terms = get_the_terms( $post, $taxonomy->name ); @@ -281,14 +276,14 @@ private static function purge_post_with_related( $post ) { * @param integer $term_id ID for the modified term. */ private static function purge_term( $term_id ) { - $keys = array( + $keys = [ 'term-' . $term_id, 'rest-term-' . $term_id, 'post-term-' . $term_id, 'term-huge', 'rest-term-huge', 'post-term-huge', - ); + ]; /** * Surrogate keys purged when purging a term. * @@ -306,12 +301,12 @@ private static function purge_term( $term_id ) { * @param integer $user_id ID for the modified user. */ public static function action_clean_user_cache( $user_id ) { - $keys = array( + $keys = [ 'user-' . $user_id, 'rest-user-' . $user_id, 'user-huge', 'rest-user-huge', - ); + ]; /** * Surrogate keys purged when clearing user cache. * @@ -336,10 +331,10 @@ public static function action_updated_option( $option ) { return; } $rest_name = ! empty( $settings[ $option ]['show_in_rest']['name'] ) ? $settings[ $option ]['show_in_rest']['name'] : $option; - $keys = array( + $keys = [ 'rest-setting-' . $rest_name, 'rest-setting-huge', - ); + ]; /** * Surrogate keys purged when updating an option cache. * diff --git a/inc/class-user-interface.php b/inc/class-user-interface.php index 692329b7..e22a60cd 100644 --- a/inc/class-user-interface.php +++ b/inc/class-user-interface.php @@ -11,7 +11,6 @@ * Controller for a variety of admin UI. */ class User_Interface { - /** * Register a toolbar button to purge the cache for the current page. * @@ -22,41 +21,42 @@ public static function action_admin_bar_menu( $wp_admin_bar ) { return; } - if ( ! empty( $_GET['message'] ) && 'pantheon-cleared-url-cache' === $_GET['message'] ) { + // Todo: Maybe add nonce check here. + if ( ! empty( $_GET['message'] ) && 'pantheon-cleared-url-cache' === $_GET['message'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $title = esc_html__( 'URL Cache Cleared', 'pantheon-advanced-page-cache' ); } else { $title = esc_html__( 'Clear URL Cache', 'pantheon-advanced-page-cache' ); } - $wp_admin_bar->add_menu( - array( - 'parent' => '', - 'id' => 'clear-page-cache', - 'title' => $title, - 'meta' => array( - 'title' => __( 'Delete cache of the current URL.', 'pantheon-advanced-page-cache' ), - ), - 'href' => wp_nonce_url( admin_url( 'admin-ajax.php?action=pantheon_clear_url_cache&path=' . rawurlencode( preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $_SERVER['REQUEST_URI'] ) ) ), 'clear-url-cache' ), - ) - ); + $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( $_SERVER['REQUEST_URI'] ) : ''; + $wp_admin_bar->add_menu( [ + 'parent' => '', + 'id' => 'clear-page-cache', + 'title' => $title, + 'meta' => [ + 'title' => __( 'Delete cache of the current URL.', 'pantheon-advanced-page-cache' ), + ], + 'href' => wp_nonce_url( admin_url( 'admin-ajax.php?action=pantheon_clear_url_cache&path=' . rawurlencode( preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $request_uri ) ) ), 'clear-url-cache' ), + ] ); } /** * Handle an admin-ajax request to clear the URL cache. */ public static function handle_ajax_clear_url_cache() { - - if ( empty( $_GET['_wpnonce'] ) - || ! wp_verify_nonce( $_GET['_wpnonce'], 'clear-url-cache' ) + $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( $_GET['_wpnonce'] ) : ''; + if ( empty( $nonce ) + || ! wp_verify_nonce( $nonce, 'clear-url-cache' ) || ! current_user_can( 'delete_others_posts' ) ) { wp_die( esc_html__( "You shouldn't be doing this.", 'pantheon-advanced-page-cache' ) ); } - $ret = pantheon_wp_clear_edge_paths( array( $_GET['path'] ) ); + $path = isset( $_GET['path'] ) ? sanitize_text_field( $_GET['path'] ) : ''; + $ret = pantheon_wp_clear_edge_paths( [ $path ] ); if ( is_wp_error( $ret ) ) { wp_die( wp_kses_post( $ret->get_error_message() ) ); } - wp_safe_redirect( add_query_arg( 'message', 'pantheon-cleared-url-cache', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $_GET['path'] ) ) ); + wp_safe_redirect( add_query_arg( 'message', 'pantheon-cleared-url-cache', preg_replace( '/[ <>\'\"\r\n\t\(\)]/', '', $path ) ) ); exit; } } diff --git a/pantheon-advanced-page-cache.php b/pantheon-advanced-page-cache.php index 60c0a7d0..b94ab61d 100644 --- a/pantheon-advanced-page-cache.php +++ b/pantheon-advanced-page-cache.php @@ -7,7 +7,7 @@ * Author URI: https://pantheon.io * Text Domain: pantheon-advanced-page-cache * Domain Path: /languages - * Version: 1.2.2 + * Version: 1.2.3 * * @package Pantheon_Advanced_Page_Cache */ @@ -18,7 +18,6 @@ * @param array $keys Surrogate keys to purge. */ function pantheon_wp_clear_edge_keys( $keys ) { - /** * Fires when purging specific surrogate keys. * @@ -42,7 +41,6 @@ function pantheon_wp_clear_edge_keys( $keys ) { * @param array $paths URI paths to purge. */ function pantheon_wp_clear_edge_paths( $paths ) { - /** * Fires when purging specific URI paths. * @@ -64,7 +62,6 @@ function pantheon_wp_clear_edge_paths( $paths ) { * Purge the entire cache. */ function pantheon_wp_clear_edge_all() { - /** * Fires when purging the entire cache. */ @@ -97,7 +94,7 @@ function( $class_autoloader ) { $parts[] = $last; $file = __DIR__ . '/inc/' . str_replace( '_', '-', strtolower( implode( '/', $parts ) ) ); if ( file_exists( $file ) ) { - require $file; + require $file; // phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable } } ); @@ -105,37 +102,37 @@ function( $class_autoloader ) { /** * Registers relevant UI */ -add_action( 'admin_bar_menu', array( 'Pantheon_Advanced_Page_Cache\User_Interface', 'action_admin_bar_menu' ), 99 ); // End of the stack. -add_action( 'wp_ajax_pantheon_clear_url_cache', array( 'Pantheon_Advanced_Page_Cache\User_Interface', 'handle_ajax_clear_url_cache' ) ); +add_action( 'admin_bar_menu', [ 'Pantheon_Advanced_Page_Cache\User_Interface', 'action_admin_bar_menu' ], 99 ); // End of the stack. +add_action( 'wp_ajax_pantheon_clear_url_cache', [ 'Pantheon_Advanced_Page_Cache\User_Interface', 'handle_ajax_clear_url_cache' ] ); /** * Emits the appropriate surrogate tags per view. */ -add_filter( 'wp', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'action_wp' ) ); -add_action( 'rest_api_init', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'action_rest_api_init' ) ); -add_filter( 'rest_pre_dispatch', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_rest_pre_dispatch' ), 10, 3 ); -add_filter( 'rest_post_dispatch', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_rest_post_dispatch' ), 10, 2 ); +add_filter( 'wp', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'action_wp' ] ); +add_action( 'rest_api_init', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'action_rest_api_init' ] ); +add_filter( 'rest_pre_dispatch', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_rest_pre_dispatch' ], 10, 3 ); +add_filter( 'rest_post_dispatch', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_rest_post_dispatch' ], 10, 2 ); -add_filter( 'graphql_dataloader_get_model', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_graphql_dataloader_get_model' ) ); -add_filter( 'graphql_response_headers_to_send', array( 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_graphql_response_headers_to_send' ) ); +add_filter( 'graphql_dataloader_get_model', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_graphql_dataloader_get_model' ] ); +add_filter( 'graphql_response_headers_to_send', [ 'Pantheon_Advanced_Page_Cache\Emitter', 'filter_graphql_response_headers_to_send' ] ); /** * Clears surrogate tags when various modification behaviors are performed. */ -add_action( 'wp_insert_post', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_wp_insert_post' ), 10, 2 ); -add_action( 'transition_post_status', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_transition_post_status' ), 10, 3 ); -add_action( 'before_delete_post', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_before_delete_post' ) ); -add_action( 'delete_attachment', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_delete_attachment' ) ); -add_action( 'clean_post_cache', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_post_cache' ) ); -add_action( 'created_term', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_created_term' ), 10, 3 ); -add_action( 'edited_term', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_edited_term' ) ); -add_action( 'delete_term', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_delete_term' ) ); -add_action( 'clean_term_cache', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_term_cache' ) ); -add_action( 'wp_insert_comment', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_wp_insert_comment' ), 10, 2 ); -add_action( 'transition_comment_status', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_transition_comment_status' ), 10, 3 ); -add_action( 'clean_comment_cache', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_comment_cache' ) ); -add_action( 'clean_user_cache', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_user_cache' ) ); -add_action( 'updated_option', array( 'Pantheon_Advanced_Page_Cache\Purger', 'action_updated_option' ) ); +add_action( 'wp_insert_post', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_wp_insert_post' ], 10, 2 ); +add_action( 'transition_post_status', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_transition_post_status' ], 10, 3 ); +add_action( 'before_delete_post', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_before_delete_post' ] ); +add_action( 'delete_attachment', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_delete_attachment' ] ); +add_action( 'clean_post_cache', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_post_cache' ] ); +add_action( 'created_term', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_created_term' ], 10, 3 ); +add_action( 'edited_term', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_edited_term' ] ); +add_action( 'delete_term', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_delete_term' ] ); +add_action( 'clean_term_cache', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_term_cache' ] ); +add_action( 'wp_insert_comment', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_wp_insert_comment' ], 10, 2 ); +add_action( 'transition_comment_status', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_transition_comment_status' ], 10, 3 ); +add_action( 'clean_comment_cache', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_comment_cache' ] ); +add_action( 'clean_user_cache', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_clean_user_cache' ] ); +add_action( 'updated_option', [ 'Pantheon_Advanced_Page_Cache\Purger', 'action_updated_option' ] ); /** * Registers the WP-CLI commands. diff --git a/readme.txt b/readme.txt index 6e5db6b1..52cb4b83 100644 --- a/readme.txt +++ b/readme.txt @@ -1,356 +1,362 @@ -=== Pantheon Advanced Page Cache === -Contributors: getpantheon, danielbachhuber, kporras07 -Tags: pantheon, cdn, cache -Requires at least: 4.7 -Tested up to: 6.1 -Stable tag: 1.2.2 -License: GPLv2 or later -License URI: http://www.gnu.org/licenses/gpl-2.0.html - -Automatically clear related pages from Pantheon's Edge when you update content. High TTL. Fresh content. Visitors never wait. - -== Description == - -[![CircleCI](https://circleci.com/gh/pantheon-systems/pantheon-advanced-page-cache.svg?style=svg)](https://circleci.com/gh/pantheon-systems/pantheon-advanced-page-cache) - -For sites wanting fine-grained control over how their responses are represented in their edge cache, Pantheon Advanced Page Cache is the golden ticket. Here's a high-level overview of how the plugin works: - -1. When a response is generated, the plugin uses surrogate keys based on WordPress' main `WP_Query` object to "tag" the response with identifers for the data used in the response. See the "Adding Custom Keys" section for including your own surrogate keys. -2. When WordPress data is modified, the plugin triggers a purge request for the data's corresponding surrogate keys. - -Because of its surrogate key technology, Pantheon Advanced Page Cache empowers WordPress sites with a significantly more accurate cache purge mechanism, and generally higher cache hit rate. It even works with the WordPress REST API. - -Go forth and make awesome! And, once you've built something great, [send us feature requests (or bug reports)](https://github.com/pantheon-systems/pantheon-advanced-page-cache/issues). - -== Installation == - -To install Pantheon Advanced Page Cache, follow these steps: - -1. Install the plugin from WordPress.org using the WordPress dashboard. -2. Activate the plugin. - -To install Pantheon Advanced Page Cache in one line with WP-CLI: - - wp plugin install pantheon-advanced-page-cache --activate - -== How It Works == - -Pantheon Advanced Page Cache makes heavy use of surrogate keys, which enable responses to be "tagged" with identifiers that can then later be used in purge requests. For instance, a home page response might include the `Surrogate-Key` header with these keys: - - Surrogate-Key: front home post-43 user-4 post-41 post-9 post-7 post-1 user-1 - -Similarly, a `GET` requests to `/wp-json/wp/v2/posts` might include the `Surrogate-Key` header with these keys: - - Surrogate-Key: rest-post-collection rest-post-43 rest-post-43 rest-post-9 rest-post-7 rest-post-1 - -Because cached responses include metadata describing the data therein, surrogate keys enable more flexible purging behavior like: - -* When a post is updated, clear the cache for the post's URL, the homepage, any index view the post appears on, and any REST API endpoints the post is present in. -* When an author changes their name, clear the cache for the author's archive and any post they've authored. - -There is a limit to the number of surrogate keys in a response, so we've optimized them based on a user's expectation of a normal WordPress site. See the "Emitted Keys" section for full details on which keys are included, and the "Adding Custom Keys" section following for information on how to add your own. - -= Adding Custom Keys = - -By default, Pantheon Advanced Page Cache generates surrogate keys based on an interpretation of the main `WP_Query` query object. Because WordPress sends headers before the page is rendered, you need to use the `pantheon_wp_main_query_surrogate_keys` filter to include additional surrogate keys for any data present on the page. - -For example, to include surrogate keys for a sidebar rendered on the homepage, you can filter the keys using the `is_home()` template tag: - - /** - * Add surrogate key for the featured content sidebar rendered on the homepage. - */ - add_filter( 'pantheon_wp_main_query_surrogate_keys', function( $keys ){ - if ( is_home() ) { - $keys[] = 'sidebar-home-featured'; - } - return $keys; - }); - -Then, when sidebars are updated, you can use the `pantheon_wp_clear_edge_keys()` helper function to emit a purge event specific to the surrogate key: - - /** - * Trigger a purge event for the featured content sidebar when widgets are updated. - */ - add_action( 'update_option_sidebars_widgets', function() { - pantheon_wp_clear_edge_keys( array( 'sidebar-home-featured' ) ); - }); - -Similarly, to include surrogate keys for posts queried on the homepage, you can pre-fetch the posts before the page is rendered: - - /** - * An example of pre-fetching a WP_Query to tag the - * response with queried data. You'd use `papcx_wp_query()` - * a second time within your template to use the data. - */ - add_filter( 'pantheon_wp_main_query_surrogate_keys', function( $keys ) { - if ( is_home() ) { - $query = papcx_wp_query( array( - 'post_type' => 'page', - ) ); - foreach( $query->posts as $post ) { - $keys[] = 'post-' . $post->ID; - } - } - return $keys; - }); - - /** - * Register a 'papc-non-persistent' cache group to cache data - * in a non-persistent manner. We only want data in this group - * to be cached within the page request. - */ - add_action( 'init', function(){ - wp_cache_add_non_persistent_groups( array( 'papc-non-persistent' ) ); - }); - - /** - * Helper function to instantiate a WP_Query object only - * once per page request. - * - * @param array $args Arguments to pass to WP_Query. - * @return WP_Query - */ - function papcx_wp_query( $args = array() ) { - $cache_key = md5( serialize( $args ) ); - // WP_Query object will be in cache the second time we use the function. - $cache_value = wp_cache_get( $cache_key, 'papc-non-persistent' ); - if ( false !== $cache_value ) { - return $cache_value; - } - $query = new WP_Query( $args ); - wp_cache_set( $cache_key, $query, 'papc-non-persistent' ); - return $query; - } - -Because Pantheon Advanced Page Cache already handles WordPress post purge events, there's no additional call to `pantheon_wp_clear_edge_keys()`. - -Lastly, the `pantheon_wp_rest_api_surrogate_keys` filter lets you filter surrogate keys present in a REST API response. - -Need a bit more power? In addition to `pantheon_wp_clear_edge_keys()`, there are two additional helper functions you can use: - -* `pantheon_wp_clear_edge_paths( $paths = array() )` - Purge cache for one or more paths. -* `pantheon_wp_clear_edge_all()` - Warning! With great power comes great responsibility. Purge the entire cache, but do so wisely. - -== WP-CLI Commands == - -This plugin implements a variety of [WP-CLI](https://wp-cli.org) commands. All commands are grouped into the `wp pantheon cache` namespace. - - $ wp help pantheon cache - - NAME - - wp pantheon cache - - DESCRIPTION - - Manage the Pantheon Advanced Page Cache. - - SYNOPSIS - - wp pantheon cache - - SUBCOMMANDS - - purge-all Purge the entire page cache. - purge-key Purge one or more surrogate keys from cache. - purge-path Purge one or more paths from cache. - -Use `wp help pantheon cache ` to learn more about each command. - -== Debugging == - -By default, Pantheon's infrastructure strips out the `Surrogate-Key` response header before responses are served to clients. The contents of this header can be viewed as `Surrogate-Key-Raw` by adding on a debugging header to the request. - -A direct way of inspecting headers is with `curl -I`. This command will make a request and show just the response headers. Adding `-H "Pantheon-Debug:1"` will result in `Surrogate-Key-Raw` being included in the response headers. The complete command looks like this: - - curl -IH "Pantheon-Debug:1" https://scalewp.io/ - -Piping to `grep` will filter the output down to just the `Surrogate-Key-Raw` header: - - curl -IH "Pantheon-Debug:1" https://scalewp.io/ | grep -i Surrogate-Key-Raw - -Tada! - -== Emitted Keys and Purge Events = - -= Emitted Keys on Traditional Views = - -**Home `/`** - -* Emits surrogate keys: `home`, `front`, `post-` (all posts in main query) - -**Single post `/2016/10/14/surrogate-keys/`** - -* Emits surrogate keys: `single`, `post-`, `post-user-`, `post-term-` (all terms assigned to post) - -**Author archive `/author/pantheon/`** - -* Emits surrogate keys: `archive`, `user-`, `post-` (all posts in main query) - -**Term archive `/tag/cdn/`** - -* Emits surrogate keys: `archive`, `term-`, `post-` (all posts in main query) - -**Day archive `/2016/10/14/`** - -* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) - -**Month archive `/2016/10/`** - -* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) - -**Year archive `/2016/`** - -* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) - -**Search `/?s=`** - -* Emits surrogate keys: `search`, either `search-results` or `search-no-results`, `post-` (all posts in main query) - -**Not found (404)** - -* Emits surrogate keys: `404` - -= Emitted Keys on REST API Endpoints = - -**Posts** - -* `/wp-json/wp/v2/posts` emits surrogate keys: `rest-post-collection`, `rest-post-` -* `/wp-json/wp/v2/posts/` emits surrogate keys: `rest-post-` - -**Pages** - -* `/wp-json/wp/v2/pages` emits surrogate keys: `rest-page-collection`, `rest-post-` -* `/wp-json/wp/v2/pages/` emits surrogate keys: `rest-post-` - -**Categories** - -* `/wp-json/wp/v2/categories` emits surrogate keys: `rest-category-collection`, `rest-term-` -* `/wp-json/wp/v2/categories/` emits surrogate keys: `rest-term-` - -**Tags** - -* `/wp-json/wp/v2/tags` emits surrogate keys: `rest-post_tag-collection`, `rest-term-` -* `/wp-json/wp/v2/tags/` emits surrogate keys: `rest-term-` - -**Comments** - -* `/wp-json/wp/v2/comments` emits surrogate keys: `rest-comment-collection`, `rest-comment-post-`, `rest-comment-` -* `/wp-json/wp/v2/comments/` emits surrogate keys: `rest-comment-post-`, `rest-comment-` - -**Users** - -* `/wp-json/wp/v2/users` emits surrogate keys: `rest-user-collection`, `rest-user-` -* `/wp-json/wp/v2/users/` emits surrogate keys: `rest-user-` - -**Settings** - -* `/wp-json/wp/v2/settings` emits surrogate keys: `rest-setting-` - -= Purge Events = - -Different WordPress actions cause different surrogate keys to be purged, documented here. - -**wp_insert_post / transition_post_status / before_delete_post / delete_attachment** - -* Purges surrogate keys: `home`, `front`, `404`, `post-`, `user-`, `term-`, `rest--collection`, `rest-comment-post-` -* Affected views: homepage, single post, any page with 404 header, any archive where post displays, author archive, term archive, REST API collection and resource endpoints - -**clean_post_cache** - -* Purges surrogate keys: `post-`, `rest-post-` -* Affected views: single post, REST API resource endpoint - -**created_term / edited_term / delete_term** - -* Purges surrogate keys: `term-`, `post-term-`, `rest--collection` -* Affected views: term archive, any post where the term is assigned, REST API collection and resource endpoints - -**clean_term_cache** - -* Purges surrogate keys: `term-`, `rest-term-` -* Affected views: term archive, REST API resource endpoint - -**wp_insert_comment / transition_comment_status** - -* Purges surrogate keys: `rest-comment-collection`, `rest-comment-` -* Affected views: REST API collection and resource endpoints - -**clean_comment_cache** - -* Purges surrogate keys: `rest-comment-` -* Affected views: REST API resource endpoint - -**clean_user_cache** - -* Purges surrogate keys: `user-`, `rest-user-` -* Affected views: author archive, any post where the user is the author - -**updated_option** - -* Purges surrogate keys: `rest-setting-` -* Affected views: REST API resource endpoint - -## Plugin Integrations ## - -Pantheon Advanced Page Cache integrates with WordPress plugins, including: - -* [WPGraphQL](https://wordpress.org/plugins/wp-graphql/) - -== Contributing == - -See [CONTRIBUTING.md](https://github.com/pantheon-systems/wp-saml-auth/blob/master/CONTRIBUTING.md) for information on contributing. - -== Changelog == - -= 1.2.2 (March 14, 2023) = -* Adds PHP 8.2 compatibility [[#218](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/218)]. -* Bump dependencies [[#204](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/204)]. - -= 1.2.1 (February 23, 2023) = -* Handle models that are not instances of the `WPGraphQL\Model\Model` class [[#212](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/212)]. -* Make dependabot target develop branch [[#209](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/209)]. -* Bump dependencies [[#210](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/210)] [[#214](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/214)]. - -= 1.2.0 (November 29, 2022) = -* Adds Github Actions for building tag and deploying to wp.org. Add CONTRIBUTING.md. [[#203](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/203)] - -= 1.1.0 (November 1, 2022) = -* Hook into WPGraphQL to emit surrogate keys [[#199](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/199)]. -* Add Plugin Integrations section to README - -= 1.0.0 (March 2, 2020) = -* Plugin is stable. - -= 0.3.1 (October 27th, 2019) = -* Fixes reversed argument order with use of `implode()` [[#139](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/139)]. -* Various PHPCS cleanup [[#127](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/127)]. - -= 0.3.0 (November 27th, 2017) = -* Emits '404' surrogate key on 404s; purges when purging the homepage [[#107](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/107)]. -* Adds more specific filters for modifying surrogate keys in different contexts [[#109](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/109)]. -* Cleans up codebase according to WordPress Coding Standards [[#110](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/110), [#116](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/116)]. - -= 0.2.1 (October 25th, 2017) = -* Ensures use of `?_embed` emits correct surrogate keys [[#103](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/103)]. - -= 0.2.0 (August 10th, 2017) = -* Automatically trims large lists of surrogate keys that break Nginx and Varnish limits for header size. - -= 0.1.5 (May 24th, 2017) = -* Disables emitting surrogate keys for the admin, unless explicitly added by filter. - -= 0.1.4 (March 7th, 2017) = -* Emits `feed` surrogate key for RSS feeds, and purges when posts are created, modified, or deleted. - -= 0.1.3 (March 1st, 2017) = -* Prevents error notices by only accessing `$rest_base` property of post types and taxonomies when set. - -= 0.1.2 (December 6th, 2016) = -* Permits admins to flush cache for a specific page if the `delete_others_posts` capability has been deleted. - -= 0.1.1 (November 30th, 2016) = -* Drops settings UI in favor of including it in Pantheon's WordPress upstream. - -= 0.1.0 (November 23rd, 2016) = -* Initial release. +=== Pantheon Advanced Page Cache === +Contributors: getpantheon, danielbachhuber, kporras07, jspellman, jazzs3quence +Tags: pantheon, cdn, cache +Requires at least: 4.7 +Tested up to: 6.2 +Stable tag: 1.2.3 +License: GPLv2 or later +License URI: http://www.gnu.org/licenses/gpl-2.0.html + +Automatically clear related pages from Pantheon's Edge when you update content. High TTL. Fresh content. Visitors never wait. + +== Description == + +[![CircleCI](https://circleci.com/gh/pantheon-systems/pantheon-advanced-page-cache.svg?style=svg)](https://circleci.com/gh/pantheon-systems/pantheon-advanced-page-cache) + +For sites wanting fine-grained control over how their responses are represented in their edge cache, Pantheon Advanced Page Cache is the golden ticket. Here's a high-level overview of how the plugin works: + +1. When a response is generated, the plugin uses surrogate keys based on WordPress' main `WP_Query` object to "tag" the response with identifers for the data used in the response. See the "Adding Custom Keys" section for including your own surrogate keys. +2. When WordPress data is modified, the plugin triggers a purge request for the data's corresponding surrogate keys. + +Because of its surrogate key technology, Pantheon Advanced Page Cache empowers WordPress sites with a significantly more accurate cache purge mechanism, and generally higher cache hit rate. It even works with the WordPress REST API. + +Go forth and make awesome! And, once you've built something great, [send us feature requests (or bug reports)](https://github.com/pantheon-systems/pantheon-advanced-page-cache/issues). + +== Installation == + +To install Pantheon Advanced Page Cache, follow these steps: + +1. Install the plugin from WordPress.org using the WordPress dashboard. +2. Activate the plugin. + +To install Pantheon Advanced Page Cache in one line with WP-CLI: + + wp plugin install pantheon-advanced-page-cache --activate + +== How It Works == + +Pantheon Advanced Page Cache makes heavy use of surrogate keys, which enable responses to be "tagged" with identifiers that can then later be used in purge requests. For instance, a home page response might include the `Surrogate-Key` header with these keys: + + Surrogate-Key: front home post-43 user-4 post-41 post-9 post-7 post-1 user-1 + +Similarly, a `GET` requests to `/wp-json/wp/v2/posts` might include the `Surrogate-Key` header with these keys: + + Surrogate-Key: rest-post-collection rest-post-43 rest-post-43 rest-post-9 rest-post-7 rest-post-1 + +Because cached responses include metadata describing the data therein, surrogate keys enable more flexible purging behavior like: + +* When a post is updated, clear the cache for the post's URL, the homepage, any index view the post appears on, and any REST API endpoints the post is present in. +* When an author changes their name, clear the cache for the author's archive and any post they've authored. + +There is a limit to the number of surrogate keys in a response, so we've optimized them based on a user's expectation of a normal WordPress site. See the "Emitted Keys" section for full details on which keys are included, and the "Adding Custom Keys" section following for information on how to add your own. + += Adding Custom Keys = + +By default, Pantheon Advanced Page Cache generates surrogate keys based on an interpretation of the main `WP_Query` query object. Because WordPress sends headers before the page is rendered, you need to use the `pantheon_wp_main_query_surrogate_keys` filter to include additional surrogate keys for any data present on the page. + +For example, to include surrogate keys for a sidebar rendered on the homepage, you can filter the keys using the `is_home()` template tag: + + /** + * Add surrogate key for the featured content sidebar rendered on the homepage. + */ + add_filter( 'pantheon_wp_main_query_surrogate_keys', function( $keys ){ + if ( is_home() ) { + $keys[] = 'sidebar-home-featured'; + } + return $keys; + }); + +Then, when sidebars are updated, you can use the `pantheon_wp_clear_edge_keys()` helper function to emit a purge event specific to the surrogate key: + + /** + * Trigger a purge event for the featured content sidebar when widgets are updated. + */ + add_action( 'update_option_sidebars_widgets', function() { + pantheon_wp_clear_edge_keys( array( 'sidebar-home-featured' ) ); + }); + +Similarly, to include surrogate keys for posts queried on the homepage, you can pre-fetch the posts before the page is rendered: + + /** + * An example of pre-fetching a WP_Query to tag the + * response with queried data. You'd use `papcx_wp_query()` + * a second time within your template to use the data. + */ + add_filter( 'pantheon_wp_main_query_surrogate_keys', function( $keys ) { + if ( is_home() ) { + $query = papcx_wp_query( array( + 'post_type' => 'page', + ) ); + foreach( $query->posts as $post ) { + $keys[] = 'post-' . $post->ID; + } + } + return $keys; + }); + + /** + * Register a 'papc-non-persistent' cache group to cache data + * in a non-persistent manner. We only want data in this group + * to be cached within the page request. + */ + add_action( 'init', function(){ + wp_cache_add_non_persistent_groups( array( 'papc-non-persistent' ) ); + }); + + /** + * Helper function to instantiate a WP_Query object only + * once per page request. + * + * @param array $args Arguments to pass to WP_Query. + * @return WP_Query + */ + function papcx_wp_query( $args = array() ) { + $cache_key = md5( serialize( $args ) ); + // WP_Query object will be in cache the second time we use the function. + $cache_value = wp_cache_get( $cache_key, 'papc-non-persistent' ); + if ( false !== $cache_value ) { + return $cache_value; + } + $query = new WP_Query( $args ); + wp_cache_set( $cache_key, $query, 'papc-non-persistent' ); + return $query; + } + +Because Pantheon Advanced Page Cache already handles WordPress post purge events, there's no additional call to `pantheon_wp_clear_edge_keys()`. + +Lastly, the `pantheon_wp_rest_api_surrogate_keys` filter lets you filter surrogate keys present in a REST API response. + +Need a bit more power? In addition to `pantheon_wp_clear_edge_keys()`, there are two additional helper functions you can use: + +* `pantheon_wp_clear_edge_paths( $paths = array() )` - Purge cache for one or more paths. +* `pantheon_wp_clear_edge_all()` - Warning! With great power comes great responsibility. Purge the entire cache, but do so wisely. + +== WP-CLI Commands == + +This plugin implements a variety of [WP-CLI](https://wp-cli.org) commands. All commands are grouped into the `wp pantheon cache` namespace. + + $ wp help pantheon cache + + NAME + + wp pantheon cache + + DESCRIPTION + + Manage the Pantheon Advanced Page Cache. + + SYNOPSIS + + wp pantheon cache + + SUBCOMMANDS + + purge-all Purge the entire page cache. + purge-key Purge one or more surrogate keys from cache. + purge-path Purge one or more paths from cache. + +Use `wp help pantheon cache ` to learn more about each command. + +== Debugging == + +By default, Pantheon's infrastructure strips out the `Surrogate-Key` response header before responses are served to clients. The contents of this header can be viewed as `Surrogate-Key-Raw` by adding on a debugging header to the request. + +A direct way of inspecting headers is with `curl -I`. This command will make a request and show just the response headers. Adding `-H "Pantheon-Debug:1"` will result in `Surrogate-Key-Raw` being included in the response headers. The complete command looks like this: + + curl -IH "Pantheon-Debug:1" https://scalewp.io/ + +Piping to `grep` will filter the output down to just the `Surrogate-Key-Raw` header: + + curl -IH "Pantheon-Debug:1" https://scalewp.io/ | grep -i Surrogate-Key-Raw + +Tada! + +== Emitted Keys and Purge Events = + += Emitted Keys on Traditional Views = + +**Home `/`** + +* Emits surrogate keys: `home`, `front`, `post-` (all posts in main query) + +**Single post `/2016/10/14/surrogate-keys/`** + +* Emits surrogate keys: `single`, `post-`, `post-user-`, `post-term-` (all terms assigned to post) + +**Author archive `/author/pantheon/`** + +* Emits surrogate keys: `archive`, `user-`, `post-` (all posts in main query) + +**Term archive `/tag/cdn/`** + +* Emits surrogate keys: `archive`, `term-`, `post-` (all posts in main query) + +**Day archive `/2016/10/14/`** + +* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) + +**Month archive `/2016/10/`** + +* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) + +**Year archive `/2016/`** + +* Emits surrogate keys: `archive`, `date`, `post-` (all posts in main query) + +**Search `/?s=`** + +* Emits surrogate keys: `search`, either `search-results` or `search-no-results`, `post-` (all posts in main query) + +**Not found (404)** + +* Emits surrogate keys: `404` + += Emitted Keys on REST API Endpoints = + +**Posts** + +* `/wp-json/wp/v2/posts` emits surrogate keys: `rest-post-collection`, `rest-post-` +* `/wp-json/wp/v2/posts/` emits surrogate keys: `rest-post-` + +**Pages** + +* `/wp-json/wp/v2/pages` emits surrogate keys: `rest-page-collection`, `rest-post-` +* `/wp-json/wp/v2/pages/` emits surrogate keys: `rest-post-` + +**Categories** + +* `/wp-json/wp/v2/categories` emits surrogate keys: `rest-category-collection`, `rest-term-` +* `/wp-json/wp/v2/categories/` emits surrogate keys: `rest-term-` + +**Tags** + +* `/wp-json/wp/v2/tags` emits surrogate keys: `rest-post_tag-collection`, `rest-term-` +* `/wp-json/wp/v2/tags/` emits surrogate keys: `rest-term-` + +**Comments** + +* `/wp-json/wp/v2/comments` emits surrogate keys: `rest-comment-collection`, `rest-comment-post-`, `rest-comment-` +* `/wp-json/wp/v2/comments/` emits surrogate keys: `rest-comment-post-`, `rest-comment-` + +**Users** + +* `/wp-json/wp/v2/users` emits surrogate keys: `rest-user-collection`, `rest-user-` +* `/wp-json/wp/v2/users/` emits surrogate keys: `rest-user-` + +**Settings** + +* `/wp-json/wp/v2/settings` emits surrogate keys: `rest-setting-` + += Purge Events = + +Different WordPress actions cause different surrogate keys to be purged, documented here. + +**wp_insert_post / transition_post_status / before_delete_post / delete_attachment** + +* Purges surrogate keys: `home`, `front`, `404`, `post-`, `user-`, `term-`, `rest--collection`, `rest-comment-post-` +* Affected views: homepage, single post, any page with 404 header, any archive where post displays, author archive, term archive, REST API collection and resource endpoints + +**clean_post_cache** + +* Purges surrogate keys: `post-`, `rest-post-` +* Affected views: single post, REST API resource endpoint + +**created_term / edited_term / delete_term** + +* Purges surrogate keys: `term-`, `post-term-`, `rest--collection` +* Affected views: term archive, any post where the term is assigned, REST API collection and resource endpoints + +**clean_term_cache** + +* Purges surrogate keys: `term-`, `rest-term-` +* Affected views: term archive, REST API resource endpoint + +**wp_insert_comment / transition_comment_status** + +* Purges surrogate keys: `rest-comment-collection`, `rest-comment-` +* Affected views: REST API collection and resource endpoints + +**clean_comment_cache** + +* Purges surrogate keys: `rest-comment-` +* Affected views: REST API resource endpoint + +**clean_user_cache** + +* Purges surrogate keys: `user-`, `rest-user-` +* Affected views: author archive, any post where the user is the author + +**updated_option** + +* Purges surrogate keys: `rest-setting-` +* Affected views: REST API resource endpoint + +## Plugin Integrations ## + +Pantheon Advanced Page Cache integrates with WordPress plugins, including: + +* [WPGraphQL](https://wordpress.org/plugins/wp-graphql/) + +== Contributing == + +See [CONTRIBUTING.md](https://github.com/pantheon-systems/wp-saml-auth/blob/master/CONTRIBUTING.md) for information on contributing. + +== Changelog == += 1.2.3 (April 5, 2023) = +* Bump tested up to version to 6.2 + += 1.2.2 (March 14, 2023) = +* Adds PHP 8.2 compatibility [[#218](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/218)]. +* Bump dependencies [[#204](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/204)]. + += 1.2.2 (March 14, 2023) = +* Adds PHP 8.2 compatibility [[#218](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/218)]. +* Bump dependencies [[#204](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/204)]. + += 1.2.1 (February 23, 2023) = +* Handle models that are not instances of the `WPGraphQL\Model\Model` class [[#212](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/212)]. +* Make dependabot target develop branch [[#209](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/209)]. +* Bump dependencies [[#210](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/210)] [[#214](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/214)]. + += 1.2.0 (November 29, 2022) = +* Adds Github Actions for building tag and deploying to wp.org. Add CONTRIBUTING.md. [[#203](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/203)] + += 1.1.0 (November 1, 2022) = +* Hook into WPGraphQL to emit surrogate keys [[#199](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/199)]. +* Add Plugin Integrations section to README + += 1.0.0 (March 2, 2020) = +* Plugin is stable. + += 0.3.1 (October 27th, 2019) = +* Fixes reversed argument order with use of `implode()` [[#139](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/139)]. +* Various PHPCS cleanup [[#127](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/127)]. + += 0.3.0 (November 27th, 2017) = +* Emits '404' surrogate key on 404s; purges when purging the homepage [[#107](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/107)]. +* Adds more specific filters for modifying surrogate keys in different contexts [[#109](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/109)]. +* Cleans up codebase according to WordPress Coding Standards [[#110](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/110), [#116](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/116)]. + += 0.2.1 (October 25th, 2017) = +* Ensures use of `?_embed` emits correct surrogate keys [[#103](https://github.com/pantheon-systems/pantheon-advanced-page-cache/pull/103)]. + += 0.2.0 (August 10th, 2017) = +* Automatically trims large lists of surrogate keys that break Nginx and Varnish limits for header size. + += 0.1.5 (May 24th, 2017) = +* Disables emitting surrogate keys for the admin, unless explicitly added by filter. + += 0.1.4 (March 7th, 2017) = +* Emits `feed` surrogate key for RSS feeds, and purges when posts are created, modified, or deleted. + += 0.1.3 (March 1st, 2017) = +* Prevents error notices by only accessing `$rest_base` property of post types and taxonomies when set. + += 0.1.2 (December 6th, 2016) = +* Permits admins to flush cache for a specific page if the `delete_others_posts` capability has been deleted. + += 0.1.1 (November 30th, 2016) = +* Drops settings UI in favor of including it in Pantheon's WordPress upstream. + += 0.1.0 (November 23rd, 2016) = +* Initial release. diff --git a/tests/phpunit/class-pantheon-advanced-page-cache-testcase.php b/tests/phpunit/class-pantheon-advanced-page-cache-testcase.php index 8320f2ae..df8cb70d 100644 --- a/tests/phpunit/class-pantheon-advanced-page-cache-testcase.php +++ b/tests/phpunit/class-pantheon-advanced-page-cache-testcase.php @@ -18,14 +18,14 @@ class Pantheon_Advanced_Page_Cache_Testcase extends WP_UnitTestCase { * * @var array */ - protected $cleared_keys = array(); + protected $cleared_keys = []; /** * Mapping of views to their surrogate keys. * * @var array */ - protected $view_surrogate_keys = array(); + protected $view_surrogate_keys = []; /** * Sets up the testcase. @@ -38,154 +38,154 @@ public function setUp(): void { $this->setup_permalink_structure(); $this->user_id1 = $this->factory->user->create( - array( + [ 'role' => 'author', 'user_nicename' => 'first-user', - ) + ] ); $this->user_id2 = $this->factory->user->create( - array( + [ 'role' => 'author', 'user_nicename' => 'second-user', - ) + ] ); $this->user_id3 = $this->factory->user->create( - array( + [ 'role' => 'author', 'user_nicename' => 'third-user', - ) + ] ); $this->admin_id1 = $this->factory->user->create( - array( + [ 'role' => 'administrator', 'user_nicename' => 'first-admin', - ) + ] ); $this->tag_id1 = $this->factory->tag->create( - array( + [ 'slug' => 'first-tag', - ) + ] ); $this->tag_id2 = $this->factory->tag->create( - array( + [ 'slug' => 'second-tag', - ) + ] ); $this->category_id1 = 1; // This is the default 'uncategorized' category. $this->category_id2 = $this->factory->category->create( - array( + [ 'slug' => 'second-category', - ) + ] ); $this->product_category_id1 = $this->factory->product_category->create( - array( + [ 'slug' => 'first-product-category', - ) + ] ); $this->product_category_id2 = $this->factory->product_category->create( - array( + [ 'slug' => 'second-product-category', - ) + ] ); $this->product_category_id3 = $this->factory->product_category->create( - array( + [ 'slug' => 'third-product-category', - ) + ] ); $this->post_id1 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_author' => $this->user_id1, 'post_date' => '2016-10-14 12:00', 'post_date_gmt' => '2016-10-14 12:00', 'post_name' => 'first-post', - ) + ] ); - wp_set_object_terms( $this->post_id1, array( $this->tag_id2 ), 'post_tag' ); + wp_set_object_terms( $this->post_id1, [ $this->tag_id2 ], 'post_tag' ); $this->post_id2 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_author' => $this->user_id2, 'post_date' => '2016-10-14 11:00', 'post_date_gmt' => '2016-10-14 11:00', 'post_name' => 'second-post', - ) + ] ); $this->post_id3 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_author' => $this->user_id2, 'post_date' => '2016-10-15 11:00', 'post_date_gmt' => '2016-10-15 11:00', 'post_name' => 'third-post', - ) + ] ); $this->post_id4 = $this->factory->post->create( - array( + [ 'post_status' => 'draft', 'post_author' => $this->user_id2, 'post_date' => '2016-10-15 11:00', 'post_date_gmt' => '2016-10-15 11:00', 'post_name' => 'fourth-post', - ) + ] ); $this->page_id1 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_type' => 'page', 'post_author' => $this->user_id1, 'post_name' => 'first-page', - ) + ] ); $this->product_id1 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_type' => 'product', 'post_author' => $this->user_id1, 'post_date' => '2016-10-14 12:00', 'post_date_gmt' => '2016-10-14 12:00', 'post_name' => 'first-product', - ) + ] ); - wp_set_object_terms( $this->product_id1, array( $this->product_category_id2 ), 'product_category' ); + wp_set_object_terms( $this->product_id1, [ $this->product_category_id2 ], 'product_category' ); $this->product_id2 = $this->factory->post->create( - array( + [ 'post_status' => 'publish', 'post_type' => 'product', 'post_author' => $this->user_id2, 'post_date' => '2016-10-14 11:00', 'post_date_gmt' => '2016-10-14 11:00', 'post_name' => 'second-product', - ) + ] ); - wp_set_object_terms( $this->product_id2, array( $this->product_category_id1 ), 'product_category' ); + wp_set_object_terms( $this->product_id2, [ $this->product_category_id1 ], 'product_category' ); $this->comment_id1 = $this->factory->comment->create( - array( + [ 'comment_post_ID' => $this->post_id1, 'comment_approved' => 1, 'user_id' => 0, - ) + ] ); $this->attachment_id1 = $this->factory->post->create( - array( + [ 'post_mime_type' => 'image/jpeg', 'post_type' => 'attachment', 'post_author' => $this->user_id1, 'post_status' => 'publish', 'post_parent' => 0, - ) + ] ); - $this->cleared_keys = array(); + $this->cleared_keys = []; $this->setup_view_surrogate_keys(); Emitter::reset_rest_api_surrogate_keys(); - add_action( 'pantheon_wp_clear_edge_keys', array( $this, 'action_pantheon_wp_clear_edge_keys' ) ); + add_action( 'pantheon_wp_clear_edge_keys', [ $this, 'action_pantheon_wp_clear_edge_keys' ] ); } /** @@ -228,9 +228,9 @@ protected function setup_rest_api_server() { * Primes the mapping of views to their surrogate keys. */ protected function setup_view_surrogate_keys() { - $this->view_surrogate_keys = array(); + $this->view_surrogate_keys = []; // Primes the mapping of views to their surrogate keys. - $views = array( + $views = [ home_url( '/' ), // Homepage. '/products/', // Product post type archive. '/2016/10/14/', // Day archive with posts. @@ -240,14 +240,14 @@ protected function setup_view_surrogate_keys() { '/2016/', // Year archive with posts. '/2015/', // Year archive without posts. '/feed/', // Basic RSS feed. - ); - $rest_api_routes = array(); + ]; + $rest_api_routes = []; $posts = get_posts( - array( + [ 'post_type' => 'any', 'post_status' => 'any', 'posts_per_page' => -1, - ) + ] ); foreach ( $posts as $post ) { $views[] = get_permalink( $post->ID ); @@ -259,9 +259,9 @@ protected function setup_view_surrogate_keys() { } } $users = get_users( - array( + [ 'fields' => 'ids', - ) + ] ); foreach ( $users as $user_id ) { $views[] = get_author_posts_url( $user_id ); @@ -269,10 +269,10 @@ protected function setup_view_surrogate_keys() { $rest_api_routes[] = '/wp/v2/users/' . $user_id; } $terms = get_terms( - array( 'post_tag', 'category', 'product_category' ), - array( + [ 'post_tag', 'category', 'product_category' ], + [ 'hide_empty' => false, - ) + ] ); foreach ( $terms as $term ) { $views[] = get_term_link( $term ); @@ -346,22 +346,22 @@ protected function setup_view_surrogate_keys() { private function register_custom_types() { register_post_type( 'product', - array( + [ 'public' => true, 'has_archive' => 'products', 'show_in_rest' => true, - ) + ] ); register_taxonomy( 'product_category', - array( 'product' ), - array( + [ 'product' ], + [ 'public' => true, - 'rewrite' => array( + 'rewrite' => [ 'slug' => 'product-category', - ), + ], 'show_in_rest' => true, - ) + ] ); } @@ -394,7 +394,7 @@ protected function assertClearedKeys( $expected ) { * @param array $expected URIs expected to be cleared based on cleared keys. */ protected function assertPurgedURIs( $expected ) { - $actual = array(); + $actual = []; foreach ( $this->view_surrogate_keys as $view => $keys ) { if ( array_intersect( $keys, $this->cleared_keys ) ) { $actual[] = $view; @@ -428,9 +428,9 @@ protected function assertArrayValues( $expected, $actual ) { /** * Tear down behaviors after the tests have completed. */ - public function tearDown(): void { - $this->cleared_keys = array(); - remove_action( 'pantheon_wp_clear_edge_keys', array( $this, 'action_pantheon_wp_clear_edge_keys' ) ); + public function tearDown() : void { + $this->cleared_keys = []; + remove_action( 'pantheon_wp_clear_edge_keys', [ $this, 'action_pantheon_wp_clear_edge_keys' ] ); _unregister_post_type( 'product' ); _unregister_taxonomy( 'product_category' ); parent::tearDown();