From 73ccfd858ca0bf3366aad5ed4d9072e741841606 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Tue, 1 Aug 2023 10:55:05 +0200 Subject: [PATCH 01/25] Disable XML RPC endpoint by default --- src/Managers/CleanupManager.php | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/Managers/CleanupManager.php b/src/Managers/CleanupManager.php index a674f20..e29d52a 100644 --- a/src/Managers/CleanupManager.php +++ b/src/Managers/CleanupManager.php @@ -18,9 +18,24 @@ * Cleanup a WordPress project for security and performance. */ class CleanupManager implements ManagerInterface { - // phpcs:ignore Generic.Commenting.DocComment.MissingShort /** - * @inheritdoc + * Wether to enable XML RPC endpoint or not. + * + * @var bool + */ + protected $xml_rpc; + + /** + * Constructor. + * + * @param bool $xml_rpc Enable or disable XML RPC. + */ + public function __construct( bool $xml_rpc = false ) { + $this->xml_rpc = $xml_rpc; + } + + /** + * {@inheritdoc} */ public function run() { // Clean up . @@ -47,6 +62,8 @@ public function run() { // Remove comments from the admin menu. add_action( 'admin_menu', array( $this, 'remove_comments_from_admin_menu' ) ); + + add_filter( 'xmlrpc_enabled', array( $this, 'xmlrpc_enabled' ) ); } /** @@ -152,4 +169,11 @@ public function remove_comments_from_admin_menu():void { // Remove comments admin menu item. remove_menu_page( 'edit-comments.php' ); } + + /** + * Enable or disable XML RPC endpoint. + */ + public function xmlrpc_enabled():bool { + return $this->xml_rpc; + } } From f5fbfcde8d905d4180d7b3283dbdd7d50f72a040 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 19 Oct 2023 10:32:36 +0200 Subject: [PATCH 02/25] Update changelog --- CHANGELOG.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c665759 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,11 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +### Added + +- **CleanupManager:** Disable XML-RPC by default ([#21](https://github.com/studiometa/wp-toolkit/pull/21)) From 3146b9c547b78e77047bc718551a852dcb1f382a Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 19 Oct 2023 10:56:32 +0200 Subject: [PATCH 03/25] Add tests --- tests/Managers/CleanupManagerTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/Managers/CleanupManagerTest.php b/tests/Managers/CleanupManagerTest.php index f35b381..88d43da 100644 --- a/tests/Managers/CleanupManagerTest.php +++ b/tests/Managers/CleanupManagerTest.php @@ -6,6 +6,14 @@ * CleanupManagerTest test case. */ class CleanupManagerTest extends WP_UnitTestCase { + + /** + * CleanupManager. + * + * @var CleanupManager + */ + public $cleanup_manager; + public function setUp():void { parent::setUp(); @@ -28,4 +36,14 @@ public function test_remove_version_css_js() { $this->assertFalse( strpos( $updated_other_src, 'ver=' ) ); $this->assertNotFalse( strpos( $updated_theme_src, 'ver=' ) ); } + + /** + * Test disable XML RPC. + * + * @return void + */ + public function test_xml_rpc_disabled() { + $this->cleanup_manager->run(); + $this->assertFalse( apply_filters( 'xmlrpc_enabled', true ) ); + } } From 50fa919c2a62f9677fcbe0ec585a4d494c3b52d0 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 15:52:42 +0100 Subject: [PATCH 04/25] Add a `Plugin` helper class --- .ddev/config.yaml | 258 +---------- composer.json | 15 +- composer.lock | 761 +++++++++++++++++++++------------ src/Helpers/Plugin.php | 130 ++++++ src/Helpers/PluginHelper.php | 42 -- tests/Helpers/PluginHelper.php | 19 - tests/Helpers/PluginTest.php | 36 ++ 7 files changed, 678 insertions(+), 583 deletions(-) create mode 100644 src/Helpers/Plugin.php delete mode 100644 src/Helpers/PluginHelper.php delete mode 100644 tests/Helpers/PluginHelper.php create mode 100644 tests/Helpers/PluginTest.php diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 1dd4d20..808b3d4 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -1,262 +1,22 @@ name: wp-toolkit type: php docroot: src -php_version: "8.0" +php_version: '8.1' webserver_type: nginx-fpm -router_http_port: "80" -router_https_port: "443" +router_http_port: '80' +router_https_port: '443' xdebug_enabled: true additional_hostnames: [] additional_fqdns: [] database: type: mariadb - version: "10.4" -nfs_mount_enabled: false -mutagen_enabled: false -use_dns_when_possible: true -composer_version: "2" -web_environment: - - XDEBUG_MODE=coverage -nodejs_version: "16" + version: '10.4' hooks: post-start: - exec: sudo apt-get update && sudo apt-get install subversion -y - exec: ./bin/install-wp-tests.sh wordpress_test root root db latest - -# Key features of ddev's config.yaml: - -# name: # Name of the project, automatically provides -# http://projectname.ddev.site and https://projectname.ddev.site - -# type: # drupal6/7/8, backdrop, typo3, wordpress, php - -# docroot: # Relative path to the directory containing index.php. - -# php_version: "7.4" # PHP version to use, "5.6", "7.0", "7.1", "7.2", "7.3", "7.4", "8.0", "8.1", "8.2" - -# You can explicitly specify the webimage but this -# is not recommended, as the images are often closely tied to ddev's' behavior, -# so this can break upgrades. - -# webimage: # nginx/php docker image. - -# database: -# type: # mysql, mariadb -# version: # database version, like "10.3" or "8.0" -# Note that mariadb_version or mysql_version from v1.18 and earlier -# will automatically be converted to this notation with just a "ddev config --auto" - -# router_http_port: # Port to be used for http (defaults to port 80) -# router_https_port: # Port for https (defaults to 443) - -# xdebug_enabled: false # Set to true to enable xdebug and "ddev start" or "ddev restart" -# Note that for most people the commands -# "ddev xdebug" to enable xdebug and "ddev xdebug off" to disable it work better, -# as leaving xdebug enabled all the time is a big performance hit. - -# xhprof_enabled: false # Set to true to enable xhprof and "ddev start" or "ddev restart" -# Note that for most people the commands -# "ddev xhprof" to enable xhprof and "ddev xhprof off" to disable it work better, -# as leaving xhprof enabled all the time is a big performance hit. - -# webserver_type: nginx-fpm # or apache-fpm - -# timezone: Europe/Berlin -# This is the timezone used in the containers and by PHP; -# it can be set to any valid timezone, -# see https://en.wikipedia.org/wiki/List_of_tz_database_time_zones -# For example Europe/Dublin or MST7MDT - -# composer_root: -# Relative path to the composer root directory from the project root. This is -# the directory which contains the composer.json and where all Composer related -# commands are executed. - -# composer_version: "2" -# You can set it to "" or "2" (default) for Composer v2 or "1" for Composer v1 -# to use the latest major version available at the time your container is built. -# It is also possible to use each other Composer version channel. This includes: -# - 2.2 (latest Composer LTS version) -# - stable -# - preview -# - snapshot -# Alternatively, an explicit Composer version may be specified, for example "2.2.18". -# To reinstall Composer after the image was built, run "ddev debug refresh". - -# nodejs_version: "16" -# change from the default system Node.js version to another supported version, like 12, 14, 17, 18. -# Note that you can use 'ddev nvm' or nvm inside the web container to provide nearly any -# Node.js version, including v6, etc. - -# additional_hostnames: -# - somename -# - someothername -# would provide http and https URLs for "somename.ddev.site" -# and "someothername.ddev.site". - -# additional_fqdns: -# - example.com -# - sub1.example.com -# would provide http and https URLs for "example.com" and "sub1.example.com" -# Please take care with this because it can cause great confusion. - -# upload_dir: custom/upload/dir -# would set the destination path for ddev import-files to /custom/upload/dir -# When mutagen is enabled this path is bind-mounted so that all the files -# in the upload_dir don't have to be synced into mutagen - -# working_dir: -# web: /var/www/html -# db: /home -# would set the default working directory for the web and db services. -# These values specify the destination directory for ddev ssh and the -# directory in which commands passed into ddev exec are run. - -# omit_containers: [db, dba, ddev-ssh-agent] -# Currently only these containers are supported. Some containers can also be -# omitted globally in the ~/.ddev/global_config.yaml. Note that if you omit -# the "db" container, several standard features of ddev that access the -# database container will be unusable. In the global configuration it is also -# possible to omit ddev-router, but not here. - -# nfs_mount_enabled: false -# Great performance improvement but requires host configuration first. -# See https://ddev.readthedocs.io/en/latest/users/install/performance/#nfs - -# mutagen_enabled: false -# Performance improvement using mutagen asynchronous updates. -# See https://ddev.readthedocs.io/en/latest/users/install/performance/#mutagen - -# fail_on_hook_fail: False -# Decide whether 'ddev start' should be interrupted by a failing hook - -# host_https_port: "59002" -# The host port binding for https can be explicitly specified. It is -# dynamic unless otherwise specified. -# This is not used by most people, most people use the *router* instead -# of the localhost port. - -# host_webserver_port: "59001" -# The host port binding for the ddev-webserver can be explicitly specified. It is -# dynamic unless otherwise specified. -# This is not used by most people, most people use the *router* instead -# of the localhost port. - -# host_db_port: "59002" -# The host port binding for the ddev-dbserver can be explicitly specified. It is dynamic -# unless explicitly specified. - -# phpmyadmin_port: "8036" -# phpmyadmin_https_port: "8037" -# The PHPMyAdmin ports can be changed from the default 8036 and 8037 - -# host_phpmyadmin_port: "8036" -# The phpmyadmin (dba) port is not normally bound on the host at all, instead being routed -# through ddev-router, but it can be specified and bound. - -# mailhog_port: "8025" -# mailhog_https_port: "8026" -# The MailHog ports can be changed from the default 8025 and 8026 - -# host_mailhog_port: "8025" -# The mailhog port is not normally bound on the host at all, instead being routed -# through ddev-router, but it can be bound directly to localhost if specified here. - -# webimage_extra_packages: [php7.4-tidy, php-bcmath] -# Extra Debian packages that are needed in the webimage can be added here - -# dbimage_extra_packages: [telnet,netcat] -# Extra Debian packages that are needed in the dbimage can be added here - -# use_dns_when_possible: true -# If the host has internet access and the domain configured can -# successfully be looked up, DNS will be used for hostname resolution -# instead of editing /etc/hosts -# Defaults to true - -# project_tld: ddev.site -# The top-level domain used for project URLs -# The default "ddev.site" allows DNS lookup via a wildcard -# If you prefer you can change this to "ddev.local" to preserve -# pre-v1.9 behavior. - -# ngrok_args: --basic-auth username:pass1234 -# Provide extra flags to the "ngrok http" command, see -# https://ngrok.com/docs#http or run "ngrok http -h" - -# disable_settings_management: false -# If true, ddev will not create CMS-specific settings files like -# Drupal's settings.php/settings.ddev.php or TYPO3's AdditionalConfiguration.php -# In this case the user must provide all such settings. - -# You can inject environment variables into the web container with: -# web_environment: -# - SOMEENV=somevalue -# - SOMEOTHERENV=someothervalue - -# no_project_mount: false -# (Experimental) If true, ddev will not mount the project into the web container; -# the user is responsible for mounting it manually or via a script. -# This is to enable experimentation with alternate file mounting strategies. -# For advanced users only! - -# bind_all_interfaces: false -# If true, host ports will be bound on all network interfaces, -# not just the localhost interface. This means that ports -# will be available on the local network if the host firewall -# allows it. - -# default_container_timeout: 120 -# The default time that ddev waits for all containers to become ready can be increased from -# the default 120. This helps in importing huge databases, for example. - -#web_extra_exposed_ports: -#- name: nodejs -# container_port: 3000 -# http_port: 2999 -# https_port: 3000 -#- name: something -# container_port: 4000 -# https_port: 4000 -# http_port: 3999 -# Allows a set of extra ports to be exposed via ddev-router -# The port behavior on the ddev-webserver must be arranged separately, for example -# using web_extra_daemons. -# For example, with a web app on port 3000 inside the container, this config would -# expose that web app on https://.ddev.site:9999 and http://.ddev.site:9998 -# web_extra_exposed_ports: -# - container_port: 3000 -# http_port: 9998 -# https_port: 9999 - -#web_extra_daemons: -#- name: "http-1" -# command: "/var/www/html/node_modules/.bin/http-server -p 3000" -# directory: /var/www/html -#- name: "http-2" -# command: "/var/www/html/node_modules/.bin/http-server /var/www/html/sub -p 3000" -# directory: /var/www/html - -# override_config: false -# By default, config.*.yaml files are *merged* into the configuration -# But this means that some things can't be overridden -# For example, if you have 'nfs_mount_enabled: true'' you can't override it with a merge -# and you can't erase existing hooks or all environment variables. -# However, with "override_config: true" in a particular config.*.yaml file, -# 'nfs_mount_enabled: false' can override the existing values, and -# hooks: -# post-start: [] -# or -# web_environment: [] -# or -# additional_hostnames: [] -# can have their intended affect. 'override_config' affects only behavior of the -# config.*.yaml file it exists in. - -# Many ddev commands can be extended to run tasks before or after the -# ddev command is executed, for example "post-start", "post-import-db", -# "pre-composer", "post-composer" -# See https://ddev.readthedocs.io/en/stable/users/extend/custom-commands/ for more -# information on the commands that can be extended and the tasks you can define -# for them. Example: -#hooks: +use_dns_when_possible: true +composer_version: '2' +web_environment: + - XDEBUG_MODE=coverage +nodejs_version: '20' diff --git a/composer.json b/composer.json index e5d392e..da68da2 100644 --- a/composer.json +++ b/composer.json @@ -1,13 +1,15 @@ { "name": "studiometa/wp-toolkit", - "version": "1.0.0", + "version": "2.0.0", "description": "WordPress utilities for Studio Meta.", "license": "MIT", "type": "library", "require": { - "php": "^7.3|^8.0", - "symfony/yaml": "^5.1", - "studiometa/webpack-config": "^4.0" + "php": "^8.1", + "symfony/yaml": "^6.4|^7.0", + "studiometa/webpack-config": "^5.0", + "wecodemore/wordpress-early-hook": "^1.2", + "symfony/http-foundation": "^6.4|^7.0" }, "require-dev": { "squizlabs/php_codesniffer": "^3.4", @@ -21,7 +23,10 @@ "autoload": { "psr-4": { "Studiometa\\WPToolkit\\": "src/" - } + }, + "files": [ + "src/helpers.php" + ] }, "scripts": { "phpcs": "phpcs -s --colors --standard=./phpcs.xml", diff --git a/composer.lock b/composer.lock index 25b7749..d3e54f9 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3673c457682ecd22e94f372b339a4700", + "content-hash": "58321d066b07ecb11928cd5e68e5d563", "packages": [ { "name": "anahkiasen/html-object", @@ -54,16 +54,16 @@ }, { "name": "studiometa/webpack-config", - "version": "4.0.6", + "version": "5.3.0", "source": { "type": "git", "url": "https://github.com/studiometa/webpack-config.git", - "reference": "58c20fcecb52d832ef72cc98baa5db40d2c237d4" + "reference": "e7f09bc56d43a257937183e6be8a124408b248eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/studiometa/webpack-config/zipball/58c20fcecb52d832ef72cc98baa5db40d2c237d4", - "reference": "58c20fcecb52d832ef72cc98baa5db40d2c237d4", + "url": "https://api.github.com/repos/studiometa/webpack-config/zipball/e7f09bc56d43a257937183e6be8a124408b248eb", + "reference": "e7f09bc56d43a257937183e6be8a124408b248eb", "shasum": "" }, "require": { @@ -95,31 +95,31 @@ "description": "PHP Helpers for @studiometa/webpack-config", "support": { "issues": "https://github.com/studiometa/webpack-config/issues", - "source": "https://github.com/studiometa/webpack-config/tree/4.0.6" + "source": "https://github.com/studiometa/webpack-config/tree/5.3.0" }, - "time": "2022-10-25T22:39:10+00:00" + "time": "2023-10-26T20:50:18+00:00" }, { "name": "symfony/deprecation-contracts", - "version": "v2.5.2", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf" }, "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/7c3aff79d10325257a001fcf92d991f24fc967cf", + "reference": "7c3aff79d10325257a001fcf92d991f24fc967cf", "shasum": "" }, "require": { - "php": ">=7.1" + "php": ">=8.1" }, "type": "library", "extra": { "branch-alias": { - "dev-main": "2.5-dev" + "dev-main": "3.4-dev" }, "thanks": { "name": "symfony/contracts", @@ -148,7 +148,84 @@ "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.4.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2023-05-23T14:45:45+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v6.4.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "reference": "ebc713bc6e6f4b53f46539fc158be85dfcd77304", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "symfony/cache": "<6.3" + }, + "require-dev": { + "doctrine/dbal": "^2.13.1|^3|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.3|^7.0", + "symfony/dependency-injection": "^5.4|^6.0|^7.0", + "symfony/expression-language": "^5.4|^6.0|^7.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4|^7.0", + "symfony/mime": "^5.4|^6.0|^7.0", + "symfony/rate-limiter": "^5.4|^6.0|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v6.4.4" }, "funding": [ { @@ -164,20 +241,20 @@ "type": "tidelift" } ], - "time": "2022-01-02T09:53:40+00:00" + "time": "2024-02-08T15:01:18+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.26.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4" + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", - "reference": "6fd1b9a79f6e3cf65f9e679b23af304cd9e010d4", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/ef4d7e442ca910c4764bce785146269b30cb5fc4", + "reference": "ef4d7e442ca910c4764bce785146269b30cb5fc4", "shasum": "" }, "require": { @@ -191,9 +268,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -230,7 +304,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.29.0" }, "funding": [ { @@ -246,20 +320,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-mbstring", - "version": "v1.26.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e" + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", - "reference": "9344f9cb97f3b19424af1a21a3b0e75b0a7d8d7e", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/9773676c8a1bb1f8d4340a62efe641cf76eda7ec", + "reference": "9773676c8a1bb1f8d4340a62efe641cf76eda7ec", "shasum": "" }, "require": { @@ -273,9 +347,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -313,7 +384,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.29.0" }, "funding": [ { @@ -329,20 +400,20 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/polyfill-php80", - "version": "v1.26.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", - "reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", + "reference": "87b68208d5c1188808dd7839ee1e6c8ec3b02f1b", "shasum": "" }, "require": { @@ -350,9 +421,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -396,7 +464,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.29.0" }, "funding": [ { @@ -412,43 +480,116 @@ "type": "tidelift" } ], - "time": "2022-05-10T07:21:04+00:00" + "time": "2024-01-29T20:11:03+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.29.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/86fcae159633351e5fd145d1c47de6c528f8caff", + "reference": "86fcae159633351e5fd145d1c47de6c528f8caff", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "symfony/polyfill-php80": "^1.14" + }, + "type": "library", + "extra": { + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.29.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-01-29T20:11:03+00:00" }, { "name": "symfony/var-dumper", - "version": "v5.4.14", + "version": "v6.4.4", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "6894d06145fefebd9a4c7272baa026a1c394a430" + "reference": "b439823f04c98b84d4366c79507e9da6230944b1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6894d06145fefebd9a4c7272baa026a1c394a430", - "reference": "6894d06145fefebd9a4c7272baa026a1c394a430", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/b439823f04c98b84d4366c79507e9da6230944b1", + "reference": "b439823f04c98b84d4366c79507e9da6230944b1", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/polyfill-mbstring": "~1.0", - "symfony/polyfill-php80": "^1.16" + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" }, "conflict": { - "phpunit/phpunit": "<5.4.3", - "symfony/console": "<4.4" + "symfony/console": "<5.4" }, "require-dev": { "ext-iconv": "*", - "symfony/console": "^4.4|^5.0|^6.0", - "symfony/process": "^4.4|^5.0|^6.0", - "symfony/uid": "^5.1|^6.0", + "symfony/console": "^5.4|^6.0|^7.0", + "symfony/error-handler": "^6.3|^7.0", + "symfony/http-kernel": "^5.4|^6.0|^7.0", + "symfony/process": "^5.4|^6.0|^7.0", + "symfony/uid": "^5.4|^6.0|^7.0", "twig/twig": "^2.13|^3.0.4" }, - "suggest": { - "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", - "ext-intl": "To show region name in time zone dump", - "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" - }, "bin": [ "Resources/bin/var-dump-server" ], @@ -485,7 +626,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v5.4.14" + "source": "https://github.com/symfony/var-dumper/tree/v6.4.4" }, "funding": [ { @@ -501,35 +642,32 @@ "type": "tidelift" } ], - "time": "2022-10-07T08:01:20+00:00" + "time": "2024-02-15T11:23:52+00:00" }, { "name": "symfony/yaml", - "version": "v5.4.14", + "version": "v6.4.3", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "e83fe9a72011f07c662da46a05603d66deeeb487" + "reference": "d75715985f0f94f978e3a8fa42533e10db921b90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/e83fe9a72011f07c662da46a05603d66deeeb487", - "reference": "e83fe9a72011f07c662da46a05603d66deeeb487", + "url": "https://api.github.com/repos/symfony/yaml/zipball/d75715985f0f94f978e3a8fa42533e10db921b90", + "reference": "d75715985f0f94f978e3a8fa42533e10db921b90", "shasum": "" }, "require": { - "php": ">=7.2.5", - "symfony/deprecation-contracts": "^2.1|^3", + "php": ">=8.1", + "symfony/deprecation-contracts": "^2.5|^3", "symfony/polyfill-ctype": "^1.8" }, "conflict": { - "symfony/console": "<5.3" + "symfony/console": "<5.4" }, "require-dev": { - "symfony/console": "^5.3|^6.0" - }, - "suggest": { - "symfony/console": "For validating YAML files using the lint command" + "symfony/console": "^5.4|^6.0|^7.0" }, "bin": [ "Resources/bin/yaml-lint" @@ -560,7 +698,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.14" + "source": "https://github.com/symfony/yaml/tree/v6.4.3" }, "funding": [ { @@ -576,20 +714,20 @@ "type": "tidelift" } ], - "time": "2022-10-03T15:15:50+00:00" + "time": "2024-01-23T14:51:35+00:00" }, { "name": "tightenco/collect", - "version": "v8.83.25", + "version": "v8.83.27", "source": { "type": "git", "url": "https://github.com/tighten/collect.git", - "reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea" + "reference": "07eed6cf7441c7a69c379fdcb118eec1a1fdd0e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/tighten/collect/zipball/7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea", - "reference": "7d2a6fc5e97c5f7209a780bea98f35042c1fd0ea", + "url": "https://api.github.com/repos/tighten/collect/zipball/07eed6cf7441c7a69c379fdcb118eec1a1fdd0e6", + "reference": "07eed6cf7441c7a69c379fdcb118eec1a1fdd0e6", "shasum": "" }, "require": { @@ -628,9 +766,71 @@ ], "support": { "issues": "https://github.com/tighten/collect/issues", - "source": "https://github.com/tighten/collect/tree/v8.83.25" + "source": "https://github.com/tighten/collect/tree/v8.83.27" + }, + "time": "2023-01-13T18:05:42+00:00" + }, + { + "name": "wecodemore/wordpress-early-hook", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/wecodemore/wordpress-early-hook.git", + "reference": "4a54f490dd1d5a87aa8b8470592df0ec4620be8e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/wecodemore/wordpress-early-hook/zipball/4a54f490dd1d5a87aa8b8470592df0ec4620be8e", + "reference": "4a54f490dd1d5a87aa8b8470592df0ec4620be8e", + "shasum": "" + }, + "require": { + "php": ">=7.1 < 8.4" + }, + "require-dev": { + "inpsyde/php-coding-standards": "^1.0.0", + "phpunit/phpunit": "^7.5.20 || ^9.6.4", + "roave/security-advisories": "dev-latest", + "roots/wordpress-no-content": ">=6.1.1", + "vimeo/psalm": "^4.30.0" + }, + "type": "library", + "autoload": { + "files": [ + "wordpress-early-hook.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Giuseppe Mazzapica", + "email": "giuseppe.mazzapica@gmail.com", + "homepage": "https://gmazzap.me", + "role": "Developer" + } + ], + "description": "Small library to safely add WordPress hooks before WordPress is loaded.", + "keywords": [ + "actions", + "filters", + "hooks", + "wordpress", + "wordpress actions", + "wordpress filters", + "wordpress hooks", + "wp", + "wp actions", + "wp filters", + "wp hooks" + ], + "support": { + "issues": "https://github.com/wecodemore/wordpress-early-hook/issues", + "source": "https://github.com/wecodemore/wordpress-early-hook" }, - "time": "2022-08-22T17:55:07+00:00" + "time": "2024-01-08T14:44:02+00:00" } ], "packages-dev": [ @@ -711,30 +911,30 @@ }, { "name": "doctrine/instantiator", - "version": "1.4.1", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/doctrine/instantiator.git", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc" + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/10dcfce151b967d20fde1b34ae6640712c3891bc", - "reference": "10dcfce151b967d20fde1b34ae6640712c3891bc", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", + "reference": "c6222283fa3f4ac679f8b9ced9a4e23f163e80d0", "shasum": "" }, "require": { - "php": "^7.1 || ^8.0" + "php": "^8.1" }, "require-dev": { - "doctrine/coding-standard": "^9", + "doctrine/coding-standard": "^11", "ext-pdo": "*", "ext-phar": "*", - "phpbench/phpbench": "^0.16 || ^1", - "phpstan/phpstan": "^1.4", - "phpstan/phpstan-phpunit": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", - "vimeo/psalm": "^4.22" + "phpbench/phpbench": "^1.2", + "phpstan/phpstan": "^1.9.4", + "phpstan/phpstan-phpunit": "^1.3", + "phpunit/phpunit": "^9.5.27", + "vimeo/psalm": "^5.4" }, "type": "library", "autoload": { @@ -761,7 +961,7 @@ ], "support": { "issues": "https://github.com/doctrine/instantiator/issues", - "source": "https://github.com/doctrine/instantiator/tree/1.4.1" + "source": "https://github.com/doctrine/instantiator/tree/2.0.0" }, "funding": [ { @@ -777,20 +977,20 @@ "type": "tidelift" } ], - "time": "2022-03-03T08:28:38+00:00" + "time": "2022-12-30T00:23:10+00:00" }, { "name": "myclabs/deep-copy", - "version": "1.11.0", + "version": "1.11.1", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614" + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/14daed4296fae74d9e3201d2c4925d1acb7aa614", - "reference": "14daed4296fae74d9e3201d2c4925d1acb7aa614", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { @@ -828,7 +1028,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.11.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" }, "funding": [ { @@ -836,29 +1036,31 @@ "type": "tidelift" } ], - "time": "2022-03-03T13:19:32+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { "name": "nikic/php-parser", - "version": "v4.15.1", + "version": "v5.0.2", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900" + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", - "reference": "0ef6c55a3f47f89d7a374e6f835197a0b5fcf900", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/139676794dc1e9231bf7bcd123cfc0c99182cb13", + "reference": "139676794dc1e9231bf7bcd123cfc0c99182cb13", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "bin": [ "bin/php-parse" @@ -866,7 +1068,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -890,26 +1092,27 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.15.1" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.0.2" }, - "time": "2022-09-04T07:30:47+00:00" + "time": "2024-03-05T20:51:40+00:00" }, { "name": "phar-io/manifest", - "version": "2.0.3", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/phar-io/manifest.git", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53" + "reference": "54750ef60c58e43759730615a392c31c80e23176" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", - "reference": "97803eca37d319dfa7826cc2437fc020857acb53", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-phar": "*", "ext-xmlwriter": "*", "phar-io/version": "^3.0.1", @@ -950,9 +1153,15 @@ "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "support": { "issues": "https://github.com/phar-io/manifest/issues", - "source": "https://github.com/phar-io/manifest/tree/2.0.3" + "source": "https://github.com/phar-io/manifest/tree/2.0.4" }, - "time": "2021-07-20T11:28:43+00:00" + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" }, { "name": "phar-io/version", @@ -1007,27 +1216,25 @@ }, { "name": "php-stubs/wordpress-stubs", - "version": "v5.9.4", + "version": "v5.9.6", "source": { "type": "git", "url": "https://github.com/php-stubs/wordpress-stubs.git", - "reference": "3e481f4c8195fb3ca9e3e4e52e5305bf59c74cdb" + "reference": "6a18d938d0aef39d091505a4a35b025fb6c10098" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/3e481f4c8195fb3ca9e3e4e52e5305bf59c74cdb", - "reference": "3e481f4c8195fb3ca9e3e4e52e5305bf59c74cdb", + "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/6a18d938d0aef39d091505a4a35b025fb6c10098", + "reference": "6a18d938d0aef39d091505a4a35b025fb6c10098", "shasum": "" }, - "replace": { - "giacocorsiglia/wordpress-stubs": "*" - }, "require-dev": { "nikic/php-parser": "< 4.12.0", "php": "~7.3 || ~8.0", - "php-stubs/generator": "^0.8.1", + "php-stubs/generator": "^0.8.3", "phpdocumentor/reflection-docblock": "^5.3", - "phpstan/phpstan": "^1.2" + "phpstan/phpstan": "^1.10.12", + "phpunit/phpunit": "^9.5" }, "suggest": { "paragonie/sodium_compat": "Pure PHP implementation of libsodium", @@ -1048,22 +1255,22 @@ ], "support": { "issues": "https://github.com/php-stubs/wordpress-stubs/issues", - "source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.9.4" + "source": "https://github.com/php-stubs/wordpress-stubs/tree/v5.9.6" }, - "time": "2022-09-30T17:45:35+00:00" + "time": "2023-05-18T04:34:27+00:00" }, { "name": "phpstan/phpstan", - "version": "1.8.11", + "version": "1.10.60", "source": { "type": "git", "url": "https://github.com/phpstan/phpstan.git", - "reference": "46e223dd68a620da18855c23046ddb00940b4014" + "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpstan/zipball/46e223dd68a620da18855c23046ddb00940b4014", - "reference": "46e223dd68a620da18855c23046ddb00940b4014", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/95dcea7d6c628a3f2f56d091d8a0219485a86bbe", + "reference": "95dcea7d6c628a3f2f56d091d8a0219485a86bbe", "shasum": "" }, "require": { @@ -1092,8 +1299,11 @@ "static analysis" ], "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", "issues": "https://github.com/phpstan/phpstan/issues", - "source": "https://github.com/phpstan/phpstan/tree/1.8.11" + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" }, "funding": [ { @@ -1109,27 +1319,27 @@ "type": "tidelift" } ], - "time": "2022-10-24T15:45:13+00:00" + "time": "2024-03-07T13:30:19+00:00" }, { "name": "phpunit/php-code-coverage", - "version": "9.2.17", + "version": "9.2.31", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8" + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/aa94dc41e8661fe90c7316849907cba3007b10d8", - "reference": "aa94dc41e8661fe90c7316849907cba3007b10d8", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/48c34b5d8d983006bd2adc2d0de92963b9155965", + "reference": "48c34b5d8d983006bd2adc2d0de92963b9155965", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", "ext-xmlwriter": "*", - "nikic/php-parser": "^4.14", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3", "phpunit/php-file-iterator": "^3.0.3", "phpunit/php-text-template": "^2.0.2", @@ -1144,8 +1354,8 @@ "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-pcov": "*", - "ext-xdebug": "*" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { @@ -1178,7 +1388,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", - "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.17" + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.31" }, "funding": [ { @@ -1186,7 +1397,7 @@ "type": "github" } ], - "time": "2022-08-30T12:24:04+00:00" + "time": "2024-03-02T06:37:42+00:00" }, { "name": "phpunit/php-file-iterator", @@ -1431,20 +1642,20 @@ }, { "name": "phpunit/phpunit", - "version": "9.5.25", + "version": "9.6.17", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d" + "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", - "reference": "3e6f90ca7e3d02025b1d147bd8d4a89fd4ca8a1d", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd", + "reference": "1a156980d78a6666721b7e8e8502fe210b587fcd", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.3.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", @@ -1455,7 +1666,7 @@ "phar-io/manifest": "^2.0.3", "phar-io/version": "^3.0.2", "php": ">=7.3", - "phpunit/php-code-coverage": "^9.2.13", + "phpunit/php-code-coverage": "^9.2.28", "phpunit/php-file-iterator": "^3.0.5", "phpunit/php-invoker": "^3.1.1", "phpunit/php-text-template": "^2.0.3", @@ -1473,8 +1684,8 @@ "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -1482,7 +1693,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "9.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { @@ -1513,7 +1724,8 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.5.25" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17" }, "funding": [ { @@ -1529,20 +1741,20 @@ "type": "tidelift" } ], - "time": "2022-09-25T03:44:45+00:00" + "time": "2024-02-23T13:14:51+00:00" }, { "name": "sebastian/cli-parser", - "version": "1.0.1", + "version": "1.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/cli-parser.git", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", - "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/2b56bea83a09de3ac06bb18b92f068e60cc6f50b", + "reference": "2b56bea83a09de3ac06bb18b92f068e60cc6f50b", "shasum": "" }, "require": { @@ -1577,7 +1789,7 @@ "homepage": "https://github.com/sebastianbergmann/cli-parser", "support": { "issues": "https://github.com/sebastianbergmann/cli-parser/issues", - "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.2" }, "funding": [ { @@ -1585,7 +1797,7 @@ "type": "github" } ], - "time": "2020-09-28T06:08:49+00:00" + "time": "2024-03-02T06:27:43+00:00" }, { "name": "sebastian/code-unit", @@ -1774,20 +1986,20 @@ }, { "name": "sebastian/complexity", - "version": "2.0.2", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/complexity.git", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", - "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a", + "reference": "25f207c40d62b8b7aa32f5ab026c53561964053a", "shasum": "" }, "require": { - "nikic/php-parser": "^4.7", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -1819,7 +2031,7 @@ "homepage": "https://github.com/sebastianbergmann/complexity", "support": { "issues": "https://github.com/sebastianbergmann/complexity/issues", - "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3" }, "funding": [ { @@ -1827,20 +2039,20 @@ "type": "github" } ], - "time": "2020-10-26T15:52:27+00:00" + "time": "2023-12-22T06:19:30+00:00" }, { "name": "sebastian/diff", - "version": "4.0.4", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d" + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/3461e3fccc7cfdfc2720be910d3bd73c69be590d", - "reference": "3461e3fccc7cfdfc2720be910d3bd73c69be590d", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/ba01945089c3a293b01ba9badc29ad55b106b0bc", + "reference": "ba01945089c3a293b01ba9badc29ad55b106b0bc", "shasum": "" }, "require": { @@ -1885,7 +2097,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/diff/issues", - "source": "https://github.com/sebastianbergmann/diff/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.6" }, "funding": [ { @@ -1893,20 +2105,20 @@ "type": "github" } ], - "time": "2020-10-26T13:10:38+00:00" + "time": "2024-03-02T06:30:58+00:00" }, { "name": "sebastian/environment", - "version": "5.1.4", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/1b5dff7bb151a4db11d49d90e5408e4e938270f7", - "reference": "1b5dff7bb151a4db11d49d90e5408e4e938270f7", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { @@ -1948,7 +2160,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/environment/issues", - "source": "https://github.com/sebastianbergmann/environment/tree/5.1.4" + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" }, "funding": [ { @@ -1956,20 +2168,20 @@ "type": "github" } ], - "time": "2022-04-03T09:37:03+00:00" + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "4.0.5", + "version": "4.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", - "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/78c00df8f170e02473b682df15bfcdacc3d32d72", + "reference": "78c00df8f170e02473b682df15bfcdacc3d32d72", "shasum": "" }, "require": { @@ -2025,7 +2237,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/exporter/issues", - "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.6" }, "funding": [ { @@ -2033,20 +2245,20 @@ "type": "github" } ], - "time": "2022-09-14T06:03:37+00:00" + "time": "2024-03-02T06:33:00+00:00" }, { "name": "sebastian/global-state", - "version": "5.0.5", + "version": "5.0.7", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2" + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/0ca8db5a5fc9c8646244e629625ac486fa286bf2", - "reference": "0ca8db5a5fc9c8646244e629625ac486fa286bf2", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", + "reference": "bca7df1f32ee6fe93b4d4a9abbf69e13a4ada2c9", "shasum": "" }, "require": { @@ -2089,7 +2301,7 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/global-state/issues", - "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.5" + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.7" }, "funding": [ { @@ -2097,24 +2309,24 @@ "type": "github" } ], - "time": "2022-02-14T08:28:10+00:00" + "time": "2024-03-02T06:35:11+00:00" }, { "name": "sebastian/lines-of-code", - "version": "1.0.3", + "version": "1.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/lines-of-code.git", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", - "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5", + "reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5", "shasum": "" }, "require": { - "nikic/php-parser": "^4.6", + "nikic/php-parser": "^4.18 || ^5.0", "php": ">=7.3" }, "require-dev": { @@ -2146,7 +2358,7 @@ "homepage": "https://github.com/sebastianbergmann/lines-of-code", "support": { "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", - "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4" }, "funding": [ { @@ -2154,7 +2366,7 @@ "type": "github" } ], - "time": "2020-11-28T06:42:11+00:00" + "time": "2023-12-22T06:20:34+00:00" }, { "name": "sebastian/object-enumerator", @@ -2270,16 +2482,16 @@ }, { "name": "sebastian/recursion-context", - "version": "4.0.4", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/cd9d8cf3c5804de4341c283ed787f099f5506172", - "reference": "cd9d8cf3c5804de4341c283ed787f099f5506172", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { @@ -2318,10 +2530,10 @@ } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.4" + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" }, "funding": [ { @@ -2329,7 +2541,7 @@ "type": "github" } ], - "time": "2020-10-26T13:17:30+00:00" + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", @@ -2388,16 +2600,16 @@ }, { "name": "sebastian/type", - "version": "3.2.0", + "version": "3.2.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/type.git", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e" + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", - "reference": "fb3fe09c5f0bae6bc27ef3ce933a1e0ed9464b6e", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", "shasum": "" }, "require": { @@ -2432,7 +2644,7 @@ "homepage": "https://github.com/sebastianbergmann/type", "support": { "issues": "https://github.com/sebastianbergmann/type/issues", - "source": "https://github.com/sebastianbergmann/type/tree/3.2.0" + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" }, "funding": [ { @@ -2440,7 +2652,7 @@ "type": "github" } ], - "time": "2022-09-12T14:47:03+00:00" + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", @@ -2497,16 +2709,16 @@ }, { "name": "squizlabs/php_codesniffer", - "version": "3.7.1", + "version": "3.9.0", "source": { "type": "git", - "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619" + "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/1359e176e9307e906dc3d890bcc9603ff6d90619", - "reference": "1359e176e9307e906dc3d890bcc9603ff6d90619", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/d63cee4890a8afaf86a22e51ad4d97c91dd4579b", + "reference": "d63cee4890a8afaf86a22e51ad4d97c91dd4579b", "shasum": "" }, "require": { @@ -2516,11 +2728,11 @@ "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" }, "bin": [ - "bin/phpcs", - "bin/phpcbf" + "bin/phpcbf", + "bin/phpcs" ], "type": "library", "extra": { @@ -2535,34 +2747,58 @@ "authors": [ { "name": "Greg Sherwood", - "role": "lead" + "role": "Former lead" + }, + { + "name": "Juliette Reinders Folmer", + "role": "Current lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer/graphs/contributors" } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", + "homepage": "https://github.com/PHPCSStandards/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], "support": { - "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", - "source": "https://github.com/squizlabs/PHP_CodeSniffer", - "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + "issues": "https://github.com/PHPCSStandards/PHP_CodeSniffer/issues", + "security": "https://github.com/PHPCSStandards/PHP_CodeSniffer/security/policy", + "source": "https://github.com/PHPCSStandards/PHP_CodeSniffer", + "wiki": "https://github.com/PHPCSStandards/PHP_CodeSniffer/wiki" }, - "time": "2022-06-18T07:21:10+00:00" + "funding": [ + { + "url": "https://github.com/PHPCSStandards", + "type": "github" + }, + { + "url": "https://github.com/jrfnl", + "type": "github" + }, + { + "url": "https://opencollective.com/php_codesniffer", + "type": "open_collective" + } + ], + "time": "2024-02-16T15:06:51+00:00" }, { "name": "symfony/polyfill-php73", - "version": "v1.26.0", + "version": "v1.29.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php73.git", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85" + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/e440d35fa0286f77fb45b79a03fedbeda9307e85", - "reference": "e440d35fa0286f77fb45b79a03fedbeda9307e85", + "url": "https://api.github.com/repos/symfony/polyfill-php73/zipball/21bd091060673a1177ae842c0ef8fe30893114d2", + "reference": "21bd091060673a1177ae842c0ef8fe30893114d2", "shasum": "" }, "require": { @@ -2570,9 +2806,6 @@ }, "type": "library", "extra": { - "branch-alias": { - "dev-main": "1.26-dev" - }, "thanks": { "name": "symfony/polyfill", "url": "https://github.com/symfony/polyfill" @@ -2612,7 +2845,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php73/tree/v1.26.0" + "source": "https://github.com/symfony/polyfill-php73/tree/v1.29.0" }, "funding": [ { @@ -2628,35 +2861,38 @@ "type": "tidelift" } ], - "time": "2022-05-24T11:49:31+00:00" + "time": "2024-01-29T20:11:03+00:00" }, { "name": "szepeviktor/phpstan-wordpress", - "version": "v1.1.3", + "version": "v1.3.3", "source": { "type": "git", "url": "https://github.com/szepeviktor/phpstan-wordpress.git", - "reference": "e644df734e1bbe95810e0f617d17df091048a94e" + "reference": "f7ff091331bc00c5688fe4ce0c4d51d06fa61553" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/e644df734e1bbe95810e0f617d17df091048a94e", - "reference": "e644df734e1bbe95810e0f617d17df091048a94e", + "url": "https://api.github.com/repos/szepeviktor/phpstan-wordpress/zipball/f7ff091331bc00c5688fe4ce0c4d51d06fa61553", + "reference": "f7ff091331bc00c5688fe4ce0c4d51d06fa61553", "shasum": "" }, "require": { "php": "^7.2 || ^8.0", "php-stubs/wordpress-stubs": "^4.7 || ^5.0 || ^6.0", - "phpstan/phpstan": "^1.6", + "phpstan/phpstan": "^1.10.31", "symfony/polyfill-php73": "^1.12.0" }, "require-dev": { "composer/composer": "^2.1.14", - "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", "php-parallel-lint/php-parallel-lint": "^1.1", "phpstan/phpstan-strict-rules": "^1.2", - "phpunit/phpunit": "^8 || ^9", - "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^0.6" + "phpunit/phpunit": "^8.0 || ^9.0", + "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^0.8" + }, + "suggest": { + "swissspidy/phpstan-no-private": "Detect usage of internal core functions, classes and methods" }, "type": "phpstan-extension", "extra": { @@ -2685,32 +2921,22 @@ ], "support": { "issues": "https://github.com/szepeviktor/phpstan-wordpress/issues", - "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v1.1.3" + "source": "https://github.com/szepeviktor/phpstan-wordpress/tree/v1.3.3" }, - "funding": [ - { - "url": "https://www.paypal.me/szepeviktor", - "type": "custom" - }, - { - "url": "https://github.com/szepeviktor", - "type": "github" - } - ], - "time": "2022-09-22T13:14:50+00:00" + "time": "2024-02-26T13:55:50+00:00" }, { "name": "theseer/tokenizer", - "version": "1.2.1", + "version": "1.2.3", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", - "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", "shasum": "" }, "require": { @@ -2739,7 +2965,7 @@ "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "support": { "issues": "https://github.com/theseer/tokenizer/issues", - "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" }, "funding": [ { @@ -2747,7 +2973,7 @@ "type": "github" } ], - "time": "2021-07-28T10:34:58+00:00" + "time": "2024-03-03T12:36:25+00:00" }, { "name": "wp-coding-standards/wpcs", @@ -2802,16 +3028,16 @@ }, { "name": "yoast/phpunit-polyfills", - "version": "1.0.3", + "version": "1.1.0", "source": { "type": "git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", - "reference": "5ea3536428944955f969bc764bbe09738e151ada" + "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/5ea3536428944955f969bc764bbe09738e151ada", - "reference": "5ea3536428944955f969bc764bbe09738e151ada", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/224e4a1329c03d8bad520e3fc4ec980034a4b212", + "reference": "224e4a1329c03d8bad520e3fc4ec980034a4b212", "shasum": "" }, "require": { @@ -2819,13 +3045,12 @@ "phpunit/phpunit": "^4.8.36 || ^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0" }, "require-dev": { - "yoast/yoastcs": "^2.2.0" + "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": { @@ -2859,7 +3084,7 @@ "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", "source": "https://github.com/Yoast/PHPUnit-Polyfills" }, - "time": "2021-11-23T01:37:03+00:00" + "time": "2023-08-19T14:25:08+00:00" } ], "aliases": [], @@ -2868,8 +3093,8 @@ "prefer-stable": true, "prefer-lowest": false, "platform": { - "php": "^7.3|^8.0" + "php": "^8.1" }, "platform-dev": [], - "plugin-api-version": "2.3.0" + "plugin-api-version": "2.6.0" } diff --git a/src/Helpers/Plugin.php b/src/Helpers/Plugin.php new file mode 100644 index 0000000..49cdcb9 --- /dev/null +++ b/src/Helpers/Plugin.php @@ -0,0 +1,130 @@ + + * @copyright 2020 Studio Meta + * @license https://opensource.org/licenses/MIT + * @since 2.0.0 + * @version 2.0.0 + */ + + +namespace Studiometa\WPToolkit\Helpers; + +use function WeCodeMore\earlyAddFilter as early_add_filter; + +/** + * Plugins class. + */ +class Plugin { + + /** + * Disabled plugins. + * + * @var string[] + */ + private static $disabled_plugins = array(); + + /** + * Class instance. + * @var self + */ + private static $instance = null; + + /** + * Hook into the activation filters on construction. + */ + private function __construct( ) { + early_add_filter( + 'option_active_plugins', + function( array $plugins ) { + return self::do_disabling( $plugins ); + } + ); + early_add_filter( + 'site_option_active_sitewide_plugins', + function( array $plugins ) { + return self::do_network_disabling( $plugins ); + } + ); + } + + /** + * Hooks in to the option_active_plugins filter and does the disabling + * + * @param string[] $plugins WP-provided list of plugin filenames. + * + * @return string[] The filtered array of plugin filenames + */ + private static function do_disabling( array $plugins ): array { + if ( count( self::$disabled_plugins ) ) { + foreach ( self::$disabled_plugins as $disabled_plugin ) { + $key = array_search( $disabled_plugin, $plugins, true ); + if ( false !== $key ) { + unset( $plugins[ $key ] ); + } + } + } + + return $plugins; + } + + /** + * Hooks in to the site_option_active_sitewide_plugins filter and does the disabling + * + * @param string[] $plugins Plugins. + * + * @return string[] + */ + private static function do_network_disabling( $plugins ) { + if ( count( self::$disabled_plugins ) ) { + foreach ( (array) self::$disabled_plugins as $plugin ) { + if ( isset( $plugins[ $plugin ] ) ) { + unset( $plugins[ $plugin ] ); + } + } + } + + return $plugins; + } + + /** + * Disable a list of plugins. + * + * @param string[] $plugins The list of plugins to disable. + */ + public static function disable( array $plugins ): void { + self::$disabled_plugins = self::$disabled_plugins + $plugins; + + if ( is_null( self::$instance) ) { + self::$instance = new self(); + } + } + + /** + * Test if plugin is enabled. + * + * @param string $filepath Plugin filepath (relative to plugins folder). + * + * @codeCoverageIgnore + * + * @return boolean Is the plugin enabled? + */ + public static function is_plugin_enabled( string $filepath ):bool { + $cache_key = __FUNCTION__ . md5( $filepath ); + $cached_results = wp_cache_get( $cache_key, __CLASS__ ); + + if ( false !== $cached_results ) { + return (bool) $cached_results; + } + + $is_enabled = is_plugin_active( $filepath ); + + wp_cache_set( $cache_key, (int) $is_enabled, __CLASS__ ); + + return $is_enabled; + } +} diff --git a/src/Helpers/PluginHelper.php b/src/Helpers/PluginHelper.php deleted file mode 100644 index e26564e..0000000 --- a/src/Helpers/PluginHelper.php +++ /dev/null @@ -1,42 +0,0 @@ - - * @copyright 2021 Studio Meta - * @license https://opensource.org/licenses/MIT - * @since 1.0.0 - * @version 1.0.0 - */ - -namespace Studiometa\WPToolkit\Helpers; - -/** - * Plugin helper class. - */ -class PluginHelper { - /** - * Test if plugin is enabled. - * - * @param string $filepath Plugin filepath (relative to plugins folder). - * - * @codeCoverageIgnore - * - * @return boolean Is plugin enabled? - */ - public static function is_plugin_enabled( string $filepath ):bool { - $cache_key = __FUNCTION__ . md5( $filepath ); - $cached_results = wp_cache_get( $cache_key, __CLASS__ ); - - if ( false !== $cached_results ) { - return (bool) $cached_results; - } - - $is_enabled = is_plugin_active( $filepath ); - - wp_cache_set( $cache_key, (int) $is_enabled, __CLASS__ ); - - return $is_enabled; - } -} diff --git a/tests/Helpers/PluginHelper.php b/tests/Helpers/PluginHelper.php deleted file mode 100644 index b50b27f..0000000 --- a/tests/Helpers/PluginHelper.php +++ /dev/null @@ -1,19 +0,0 @@ -assertTrue( - is_bool( PluginHelper::is_plugin_enabled( 'my-plugin/my-plugin.php' ) ) - ); - } -} diff --git a/tests/Helpers/PluginTest.php b/tests/Helpers/PluginTest.php new file mode 100644 index 0000000..22be2ac --- /dev/null +++ b/tests/Helpers/PluginTest.php @@ -0,0 +1,36 @@ +assertTrue( + is_bool( Plugin::is_plugin_enabled( 'my-plugin/my-plugin.php' ) ) + ); + } + + /** + * Test the `disable` method. + * + * @return void + */ + public function test_plugins_have_been_disabled() { + $this->assertTrue( is_plugin_active( 'akismet/akismet.php' ) ); + Plugin::disable( array( 'akismet/akismet.php' ) ); + $this->assertFalse( is_plugin_active( 'akismet/akismet.php' ) ); + } +} From 7c460f5d44faccc37bb3c8b0050a4d93b7cc89fb Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 15:52:53 +0100 Subject: [PATCH 05/25] Fix ddev test setup --- .ddev/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ddev/config.yaml b/.ddev/config.yaml index 808b3d4..ff17ac7 100644 --- a/.ddev/config.yaml +++ b/.ddev/config.yaml @@ -14,7 +14,7 @@ database: hooks: post-start: - exec: sudo apt-get update && sudo apt-get install subversion -y - - exec: ./bin/install-wp-tests.sh wordpress_test root root db latest + - exec: ./bin/install-wp-tests.sh db db db db latest use_dns_when_possible: true composer_version: '2' web_environment: From 8671d1347d31fdb013323e835da60429e551de71 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:01:05 +0100 Subject: [PATCH 06/25] Add env helpers --- src/Helpers/Env.php | 20 ++++++++++++++ src/Helpers/Request.php | 50 +++++++++++++++++++++++++++++++++++ src/helpers.php | 33 +++++++++++++++++++++++ tests/Helpers/EnvTest.php | 20 ++++++++++++++ tests/Helpers/RequestTest.php | 24 +++++++++++++++++ 5 files changed, 147 insertions(+) create mode 100644 src/Helpers/Env.php create mode 100644 src/Helpers/Request.php create mode 100644 src/helpers.php create mode 100644 tests/Helpers/EnvTest.php create mode 100644 tests/Helpers/RequestTest.php diff --git a/src/Helpers/Env.php b/src/Helpers/Env.php new file mode 100644 index 0000000..78876b6 --- /dev/null +++ b/src/Helpers/Env.php @@ -0,0 +1,20 @@ + Good type. */ + $env = $_ENV; + // In some environment, values are not available in the `$_ENV` variables, + // so we use `getenv` as a fallback to try and get the value. + return $env[ $key ] ?? (string) getenv( $key ); + } +} diff --git a/src/Helpers/Request.php b/src/Helpers/Request.php new file mode 100644 index 0000000..3dc3eaa --- /dev/null +++ b/src/Helpers/Request.php @@ -0,0 +1,50 @@ +request = SymfonyRequest::createFromGlobals(); + } + + /** + * Get singleton instance. + * + * @return Request + */ + private static function get_instance() { + if ( is_null( self::$instance ) ) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Work with the current HTTP request. + * + * @return SymfonyRequest + */ + public static function request(): SymfonyRequest { + return self::get_instance()->request; + } +} diff --git a/src/helpers.php b/src/helpers.php new file mode 100644 index 0000000..dc3fc66 --- /dev/null +++ b/src/helpers.php @@ -0,0 +1,33 @@ +assertTrue(is_string(env('missing'))); + $this->assertTrue(is_string(EnvClass::get('missing'))); + } +} diff --git a/tests/Helpers/RequestTest.php b/tests/Helpers/RequestTest.php new file mode 100644 index 0000000..0b39486 --- /dev/null +++ b/tests/Helpers/RequestTest.php @@ -0,0 +1,24 @@ +assertTrue($request1 instanceof SymfonyRequest); + $this->assertTrue($request2 instanceof SymfonyRequest); + $this->assertTrue($request1 === $request2); + } +} From 172b5b450c01cc857bd45d07eac6eba790c0a9e4 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:44:13 +0100 Subject: [PATCH 07/25] Update changelog --- CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c665759..d77ed8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,4 +8,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added +- Add a `Plugin::disable` method to the `Plugin` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `request` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `Request` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `env` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) +- Add a `Env` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) + +### Changed + +- ⚠️ Rename the `PluginHelper` class to `Plugin` ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - **CleanupManager:** Disable XML-RPC by default ([#21](https://github.com/studiometa/wp-toolkit/pull/21)) From 09dac667de13e2397b424fb2322e74260385b9b1 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:44:50 +0100 Subject: [PATCH 08/25] Improve linting --- .editorconfig | 2 +- composer.json | 15 +- composer.lock | 53 +- phpcs.xml | 31 +- phpstan.neon | 2 + src/Builders/Builder.php | 255 +++++----- src/Builders/PostTypeBuilder.php | 667 ++++++++++++++------------ src/Builders/TaxonomyBuilder.php | 613 ++++++++++++----------- src/Helpers/Env.php | 28 +- src/Helpers/Plugin.php | 222 ++++----- src/Helpers/Request.php | 90 ++-- src/Managers/AssetsManager.php | 658 ++++++++++++------------- src/Managers/CleanupManager.php | 330 +++++++------ src/Managers/ManagerFactory.php | 26 +- src/Managers/ManagerInterface.php | 15 +- src/TransientCleaner.php | 558 ++++++++++----------- src/helpers.php | 10 +- tests/Builder/PostTypeBuilderTest.php | 77 +-- tests/Builder/TaxonomyBuilderTest.php | 104 ++-- tests/Helpers/EnvTest.php | 25 +- tests/Helpers/PluginTest.php | 57 ++- tests/Helpers/RequestTest.php | 31 +- tests/Managers/AssetsManagerTest.php | 159 +++--- tests/Managers/CleanupManagerTest.php | 89 ++-- tests/Managers/ManagerFactoryTest.php | 55 ++- tests/TransientCleanerTest.php | 353 +++++++------- tests/bootstrap.php | 14 +- 27 files changed, 2346 insertions(+), 2193 deletions(-) diff --git a/.editorconfig b/.editorconfig index bb112e1..c8561cc 100644 --- a/.editorconfig +++ b/.editorconfig @@ -13,4 +13,4 @@ insert_final_newline = true trim_trailing_whitespace = false [*.php] -indent_style = tab +indent_size = 4 diff --git a/composer.json b/composer.json index da68da2..6b7679a 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,6 @@ }, "require-dev": { "squizlabs/php_codesniffer": "^3.4", - "wp-coding-standards/wpcs": "^2.1", "dealerdirect/phpcodesniffer-composer-installer": "^0.7.0", "szepeviktor/phpstan-wordpress": "^1.1", "php-stubs/wordpress-stubs": "^5.5", @@ -29,9 +28,17 @@ ] }, "scripts": { - "phpcs": "phpcs -s --colors --standard=./phpcs.xml", - "phpstan": "phpstan analyse --memory-limit=512M", - "phpunit": "phpunit" + "lint": [ + "@lint:style", + "@lint:static" + ], + "lint:style": "phpcs", + "lint:static": "phpstan analyse --memory-limit=512M", + "fix": [ + "@fix:style" + ], + "fix:style": "phpcbf", + "test": "phpunit" }, "minimum-stability": "dev", "prefer-stable": true, diff --git a/composer.lock b/composer.lock index d3e54f9..405f3e3 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "58321d066b07ecb11928cd5e68e5d563", + "content-hash": "f46208b8750d1d7d0f6a899a2cf219b8", "packages": [ { "name": "anahkiasen/html-object", @@ -2975,57 +2975,6 @@ ], "time": "2024-03-03T12:36:25+00:00" }, - { - "name": "wp-coding-standards/wpcs", - "version": "2.3.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7da1894633f168fe244afc6de00d141f27517b62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", - "reference": "7da1894633f168fe244afc6de00d141f27517b62", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", - "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.0", - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Contributors", - "homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", - "keywords": [ - "phpcs", - "standards", - "wordpress" - ], - "support": { - "issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues", - "source": "https://github.com/WordPress/WordPress-Coding-Standards", - "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" - }, - "time": "2020-05-13T23:57:56+00:00" - }, { "name": "yoast/phpunit-polyfills", "version": "1.1.0", diff --git a/phpcs.xml b/phpcs.xml index d2926a8..4f907dd 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -1,5 +1,10 @@ + + + + + ./src/ ./tests/ @@ -7,33 +12,17 @@ /vendor/ - - - - - - + - - - - - - - - - - */tests/* + + - + */tests/* - + */tests/* diff --git a/phpstan.neon b/phpstan.neon index a027ab3..e94f403 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -3,6 +3,8 @@ includes: parameters: level: max + cache: + nodesByStringCountMax: 512 inferPrivatePropertyTypeFromConstructor: true checkMissingIterableValueType: false reportUnmatchedIgnoredErrors: false diff --git a/src/Builders/Builder.php b/src/Builders/Builder.php index fdc5580..0e78715 100644 --- a/src/Builders/Builder.php +++ b/src/Builders/Builder.php @@ -15,127 +15,136 @@ /** * Cleanup a WordPress project for security and performance. */ -abstract class Builder { - /** - * The post type key. - * - * @var string - */ - private $type; - - /** - * The post type configuration. - * - * @var array - */ - private $config = array(); - - /** - * The post type configuration. - * - * @var array - */ - public $default_config = array(); - - /** - * The method used to register the builder. - * - * @var string - */ - public $register_method = ''; - - /** - * The key for the register method arguments. - * - * @var array - */ - public $register_method_args = array(); - - /** - * __construct - * - * @param string $type The post type key. - * @param array $config A config for the builder. - */ - public function __construct( string $type, array $config = array() ) { - $this->type = $type; - - if ( is_array( $this->default_config ) ) { - $this->update_config( $this->default_config ); - } - - $this->update_config( $config ); - } - - /** - * Build the post type configuration. - * - * @return array The post type configuration. - */ - public function get_config():array { - return $this->config; - } - - /** - * Set a config key -> value pair. - * - * @param string $key The key to set. - * @param mixed $value The value to set. - * @return $this - */ - public function set_config( string $key, $value ) { - return $this->update_config( array( $key => $value ) ); - } - - /** - * Update multiple config values. - * - * @param array $config The config to merge. - * @return $this - */ - public function update_config( $config ) { - $this->config = array_merge( $this->config, $config ); - return $this; - } - - /** - * Get the register method name. - * - * @return string The register method name. - */ - private function get_register_method():string { - return $this->register_method; - } - - /** - * Get the register method argument names. - * - * @return array The register method name. - */ - private function get_register_method_args():array { - return $this->register_method_args; - } - - /** - * Get an instance property value. - * - * @param string $key The property to get. - * @return mixed The property value. - */ - private function get( string $key ) { - return $this->{$key}; - } - - /** - * Register the post type. - * - * @return void - */ - public function register():void { - $register_method = $this->get_register_method(); - if ( $register_method && is_callable( $register_method ) ) { - $args = array_map( array( $this, 'get' ), $this->get_register_method_args() ); - $register_method( ...$args ); - } - } +abstract class Builder +{ + /** + * The post type key. + * + * @var string + */ + private $type; + + /** + * The post type configuration. + * + * @var array + */ + private $config = array(); + + /** + * The post type configuration. + * + * @var array + */ + public $default_config = array(); + + /** + * The method used to register the builder. + * + * @var string + */ + public $register_method = ''; + + /** + * The key for the register method arguments. + * + * @var array + */ + public $register_method_args = array(); + + /** + * __construct + * + * @param string $type The post type key. + * @param array $config A config for the builder. + */ + public function __construct(string $type, array $config = array()) + { + $this->type = $type; + + if (is_array($this->default_config)) { + $this->update_config($this->default_config); + } + + $this->update_config($config); + } + + /** + * Build the post type configuration. + * + * @return array The post type configuration. + */ + public function get_config():array + { + return $this->config; + } + + /** + * Set a config key -> value pair. + * + * @param string $key The key to set. + * @param mixed $value The value to set. + * @return $this + */ + public function set_config(string $key, $value) + { + return $this->update_config(array( $key => $value )); + } + + /** + * Update multiple config values. + * + * @param array $config The config to merge. + * @return $this + */ + public function update_config($config) + { + $this->config = array_merge($this->config, $config); + return $this; + } + + /** + * Get the register method name. + * + * @return string The register method name. + */ + private function get_register_method():string + { + return $this->register_method; + } + + /** + * Get the register method argument names. + * + * @return array The register method name. + */ + private function get_register_method_args():array + { + return $this->register_method_args; + } + + /** + * Get an instance property value. + * + * @param string $key The property to get. + * @return mixed The property value. + */ + private function get(string $key) + { + return $this->{$key}; + } + + /** + * Register the post type. + * + * @return void + */ + public function register():void + { + $register_method = $this->get_register_method(); + if ($register_method && is_callable($register_method)) { + $args = array_map(array( $this, 'get' ), $this->get_register_method_args()); + $register_method(...$args); + } + } } diff --git a/src/Builders/PostTypeBuilder.php b/src/Builders/PostTypeBuilder.php index 8e66a6a..dd66e95 100644 --- a/src/Builders/PostTypeBuilder.php +++ b/src/Builders/PostTypeBuilder.php @@ -15,351 +15,386 @@ /** * Build a custom post type. */ -class PostTypeBuilder extends Builder { - /** - * The post type configuration. - * - * @var array - */ - public $default_config = array( - 'public' => true, - 'show_in_rest' => false, - 'menu_position' => null, - 'has_archive' => false, - 'supports' => array( 'title', 'editor', 'thumbnail' ), - 'can_export' => true, - 'delete_with_user' => null, - ); +class PostTypeBuilder extends Builder +{ + /** + * The post type configuration. + * + * @var array + */ + public $default_config = array( + 'public' => true, + 'show_in_rest' => false, + 'menu_position' => null, + 'has_archive' => false, + 'supports' => array( 'title', 'editor', 'thumbnail' ), + 'can_export' => true, + 'delete_with_user' => null, + ); - /** - * The register method name. - * - * @var string - */ - public $register_method = 'register_post_type'; + /** + * The register method name. + * + * @var string + */ + public $register_method = 'register_post_type'; - /** - * The register method args. - * - * @var array - */ - public $register_method_args = array( 'type', 'config' ); + /** + * The register method args. + * + * @var array + */ + public $register_method_args = array( 'type', 'config' ); - /** - * Name of the post type shown in the menu. Usually plural. Default is value of $labels['name']. - * - * @param string $label The post type label. - */ - public function set_label( string $label ):self { - return $this->set_config( 'label', $label ); - } + /** + * Name of the post type shown in the menu. Usually plural. Default is value of $labels['name']. + * + * @param string $label The post type label. + */ + public function set_label(string $label):self + { + return $this->set_config('label', $label); + } - /** - * An array of labels for this post type. If not set, post labels are inherited for non-hierarchical types and page - * labels for hierarchical ones. - * - * @param string $singular The singular label. - * @param string $plural The plural label. - */ - public function set_labels( string $singular, string $plural ):self { - return $this->set_config( 'labels', $this->generate_labels( $singular, $plural ) ); - } + /** + * An array of labels for this post type. If not set, post labels are inherited for non-hierarchical types and page + * labels for hierarchical ones. + * + * @param string $singular The singular label. + * @param string $plural The plural label. + */ + public function set_labels(string $singular, string $plural):self + { + return $this->set_config('labels', $this->generate_labels($singular, $plural)); + } - /** - * Generate labels. - * - * @param string $singular Singular name. - * @param string $plural Plural name. - * @return array Labels. - */ - private function generate_labels( string $singular, string $plural ):array { + /** + * Generate labels. + * + * @param string $singular Singular name. + * @param string $plural Plural name. + * @return array Labels. + */ + private function generate_labels(string $singular, string $plural):array + { // phpcs:disable WordPress.WP.I18n - $labels = array( - 'name' => $plural, - 'singular_name' => $singular, - 'add_new' => sprintf( __( 'Add New %s', 'studiometa' ), $singular ), - 'add_new_item' => sprintf( __( 'Add New %s', 'studiometa' ), $singular ), - 'edit_item' => sprintf( __( 'Edit %s', 'studiometa' ), $singular ), - 'new_item' => sprintf( __( 'New %s', 'studiometa' ), $singular ), - 'all_items' => sprintf( __( 'All %s', 'studiometa' ), $plural ), - 'view_item' => sprintf( __( 'View %s', 'studiometa' ), $singular ), - 'search_items' => sprintf( __( 'Search %s', 'studiometa' ), $plural ), - 'not_found' => sprintf( __( 'No %s', 'studiometa' ), $plural ), - 'not_found_in_trash' => sprintf( __( 'No %s found in Trash', 'studiometa' ), $plural ), - 'parent_item_colon' => isset( $this->get_config()['hierarchical'] ) && $this->get_config()['hierarchical'] ? sprintf( __( 'Parent %s:', 'studiometa' ), $singular ) : null, - 'menu_name' => $plural, - 'insert_into_item' => sprintf( __( 'Insert into %s', 'studiometa' ), strtolower( $singular ) ), - 'uploaded_to_this_item' => sprintf( __( 'Uploaded to this %s', 'studiometa' ), strtolower( $singular ) ), - 'items_list' => sprintf( __( '%s list', 'studiometa' ), $plural ), - 'items_list_navigation' => sprintf( __( '%s list navigation', 'studiometa' ), $plural ), - 'filter_items_list' => sprintf( __( 'Filter %s list', 'studiometa' ), strtolower( $plural ) ), - ); + $labels = array( + 'name' => $plural, + 'singular_name' => $singular, + 'add_new' => sprintf(__('Add New %s', 'studiometa'), $singular), + 'add_new_item' => sprintf(__('Add New %s', 'studiometa'), $singular), + 'edit_item' => sprintf(__('Edit %s', 'studiometa'), $singular), + 'new_item' => sprintf(__('New %s', 'studiometa'), $singular), + 'all_items' => sprintf(__('All %s', 'studiometa'), $plural), + 'view_item' => sprintf(__('View %s', 'studiometa'), $singular), + 'search_items' => sprintf(__('Search %s', 'studiometa'), $plural), + 'not_found' => sprintf(__('No %s', 'studiometa'), $plural), + 'not_found_in_trash' => sprintf(__('No %s found in Trash', 'studiometa'), $plural), + 'parent_item_colon' => isset($this->get_config()['hierarchical']) && $this->get_config()['hierarchical'] + ? sprintf(__('Parent %s:', 'studiometa'), $singular) + : null, + 'menu_name' => $plural, + 'insert_into_item' => sprintf(__('Insert into %s', 'studiometa'), strtolower($singular)), + 'uploaded_to_this_item' => sprintf(__('Uploaded to this %s', 'studiometa'), strtolower($singular)), + 'items_list' => sprintf(__('%s list', 'studiometa'), $plural), + 'items_list_navigation' => sprintf(__('%s list navigation', 'studiometa'), $plural), + 'filter_items_list' => sprintf(__('Filter %s list', 'studiometa'), strtolower($plural)), + ); // phpcs:enable - return $labels; - } + return $labels; + } - /** - * A short descriptive summary of what the post type is. - * - * @param string $description The description. - * @return PostTypeBuilder - */ - public function set_description( string $description ) { - return $this->set_config( 'description', $description ); - } + /** + * A short descriptive summary of what the post type is. + * + * @param string $description The description. + * @return PostTypeBuilder + */ + public function set_description(string $description) + { + return $this->set_config('description', $description); + } - /** - * Whether a post type is intended for use publicly either via the admin interface or by front-end users. While the - * default settings of $exclude_from_search, $publicly_queryable, $show_ui, and $show_in_nav_menus are inherited from - * public, each does not rely on this relationship and controls a very specific intention. Default false. - * - * @param bool $is_public Is it public or not. - * @return PostTypeBuilder - */ - public function set_public( bool $is_public ) { - return $this->set_config( 'public', $is_public ); - } + /** + * Whether a post type is intended for use publicly either via the admin interface or by front-end users. While the + * default settings of $exclude_from_search, $publicly_queryable, $show_ui, and $show_in_nav_menus are inherited + * from public, each does not rely on this relationship and controls a very specific intention. Default false. + * + * @param bool $is_public Is it public or not. + * @return PostTypeBuilder + */ + public function set_public(bool $is_public) + { + return $this->set_config('public', $is_public); + } - /** - * Whether the post type is hierarchical (e.g. page). Default false. - * - * @param bool $is_hierarchical Is it hierarchical or not. - * @return PostTypeBuilder - */ - public function set_hierarchical( bool $is_hierarchical ) { - return $this->set_config( 'hierarchical', $is_hierarchical ); - } + /** + * Whether the post type is hierarchical (e.g. page). Default false. + * + * @param bool $is_hierarchical Is it hierarchical or not. + * @return PostTypeBuilder + */ + public function set_hierarchical(bool $is_hierarchical) + { + return $this->set_config('hierarchical', $is_hierarchical); + } - /** - * Whether to exclude posts with this post type from front end search results. - * Default is the opposite value of $public. - * - * @param bool $exclude_from_search Exclude this CPT from search or not. - * @return PostTypeBuilder - */ - public function set_exclude_from_search( bool $exclude_from_search ) { - return $this->set_config( 'exclude_from_search', $exclude_from_search ); - } + /** + * Whether to exclude posts with this post type from front end search results. + * Default is the opposite value of $public. + * + * @param bool $exclude_from_search Exclude this CPT from search or not. + * @return PostTypeBuilder + */ + public function set_exclude_from_search(bool $exclude_from_search) + { + return $this->set_config('exclude_from_search', $exclude_from_search); + } - /** - * Whether queries can be performed on the front end for the post type as part of parse_request(). - * Endpoints would include: - * - * - ?post_type={post_type_key} - * - ?{post_type_key}={single_post_slug} - * - ?{post_type_query_var}={single_post_slug} - * - * If not set, the default is inherited from $public. - * - * @param bool $is_publicly_queryable Is it publicly queryable or not. - * @return PostTypeBuilder - */ - public function set_publicly_queryable( bool $is_publicly_queryable ) { - return $this->set_config( 'publicly_queryable', $is_publicly_queryable ); - } + /** + * Whether queries can be performed on the front end for the post type as part of parse_request(). + * Endpoints would include: + * + * - ?post_type={post_type_key} + * - ?{post_type_key}={single_post_slug} + * - ?{post_type_query_var}={single_post_slug} + * + * If not set, the default is inherited from $public. + * + * @param bool $is_publicly_queryable Is it publicly queryable or not. + * @return PostTypeBuilder + */ + public function set_publicly_queryable(bool $is_publicly_queryable) + { + return $this->set_config('publicly_queryable', $is_publicly_queryable); + } - /** - * Whether to generate and allow a UI for managing this post type in the admin. Default is value of $public. - * - * @param bool $show_ui Show this CPT in the administration or not. - * @return PostTypeBuilder UI? - */ - public function set_show_ui( bool $show_ui ) { - return $this->set_config( 'show_ui', $show_ui ); - } + /** + * Whether to generate and allow a UI for managing this post type in the admin. Default is value of $public. + * + * @param bool $show_ui Show this CPT in the administration or not. + * @return PostTypeBuilder UI? + */ + public function set_show_ui(bool $show_ui) + { + return $this->set_config('show_ui', $show_ui); + } - /** - * Where to show the post type in the admin menu. To work, $show_ui must be true. If true, the post type is shown in - * its own top level menu. If false, no menu is shown. If a string of an existing top level menu (eg. 'tools.php' or - * 'edit.php?post_type=page'), the post type will be placed as a sub-menu of that. Default is value of $show_ui. - * - * @param bool|string $show_in_menu Show this CPT in menu. - * @return PostTypeBuilder in menu? - */ - public function set_show_in_menu( $show_in_menu ) { - return $this->set_config( 'show_in_menu', $show_in_menu ); - } + /** + * Where to show the post type in the admin menu. To work, $show_ui must be true. If true, the post type is shown in + * its own top level menu. If false, no menu is shown. If a string of an existing top level menu (eg. 'tools.php' or + * 'edit.php?post_type=page'), the post type will be placed as a sub-menu of that. Default is value of $show_ui. + * + * @param bool|string $show_in_menu Show this CPT in menu. + * @return PostTypeBuilder in menu? + */ + public function set_show_in_menu($show_in_menu) + { + return $this->set_config('show_in_menu', $show_in_menu); + } - /** - * Makes this post type available for selection in navigation menus. Default is value of $public. - * - * @param bool $show_in_nav_menus Is selectable in navigation menu or not. - * @return PostTypeBuilder - */ - public function set_show_in_nav_menus( bool $show_in_nav_menus ) { - return $this->set_config( 'show_in_nav_menus', $show_in_nav_menus ); - } + /** + * Makes this post type available for selection in navigation menus. Default is value of $public. + * + * @param bool $show_in_nav_menus Is selectable in navigation menu or not. + * @return PostTypeBuilder + */ + public function set_show_in_nav_menus(bool $show_in_nav_menus) + { + return $this->set_config('show_in_nav_menus', $show_in_nav_menus); + } - /** - * Makes this post type available via the admin bar. Default is value of $show_in_menu. - * - * @param bool $show_in_admin_bar Show in admin bar or not. - * @return PostTypeBuilder - */ - public function set_show_in_admin_bar( bool $show_in_admin_bar ) { - return $this->set_config( 'show_in_admin_bar', $show_in_admin_bar ); - } - /** - * Whether to include the post type in the REST API. Set this to true for the post type to be available in the block editor. - * - * @param bool $show_in_rest Show in rest or not. - * @return PostTypeBuilder - */ - public function set_show_in_rest( bool $show_in_rest ) { - return $this->set_config( 'show_in_rest', $show_in_rest ); - } + /** + * Makes this post type available via the admin bar. Default is value of $show_in_menu. + * + * @param bool $show_in_admin_bar Show in admin bar or not. + * @return PostTypeBuilder + */ + public function set_show_in_admin_bar(bool $show_in_admin_bar) + { + return $this->set_config('show_in_admin_bar', $show_in_admin_bar); + } + /** + * Whether to include the post type in the REST API. Set this to true for the post type to be available in the block + * editor. + * + * @param bool $show_in_rest Show in rest or not. + * @return PostTypeBuilder + */ + public function set_show_in_rest(bool $show_in_rest) + { + return $this->set_config('show_in_rest', $show_in_rest); + } - /** - * To change the base url of REST API route. Default is $post_type. - * - * @param string $rest_base The base url of the REST API route. - * @return PostTypeBuilder - */ - public function set_rest_base( string $rest_base ) { - return $this->set_config( 'rest_base', $rest_base ); - } + /** + * To change the base url of REST API route. Default is $post_type. + * + * @param string $rest_base The base url of the REST API route. + * @return PostTypeBuilder + */ + public function set_rest_base(string $rest_base) + { + return $this->set_config('rest_base', $rest_base); + } - /** - * REST API Controller class name. Default is 'WP_REST_Posts_Controller'. - * - * @param string $rest_controller_class The REST API Controller class name. - * @return PostTypeBuilder - */ - public function set_rest_controller_class( string $rest_controller_class ) { - return $this->set_config( 'rest_controller_class', $rest_controller_class ); - } + /** + * REST API Controller class name. Default is 'WP_REST_Posts_Controller'. + * + * @param string $rest_controller_class The REST API Controller class name. + * @return PostTypeBuilder + */ + public function set_rest_controller_class(string $rest_controller_class) + { + return $this->set_config('rest_controller_class', $rest_controller_class); + } - /** - * The position in the menu order the post type should appear. To work, $show_in_menu must be true. - * Default null (at the bottom). - * - * @param int $menu_position The menu position. - * @return PostTypeBuilder - */ - public function set_menu_position( int $menu_position ) { - return $this->set_config( 'menu_position', $menu_position ); - } + /** + * The position in the menu order the post type should appear. To work, $show_in_menu must be true. + * Default null (at the bottom). + * + * @param int $menu_position The menu position. + * @return PostTypeBuilder + */ + public function set_menu_position(int $menu_position) + { + return $this->set_config('menu_position', $menu_position); + } - /** - * The url to the icon to be used for this menu. Pass a base64-encoded SVG using a data URI, which will be colored to - * match the color scheme -- this should begin with 'data:image/svg+xml;base64,'. Pass the name of a Dashicons helper - * class to use a font icon, e.g. 'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty so an icon can - * be added via CSS. Defaults to use the posts icon. - * - * @param string $menu_icon The menu icon. - * @return PostTypeBuilder - */ - public function set_menu_icon( string $menu_icon ) { - return $this->set_config( 'menu_icon', $menu_icon ); - } + /** + * The url to the icon to be used for this menu. Pass a base64-encoded SVG using a data URI, which will be colored + * to match the color scheme -- this should begin with 'data:image/svg+xml;base64,'. Pass the name of a Dashicons + * helper class to use a font icon, e.g. 'dashicons-chart-pie'. Pass 'none' to leave div.wp-menu-image empty so an + * icon can be added via CSS. Defaults to use the posts icon. + * + * @param string $menu_icon The menu icon. + * @return PostTypeBuilder + */ + public function set_menu_icon(string $menu_icon) + { + return $this->set_config('menu_icon', $menu_icon); + } - /** - * The string to use to build the read, edit & delete capabilities. May be passed as an array to allow for alternative - * plurals when using this argument as a base to construct the capabilities, e.g. array('story', 'stories'). - * Default 'post'. - * - * @param string $capability_type The capability type of the CPT. - * @return PostTypeBuilder - */ - public function set_capability_type( string $capability_type ) { - return $this->set_config( 'capability_type', $capability_type ); - } + /** + * The string to use to build the read, edit & delete capabilities. May be passed as an array to allow for + * alternative plurals when using this argument as a base to construct the capabilities, + * e.g. array('story', 'stories'). + * Default 'post'. + * + * @param string $capability_type The capability type of the CPT. + * @return PostTypeBuilder + */ + public function set_capability_type(string $capability_type) + { + return $this->set_config('capability_type', $capability_type); + } - /** - * Array of capabilities for this post type. $capability_type is used as a base to construct capabilities by default. - * See get_post_type_capabilities(). - * - * @param array $capabilities List of capabilities. - * @return PostTypeBuilder - */ - public function set_capabilities( array $capabilities ) { - return $this->set_config( 'capabilities', $capabilities ); - } + /** + * Array of capabilities for this post type. $capability_type is used as a base to construct capabilities by + * default. + * See get_post_type_capabilities(). + * + * @param array $capabilities List of capabilities. + * @return PostTypeBuilder + */ + public function set_capabilities(array $capabilities) + { + return $this->set_config('capabilities', $capabilities); + } - /** - * Core feature(s) the post type supports. Serves as an alias for calling add_post_type_support() directly. Core - * features include 'title', 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', 'page-attributes', - * 'thumbnail', 'custom-fields', and 'post-formats'. Additionally, the 'revisions' feature dictates whether the post - * type will store revisions, and the 'comments' feature dictates whether the comments count will show on the edit - * screen. A feature can also be specified as an array of arguments to provide additional information about supporting - * that feature. Example: array( 'my_feature', array( 'field' => 'value' ) ). Default is an array containing 'title' - * and 'editor'. - * - * @param array $supports List of features this CPT should support. - * @return PostTypeBuilder - */ - public function set_supports( array $supports ) { - return $this->set_config( 'supports', $supports ); - } + /** + * Core feature(s) the post type supports. Serves as an alias for calling add_post_type_support() directly. Core + * features include 'title', 'editor', 'comments', 'revisions', 'trackbacks', 'author', 'excerpt', + * 'page-attributes', 'thumbnail', 'custom-fields', and 'post-formats'. Additionally, the 'revisions' feature + * dictates whether the post type will store revisions, and the 'comments' feature dictates whether the comments + * count will show on the edit screen. A feature can also be specified as an array of arguments to provide + * additional information about supporting that feature. + * + * Example: array( 'my_feature', array( 'field' => 'value' ) ). + * + * Default is an array containing 'title' and 'editor'. + * + * @param array $supports List of features this CPT should support. + * @return PostTypeBuilder + */ + public function set_supports(array $supports) + { + return $this->set_config('supports', $supports); + } - /** - * An array of taxonomy identifiers that will be registered for the post type. Taxonomies can be registered later with - * register_taxonomy() or register_taxonomy_for_object_type(). - * - * @param array $taxonomies List of taxonomy identifiers. - * @return PostTypeBuilder - */ - public function set_taxonomies( array $taxonomies ) { - return $this->set_config( 'taxonomies', $taxonomies ); - } + /** + * An array of taxonomy identifiers that will be registered for the post type. Taxonomies can be registered later + * with register_taxonomy() or register_taxonomy_for_object_type(). + * + * @param array $taxonomies List of taxonomy identifiers. + * @return PostTypeBuilder + */ + public function set_taxonomies(array $taxonomies) + { + return $this->set_config('taxonomies', $taxonomies); + } - /** - * Whether there should be post type archives, or if a string, the archive slug to use. Will generate the proper - * rewrite rules if $rewrite is enabled. Default false. - * - * @param bool|string $has_archive Whether this CPT has archive or not. - * @return PostTypeBuilder - */ - public function set_has_archive( $has_archive ) { - return $this->set_config( 'has_archive', $has_archive ); - } + /** + * Whether there should be post type archives, or if a string, the archive slug to use. Will generate the proper + * rewrite rules if $rewrite is enabled. Default false. + * + * @param bool|string $has_archive Whether this CPT has archive or not. + * @return PostTypeBuilder + */ + public function set_has_archive($has_archive) + { + return $this->set_config('has_archive', $has_archive); + } - /** - * Triggers the handling of rewrites for this post type. To prevent rewrite, set to false. Defaults to true, using - * $post_type as slug. - * - * Prefer using https://github.com/Upstatement/routes. - * - * @param bool|array $rewrite Rewrite rules for this CPT. - * @return PostTypeBuilder - */ - public function set_rewrite( $rewrite ) { - return $this->set_config( 'rewrite', $rewrite ); - } + /** + * Triggers the handling of rewrites for this post type. To prevent rewrite, set to false. Defaults to true, using + * $post_type as slug. + * + * Prefer using https://github.com/Upstatement/routes. + * + * @param bool|array $rewrite Rewrite rules for this CPT. + * @return PostTypeBuilder + */ + public function set_rewrite($rewrite) + { + return $this->set_config('rewrite', $rewrite); + } - /** - * Sets the query_var key for this post type. Defaults to $post_type key. If false, a post type cannot be loaded at - * ?{query_var}={post_slug}. If specified as a string, the query ?{query_var_string}={post_slug} will be valid. - * - * @param string|bool $query_var The query var key. - * @return PostTypeBuilder - */ - public function set_query_var( $query_var ) { - return $this->set_config( 'query_var', $query_var ); - } + /** + * Sets the query_var key for this post type. Defaults to $post_type key. If false, a post type cannot be loaded at + * ?{query_var}={post_slug}. If specified as a string, the query ?{query_var_string}={post_slug} will be valid. + * + * @param string|bool $query_var The query var key. + * @return PostTypeBuilder + */ + public function set_query_var($query_var) + { + return $this->set_config('query_var', $query_var); + } - /** - * Whether to allow this post type to be exported. Default true. - * - * @param bool $can_export Wether to allow export or not. - * @return PostTypeBuilder - */ - public function set_can_export( bool $can_export ) { - return $this->set_config( 'can_export', $can_export ); - } + /** + * Whether to allow this post type to be exported. Default true. + * + * @param bool $can_export Wether to allow export or not. + * @return PostTypeBuilder + */ + public function set_can_export(bool $can_export) + { + return $this->set_config('can_export', $can_export); + } - /** - * Whether to delete posts of this type when deleting a user. If true, posts of this type belonging to the user will - * be moved to Trash when then user is deleted. If false, posts of this type belonging to the user will *not* be - * trashed or deleted. If not set (the default), posts are trashed if post_type_supports('author'). Otherwise posts - * are not trashed or deleted. Default null. - * - * @param bool $delete_with_user Wether to delete posts when their author is deleted or not. - * @return PostTypeBuilder - */ - public function set_delete_with_user( bool $delete_with_user ) { - return $this->set_config( 'delete_with_user', $delete_with_user ); - } + /** + * Whether to delete posts of this type when deleting a user. If true, posts of this type belonging to the user will + * be moved to Trash when then user is deleted. If false, posts of this type belonging to the user will *not* be + * trashed or deleted. If not set (the default), posts are trashed if post_type_supports('author'). Otherwise posts + * are not trashed or deleted. Default null. + * + * @param bool $delete_with_user Wether to delete posts when their author is deleted or not. + * @return PostTypeBuilder + */ + public function set_delete_with_user(bool $delete_with_user) + { + return $this->set_config('delete_with_user', $delete_with_user); + } } diff --git a/src/Builders/TaxonomyBuilder.php b/src/Builders/TaxonomyBuilder.php index 2c9c0a1..9fa185d 100644 --- a/src/Builders/TaxonomyBuilder.php +++ b/src/Builders/TaxonomyBuilder.php @@ -15,325 +15,356 @@ /** * Build a custom post type. */ -class TaxonomyBuilder extends Builder { - /** - * The post type configuration. - * - * @var array - */ - public $default_config = array( - 'query_var' => true, - 'show_ui' => true, - 'show_admin_column' => true, - 'show_in_nav_menus' => true, - 'show_tagcloud' => true, - ); +class TaxonomyBuilder extends Builder +{ + /** + * The post type configuration. + * + * @var array + */ + public $default_config = array( + 'query_var' => true, + 'show_ui' => true, + 'show_admin_column' => true, + 'show_in_nav_menus' => true, + 'show_tagcloud' => true, + ); - /** - * The register method name. - * - * @var string - */ - public $register_method = 'register_taxonomy'; + /** + * The register method name. + * + * @var string + */ + public $register_method = 'register_taxonomy'; - /** - * The register method args. - * - * @var array - */ - public $register_method_args = array( 'type', 'post_types', 'config' ); + /** + * The register method args. + * + * @var array + */ + public $register_method_args = array( 'type', 'post_types', 'config' ); - /** - * The post types which associated to this taxonomy. - * - * @var string|array - */ - protected $post_types = array(); + /** + * The post types which associated to this taxonomy. + * + * @var string|array + */ + protected $post_types = array(); - /** - * Set the taxonomy post types. - * - * @param string|array $post_types Object type or array of object types with which the taxonomy should be associated. - * @return $this; - */ - public function set_post_types( $post_types ):self { - $this->post_types = $post_types; - return $this; - } + /** + * Set the taxonomy post types. + * + * @param string|array $post_types Object or array of objects with which the taxonomy should be associated. + * @return $this; + */ + public function set_post_types($post_types):self + { + $this->post_types = $post_types; + return $this; + } - /** - * Get the associated post types. - * - * @return string|array The name or a list of names of post types. - */ - public function get_post_types() { - return $this->post_types; - } + /** + * Get the associated post types. + * + * @return string|array The name or a list of names of post types. + */ + public function get_post_types() + { + return $this->post_types; + } - /** - * An array of labels for this post type. If not set, post labels are inherited for non-hierarchical types and page - * labels for hierarchical ones. - * - * @param string $singular The singular label. - * @param string $plural The plural label. - */ - public function set_labels( string $singular, string $plural ):self { - return $this->set_config( 'labels', $this->generate_labels( $singular, $plural ) ); - } + /** + * An array of labels for this post type. If not set, post labels are inherited for non-hierarchical types and page + * labels for hierarchical ones. + * + * @param string $singular The singular label. + * @param string $plural The plural label. + */ + public function set_labels(string $singular, string $plural):self + { + return $this->set_config('labels', $this->generate_labels($singular, $plural)); + } - /** - * Generate labels. - * - * @param string $singular Singular name. - * @param string $plural Plural name. - * @return array Labels. - */ - private function generate_labels( string $singular, string $plural ):array { + /** + * Generate labels. + * + * @param string $singular Singular name. + * @param string $plural Plural name. + * @return array Labels. + */ + private function generate_labels(string $singular, string $plural):array + { // phpcs:disable WordPress.WP.I18n - $labels = array( - 'name' => $plural, - 'singular_name' => $singular, - 'add_new_item' => sprintf( __( 'Add New %s', 'studiometa' ), $singular ), - 'all_items' => sprintf( __( 'All %s', 'studiometa' ), $plural ), - 'choose_from_most_used' => __( 'Most used', 'studiometa' ), - 'edit_item' => sprintf( __( 'Edit %s', 'studiometa' ), $singular ), - 'items_list' => sprintf( __( '%s list', 'studiometa' ), $plural ), - 'items_list_navigation' => sprintf( __( '%s list navigation', 'studiometa' ), $plural ), - 'menu_name' => $plural, - 'new_item_name' => sprintf( __( 'New %s', 'studiometa' ), $singular ), - 'no_terms' => sprintf( __( 'No %s', 'studiometa' ), $singular ), - 'parent_item' => sprintf( __( '%s parent', 'studiometa' ), $singular ), - 'parent_item_colon' => isset( $this->get_config()['hierarchical'] ) && $this->get_config()['hierarchical'] ? sprintf( __( '%s parent:', 'studiometa' ), $singular ) : null, - 'popular_items' => sprintf( __( 'Popular %s', 'studiometa' ), $singular ), - 'search_items' => sprintf( __( 'Search %s', 'studiometa' ), $plural ), - 'update_item' => sprintf( __( 'Update the %s', 'studiometa' ), $singular ), - 'view_item' => sprintf( __( 'View %s', 'studiometa' ), $singular ), - ); + $labels = array( + 'name' => $plural, + 'singular_name' => $singular, + 'add_new_item' => sprintf(__('Add New %s', 'studiometa'), $singular), + 'all_items' => sprintf(__('All %s', 'studiometa'), $plural), + 'choose_from_most_used' => __('Most used', 'studiometa'), + 'edit_item' => sprintf(__('Edit %s', 'studiometa'), $singular), + 'items_list' => sprintf(__('%s list', 'studiometa'), $plural), + 'items_list_navigation' => sprintf(__('%s list navigation', 'studiometa'), $plural), + 'menu_name' => $plural, + 'new_item_name' => sprintf(__('New %s', 'studiometa'), $singular), + 'no_terms' => sprintf(__('No %s', 'studiometa'), $singular), + 'parent_item' => sprintf(__('%s parent', 'studiometa'), $singular), + 'parent_item_colon' => isset($this->get_config()['hierarchical']) && $this->get_config()['hierarchical'] + ? sprintf(__('%s parent:', 'studiometa'), $singular) + : null, + 'popular_items' => sprintf(__('Popular %s', 'studiometa'), $singular), + 'search_items' => sprintf(__('Search %s', 'studiometa'), $plural), + 'update_item' => sprintf(__('Update the %s', 'studiometa'), $singular), + 'view_item' => sprintf(__('View %s', 'studiometa'), $singular), + ); // phpcs:enable - return $labels; - } + return $labels; + } - /** - * A short descriptive summary of what the taxonomy is for. - * - * @param string $description The description. - * @return $this - */ - public function set_description( string $description ):self { - return $this->set_config( 'description', $description ); - } + /** + * A short descriptive summary of what the taxonomy is for. + * + * @param string $description The description. + * @return $this + */ + public function set_description(string $description):self + { + return $this->set_config('description', $description); + } - /** - * Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users. The default - * settings of $publicly_queryable, $show_ui, and $show_in_nav_menus are inherited from $public. - * - * @param bool $public Public or not. - * @return $this - */ - public function set_public( bool $public ):self { - return $this->set_config( 'public', $public ); - } + /** + * Whether a taxonomy is intended for use publicly either via the admin interface or by front-end users. The default + * settings of $publicly_queryable, $show_ui, and $show_in_nav_menus are inherited from $public. + * + * @param bool $public Public or not. + * @return $this + */ + public function set_public(bool $public):self + { + return $this->set_config('public', $public); + } - /** - * Whether the taxonomy is publicly queryable. If not set, the default is inherited from $public. - * - * @param bool $publicly_queryable Is publicly queryable or not. - * @return $this - */ - public function set_publicly_queryable( bool $publicly_queryable ):self { - return $this->set_config( 'publicly_queryable', $publicly_queryable ); - } + /** + * Whether the taxonomy is publicly queryable. If not set, the default is inherited from $public. + * + * @param bool $publicly_queryable Is publicly queryable or not. + * @return $this + */ + public function set_publicly_queryable(bool $publicly_queryable):self + { + return $this->set_config('publicly_queryable', $publicly_queryable); + } - /** - * Whether the taxonomy is hierarchical. Default false. - * - * @param bool $hierarchical Hierarchical or not. - * @return $this - */ - public function set_hierarchical( bool $hierarchical ):self { - return $this->set_config( 'hierarchical', $hierarchical ); - } + /** + * Whether the taxonomy is hierarchical. Default false. + * + * @param bool $hierarchical Hierarchical or not. + * @return $this + */ + public function set_hierarchical(bool $hierarchical):self + { + return $this->set_config('hierarchical', $hierarchical); + } - /** - * Whether to generate and allow a UI for managing terms in this taxonomy in the admin. If not set, the default is - * inherited from $public. Default to true. - * - * @param bool $show_ui Show the UI or not. - * @return $this - */ - public function set_show_ui( bool $show_ui ):self { - return $this->set_config( 'show_ui', $show_ui ); - } + /** + * Whether to generate and allow a UI for managing terms in this taxonomy in the admin. If not set, the default is + * inherited from $public. Default to true. + * + * @param bool $show_ui Show the UI or not. + * @return $this + */ + public function set_show_ui(bool $show_ui):self + { + return $this->set_config('show_ui', $show_ui); + } - /** - * Whether to show the taxonomy in the admin menu or not. If true, the taxonomy is shown as a submenu of the object - * type menu. If false, no menu is shown. $show_ui must be true. If not set, default is inherited from $show_ui. - * Default to true. - * - * @param bool $show_in_menu Show in menu or not. - * @return $this - */ - public function set_show_in_menu( bool $show_in_menu ):self { - return $this->set_config( 'show_in_menu', $show_in_menu ); - } + /** + * Whether to show the taxonomy in the admin menu or not. If true, the taxonomy is shown as a submenu of the object + * type menu. If false, no menu is shown. $show_ui must be true. If not set, default is inherited from $show_ui. + * Default to true. + * + * @param bool $show_in_menu Show in menu or not. + * @return $this + */ + public function set_show_in_menu(bool $show_in_menu):self + { + return $this->set_config('show_in_menu', $show_in_menu); + } - /** - * Makes this taxonomy available for selection in navigation menus. If not set, the default is inherited from $public. - * Default to true. - * - * @param bool $show_in_nav_menus Show in nav menus or not. - * @return $this - */ - public function set_show_in_nav_menus( bool $show_in_nav_menus ):self { - return $this->set_config( 'show_in_nav_menus', $show_in_nav_menus ); - } + /** + * Makes this taxonomy available for selection in navigation menus. If not set, the default is inherited from + * $public. + * + * Default to true. + * + * @param bool $show_in_nav_menus Show in nav menus or not. + * @return $this + */ + public function set_show_in_nav_menus(bool $show_in_nav_menus):self + { + return $this->set_config('show_in_nav_menus', $show_in_nav_menus); + } - /** - * Whether to include the taxonomy in the REST API. Set this to true for the taxonomy to be available in the - * block editor. - * - * @param bool $show_in_rest Show in taxonomy or not. - * @return $this - */ - public function set_show_in_rest( bool $show_in_rest ):self { - return $this->set_config( 'show_in_rest', $show_in_rest ); - } + /** + * Whether to include the taxonomy in the REST API. Set this to true for the taxonomy to be available in the + * block editor. + * + * @param bool $show_in_rest Show in taxonomy or not. + * @return $this + */ + public function set_show_in_rest(bool $show_in_rest):self + { + return $this->set_config('show_in_rest', $show_in_rest); + } - /** - * To change the base url of REST API route. Default is $taxonomy. - * - * @param string $rest_base The REST API base route value. - * @return $this - */ - public function set_rest_base( string $rest_base ):self { - return $this->set_config( 'rest_base', $rest_base ); - } + /** + * To change the base url of REST API route. Default is $taxonomy. + * + * @param string $rest_base The REST API base route value. + * @return $this + */ + public function set_rest_base(string $rest_base):self + { + return $this->set_config('rest_base', $rest_base); + } - /** - * REST API Controller class name. Default is 'WP_REST_Terms_Controller'. - * - * @param string $rest_controller_class The REST API Controller class name. - * @return $this - */ - public function set_rest_controller_class( string $rest_controller_class ):self { - return $this->set_config( 'rest_controller_class', $rest_controller_class ); - } + /** + * REST API Controller class name. Default is 'WP_REST_Terms_Controller'. + * + * @param string $rest_controller_class The REST API Controller class name. + * @return $this + */ + public function set_rest_controller_class(string $rest_controller_class):self + { + return $this->set_config('rest_controller_class', $rest_controller_class); + } - /** - * Whether to list the taxonomy in the Tag Cloud Widget controls. If not set, the default is inherited from $show_ui. - * Default to true. - * - * @param bool $show_tagcloud Show in tag cloud or not. - * @return $this - */ - public function set_show_tagcloud( bool $show_tagcloud ):self { - return $this->set_config( 'show_tagcloud', $show_tagcloud ); - } + /** + * Whether to list the taxonomy in the Tag Cloud Widget controls. If not set, the default is inherited from + * $show_ui. + * + * Default to true. + * + * @param bool $show_tagcloud Show in tag cloud or not. + * @return $this + */ + public function set_show_tagcloud(bool $show_tagcloud):self + { + return $this->set_config('show_tagcloud', $show_tagcloud); + } - /** - * Whether to show the taxonomy in the quick/bulk edit panel. It not set, the default is inherited from $show_ui. - * Default to true. - * - * @param bool $show_in_quick_edit Show in quick edit or not. - * @return $this - */ - public function set_show_in_quick_edit( bool $show_in_quick_edit ):self { - return $this->set_config( 'show_in_quick_edit', $show_in_quick_edit ); - } + /** + * Whether to show the taxonomy in the quick/bulk edit panel. It not set, the default is inherited from $show_ui. + * Default to true. + * + * @param bool $show_in_quick_edit Show in quick edit or not. + * @return $this + */ + public function set_show_in_quick_edit(bool $show_in_quick_edit):self + { + return $this->set_config('show_in_quick_edit', $show_in_quick_edit); + } - /** - * Whether to display a column for the taxonomy on its post type listing screens. Default false. - * - * @param bool $show_admin_column Show or column or not. - * @return $this - */ - public function set_show_admin_column( bool $show_admin_column ):self { - return $this->set_config( 'show_admin_column', $show_admin_column ); - } + /** + * Whether to display a column for the taxonomy on its post type listing screens. Default false. + * + * @param bool $show_admin_column Show or column or not. + * @return $this + */ + public function set_show_admin_column(bool $show_admin_column):self + { + return $this->set_config('show_admin_column', $show_admin_column); + } - /** - * Provide a callback function for the meta box display. If not set, post_categories_meta_box() is used for - * hierarchical taxonomies, and post_tags_meta_box() is used for non-hierarchical. If false, no meta box is shown. - * - * @param bool|callable $meta_box_cb The callback function. - * @return $this - */ - public function set_meta_box_cb( $meta_box_cb ):self { - return $this->set_config( 'meta_box_cb', $meta_box_cb ); - } + /** + * Provide a callback function for the meta box display. If not set, post_categories_meta_box() is used for + * hierarchical taxonomies, and post_tags_meta_box() is used for non-hierarchical. If false, no meta box is shown. + * + * @param bool|callable $meta_box_cb The callback function. + * @return $this + */ + public function set_meta_box_cb($meta_box_cb):self + { + return $this->set_config('meta_box_cb', $meta_box_cb); + } - /** - * Callback function for sanitizing taxonomy data saved from a meta box. If no callback is defined, an appropriate one - * is determined based on the value of $meta_box_cb. - * - * @param callable $meta_box_sanitize_cb The callback function. - * @return $this - */ - public function set_meta_box_sanitize_cb( $meta_box_sanitize_cb ):self { - return $this->set_config( 'meta_box_sanitize_cb', $meta_box_sanitize_cb ); - } + /** + * Callback function for sanitizing taxonomy data saved from a meta box. If no callback is defined, an appropriate + * one is determined based on the value of $meta_box_cb. + * + * @param callable $meta_box_sanitize_cb The callback function. + * @return $this + */ + public function set_meta_box_sanitize_cb($meta_box_sanitize_cb):self + { + return $this->set_config('meta_box_sanitize_cb', $meta_box_sanitize_cb); + } - /** - * Array of capabilities for this taxonomy. - * - * @param array $capabilities Array of capabilities for this taxonomy. - * @return $this - */ - public function set_capabilities( array $capabilities ):self { - return $this->set_config( 'capabilities', $capabilities ); - } + /** + * Array of capabilities for this taxonomy. + * + * @param array $capabilities Array of capabilities for this taxonomy. + * @return $this + */ + public function set_capabilities(array $capabilities):self + { + return $this->set_config('capabilities', $capabilities); + } - /** - * Triggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent rewrite, set - * to false. To specify rewrite rules, an array can be passed with any of these keys: - * - * - `slug` (string) Customize the permastruct slug. Default $taxonomy key. - * - `with_front` (bool) Should the permastruct be prepended with WP_Rewrite::$front. Default true. - * - `hierarchical` (bool) Either hierarchical rewrite tag or not. Default false. - * - `ep_mask` (int) Assign an endpoint mask. Default EP_NONE. - * - * @param bool|array $rewrite The rewrite configuration. - * @return $this - */ - public function set_rewrite( $rewrite ):self { - return $this->set_config( 'rewrite', $rewrite ); - } + /** + * Triggers the handling of rewrites for this taxonomy. Default true, using $taxonomy as slug. To prevent rewrite, + * set to false. To specify rewrite rules, an array can be passed with any of these keys: + * + * - `slug` (string) Customize the permastruct slug. Default $taxonomy key. + * - `with_front` (bool) Should the permastruct be prepended with WP_Rewrite::$front. Default true. + * - `hierarchical` (bool) Either hierarchical rewrite tag or not. Default false. + * - `ep_mask` (int) Assign an endpoint mask. Default EP_NONE. + * + * @param bool|array $rewrite The rewrite configuration. + * @return $this + */ + public function set_rewrite($rewrite):self + { + return $this->set_config('rewrite', $rewrite); + } - /** - * Sets the query var key for this taxonomy. Default $taxonomy key. If false, a taxonomy cannot be loaded at - * ?{query_var}={term_slug}. If a string, the query ?{query_var}={term_slug} will be valid. - * - * @param string|bool $query_var The query var value. - * @return $this - */ - public function set_query_var( $query_var ):self { - return $this->set_config( 'query_var', $query_var ); - } + /** + * Sets the query var key for this taxonomy. Default $taxonomy key. If false, a taxonomy cannot be loaded at + * ?{query_var}={term_slug}. If a string, the query ?{query_var}={term_slug} will be valid. + * + * @param string|bool $query_var The query var value. + * @return $this + */ + public function set_query_var($query_var):self + { + return $this->set_config('query_var', $query_var); + } - /** - * Works much like a hook, in that it will be called when the count is updated. Default _update_post_term_count() for - * taxonomies attached to post types, which confirms that the objects are published before counting them. Default - * _update_generic_term_count() for taxonomies attached to other object types, such as users. - * - * @param callable $update_count_callback The callback function. - * @return $this - */ - public function set_update_count_callback( $update_count_callback ):self { - return $this->set_config( 'update_count_callback', $update_count_callback ); - } + /** + * Works much like a hook, in that it will be called when the count is updated. Default _update_post_term_count() + * for taxonomies attached to post types, which confirms that the objects are published before counting them. + * Default _update_generic_term_count() for taxonomies attached to other object types, such as users. + * + * @param callable $update_count_callback The callback function. + * @return $this + */ + public function set_update_count_callback($update_count_callback):self + { + return $this->set_config('update_count_callback', $update_count_callback); + } - /** - * Default term to be used for the taxonomy. If an array, it can have the following keys: - * - * - `name` (string) Name of default term. - * - `slug` (string) Slug for default term. - * - `description` (string) Description for default term. - * - * @param string|array $default_term The default term value. - * @return $this - */ - public function set_default_term( $default_term ):self { - return $this->set_config( 'default_term', $default_term ); - } + /** + * Default term to be used for the taxonomy. If an array, it can have the following keys: + * + * - `name` (string) Name of default term. + * - `slug` (string) Slug for default term. + * - `description` (string) Description for default term. + * + * @param string|array $default_term The default term value. + * @return $this + */ + public function set_default_term($default_term):self + { + return $this->set_config('default_term', $default_term); + } } diff --git a/src/Helpers/Env.php b/src/Helpers/Env.php index 78876b6..5f92efe 100644 --- a/src/Helpers/Env.php +++ b/src/Helpers/Env.php @@ -2,19 +2,21 @@ namespace Studiometa\WPToolkit\Helpers; -class Env { - /** - * Get an environment variable value. - * - * @param string $key The variable name. - * @return string - */ - public static function get( string $key ): string { +class Env +{ + /** + * Get an environment variable value. + * + * @param string $key The variable name. + * @return string + */ + public static function get(string $key): string + { // phpcs:ignore /** @var array Good type. */ - $env = $_ENV; - // In some environment, values are not available in the `$_ENV` variables, - // so we use `getenv` as a fallback to try and get the value. - return $env[ $key ] ?? (string) getenv( $key ); - } + $env = $_ENV; + // In some environment, values are not available in the `$_ENV` variables, + // so we use `getenv` as a fallback to try and get the value. + return $env[ $key ] ?? (string) getenv($key); + } } diff --git a/src/Helpers/Plugin.php b/src/Helpers/Plugin.php index 49cdcb9..e2f6bc3 100644 --- a/src/Helpers/Plugin.php +++ b/src/Helpers/Plugin.php @@ -19,112 +19,118 @@ /** * Plugins class. */ -class Plugin { - - /** - * Disabled plugins. - * - * @var string[] - */ - private static $disabled_plugins = array(); - - /** - * Class instance. - * @var self - */ - private static $instance = null; - - /** - * Hook into the activation filters on construction. - */ - private function __construct( ) { - early_add_filter( - 'option_active_plugins', - function( array $plugins ) { - return self::do_disabling( $plugins ); - } - ); - early_add_filter( - 'site_option_active_sitewide_plugins', - function( array $plugins ) { - return self::do_network_disabling( $plugins ); - } - ); - } - - /** - * Hooks in to the option_active_plugins filter and does the disabling - * - * @param string[] $plugins WP-provided list of plugin filenames. - * - * @return string[] The filtered array of plugin filenames - */ - private static function do_disabling( array $plugins ): array { - if ( count( self::$disabled_plugins ) ) { - foreach ( self::$disabled_plugins as $disabled_plugin ) { - $key = array_search( $disabled_plugin, $plugins, true ); - if ( false !== $key ) { - unset( $plugins[ $key ] ); - } - } - } - - return $plugins; - } - - /** - * Hooks in to the site_option_active_sitewide_plugins filter and does the disabling - * - * @param string[] $plugins Plugins. - * - * @return string[] - */ - private static function do_network_disabling( $plugins ) { - if ( count( self::$disabled_plugins ) ) { - foreach ( (array) self::$disabled_plugins as $plugin ) { - if ( isset( $plugins[ $plugin ] ) ) { - unset( $plugins[ $plugin ] ); - } - } - } - - return $plugins; - } - - /** - * Disable a list of plugins. - * - * @param string[] $plugins The list of plugins to disable. - */ - public static function disable( array $plugins ): void { - self::$disabled_plugins = self::$disabled_plugins + $plugins; - - if ( is_null( self::$instance) ) { - self::$instance = new self(); - } - } - - /** - * Test if plugin is enabled. - * - * @param string $filepath Plugin filepath (relative to plugins folder). - * - * @codeCoverageIgnore - * - * @return boolean Is the plugin enabled? - */ - public static function is_plugin_enabled( string $filepath ):bool { - $cache_key = __FUNCTION__ . md5( $filepath ); - $cached_results = wp_cache_get( $cache_key, __CLASS__ ); - - if ( false !== $cached_results ) { - return (bool) $cached_results; - } - - $is_enabled = is_plugin_active( $filepath ); - - wp_cache_set( $cache_key, (int) $is_enabled, __CLASS__ ); - - return $is_enabled; - } +class Plugin +{ + + /** + * Disabled plugins. + * + * @var string[] + */ + private static $disabled_plugins = array(); + + /** + * Class instance. + * @var self|null + */ + private static $instance = null; + + /** + * Hook into the activation filters on construction. + */ + private function __construct() + { + early_add_filter( + 'option_active_plugins', + function (array $plugins) { + return self::do_disabling($plugins); + } + ); + early_add_filter( + 'site_option_active_sitewide_plugins', + function (array $plugins) { + return self::do_network_disabling($plugins); + } + ); + } + + /** + * Hooks in to the option_active_plugins filter and does the disabling + * + * @param string[] $plugins WP-provided list of plugin filenames. + * + * @return string[] The filtered array of plugin filenames + */ + private static function do_disabling(array $plugins): array + { + if (count(self::$disabled_plugins)) { + foreach (self::$disabled_plugins as $disabled_plugin) { + $key = array_search($disabled_plugin, $plugins, true); + if (false !== $key) { + unset($plugins[ $key ]); + } + } + } + + return $plugins; + } + + /** + * Hooks in to the site_option_active_sitewide_plugins filter and does the disabling + * + * @param string[] $plugins Plugins. + * + * @return string[] + */ + private static function do_network_disabling($plugins) + { + if (count(self::$disabled_plugins)) { + foreach ((array) self::$disabled_plugins as $plugin) { + if (isset($plugins[ $plugin ])) { + unset($plugins[ $plugin ]); + } + } + } + + return $plugins; + } + + /** + * Disable a list of plugins. + * + * @param string[] $plugins The list of plugins to disable. + */ + public static function disable(array $plugins): void + { + self::$disabled_plugins = self::$disabled_plugins + $plugins; + + if (is_null(self::$instance)) { + self::$instance = new self(); + } + } + + /** + * Test if plugin is enabled. + * + * @param string $filepath Plugin filepath (relative to plugins folder). + * + * @codeCoverageIgnore + * + * @return boolean Is the plugin enabled? + */ + public static function is_plugin_enabled(string $filepath):bool + { + $cache_key = __FUNCTION__ . md5($filepath); + $cached_results = wp_cache_get($cache_key, __CLASS__); + + if (false !== $cached_results) { + return (bool) $cached_results; + } + + $is_enabled = is_plugin_active($filepath); + + wp_cache_set($cache_key, (int) $is_enabled, __CLASS__); + + return $is_enabled; + } } diff --git a/src/Helpers/Request.php b/src/Helpers/Request.php index 3dc3eaa..199ef1f 100644 --- a/src/Helpers/Request.php +++ b/src/Helpers/Request.php @@ -4,47 +4,51 @@ use Symfony\Component\HttpFoundation\Request as SymfonyRequest; -class Request { - /** - * Private variable to hold the helpers instance. - * - * @var ?Request - */ - private static $instance = null; - - /** - * Private variables to hold the current request instance. - * - * @var SymfonyRequest - */ - private SymfonyRequest $request; - - /** - * Private constructor. - */ - private function __construct() { - $this->request = SymfonyRequest::createFromGlobals(); - } - - /** - * Get singleton instance. - * - * @return Request - */ - private static function get_instance() { - if ( is_null( self::$instance ) ) { - self::$instance = new self(); - } - - return self::$instance; - } - - /** - * Work with the current HTTP request. - * - * @return SymfonyRequest - */ - public static function request(): SymfonyRequest { - return self::get_instance()->request; - } +class Request +{ + /** + * Private variable to hold the helpers instance. + * + * @var ?Request + */ + private static $instance = null; + + /** + * Private variables to hold the current request instance. + * + * @var SymfonyRequest + */ + private SymfonyRequest $request; + + /** + * Private constructor. + */ + private function __construct() + { + $this->request = SymfonyRequest::createFromGlobals(); + } + + /** + * Get singleton instance. + * + * @return Request + */ + private static function get_instance() + { + if (is_null(self::$instance)) { + self::$instance = new self(); + } + + return self::$instance; + } + + /** + * Work with the current HTTP request. + * + * @return SymfonyRequest + */ + public static function request(): SymfonyRequest + { + return self::get_instance()->request; + } } diff --git a/src/Managers/AssetsManager.php b/src/Managers/AssetsManager.php index 3c337a8..050892a 100644 --- a/src/Managers/AssetsManager.php +++ b/src/Managers/AssetsManager.php @@ -19,334 +19,344 @@ /** * Helper class to manage a theme's assets. */ -class AssetsManager implements ManagerInterface { - /** - * The parsed configuration. - * - * @var array - */ - public $config; - - /** - * The parsed Webpack manifest. - * - * @var Manifest - */ - public $webpack_manifest; - - /** - * Configuration filepath. - * - * @var string - */ - private $configuration_filepath; - - /** - * Webpack manifest filepath. - * - * @var string - */ - private $webpack_manifest_filepath; - - /** - * Constructor. - * - * @param string|null $configuration_filepath Configuration filepath. - * @param string|null $webpack_manifest_filepath Webpack manifest filepath. - */ - public function __construct( ?string $configuration_filepath = null, ?string $webpack_manifest_filepath = null ) { - $this->configuration_filepath = get_template_directory() . '/config/assets.yml'; - $this->webpack_manifest_filepath = get_template_directory() . '/dist/assets-manifest.json'; - - if ( isset( $configuration_filepath ) ) { - $this->configuration_filepath = $configuration_filepath; - } - - if ( isset( $webpack_manifest_filepath ) ) { - $this->webpack_manifest_filepath = $webpack_manifest_filepath; - } - } +class AssetsManager implements ManagerInterface +{ + /** + * The parsed configuration. + * + * @var array + */ + public $config; + + /** + * The parsed Webpack manifest. + * + * @var Manifest + */ + public $webpack_manifest; + + /** + * Configuration filepath. + * + * @var string + */ + private $configuration_filepath; + + /** + * Webpack manifest filepath. + * + * @var string + */ + private $webpack_manifest_filepath; + + /** + * Constructor. + * + * @param string|null $configuration_filepath Configuration filepath. + * @param string|null $webpack_manifest_filepath Webpack manifest filepath. + */ + public function __construct(?string $configuration_filepath = null, ?string $webpack_manifest_filepath = null) + { + $this->configuration_filepath = get_template_directory() . '/config/assets.yml'; + $this->webpack_manifest_filepath = get_template_directory() . '/dist/assets-manifest.json'; + + if (isset($configuration_filepath)) { + $this->configuration_filepath = $configuration_filepath; + } + + if (isset($webpack_manifest_filepath)) { + $this->webpack_manifest_filepath = $webpack_manifest_filepath; + } + } // phpcs:ignore Generic.Commenting.DocComment.MissingShort - /** - * @inheritdoc - */ - public function run() { - if ( ! file_exists( $this->configuration_filepath ) ) { - $msg = 'No assets configuration file found.'; + /** + * @inheritdoc + */ + public function run() + { + if (! file_exists($this->configuration_filepath)) { + $msg = 'No assets configuration file found.'; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error - trigger_error( esc_html( $msg ), E_USER_NOTICE ); - return; - } + trigger_error(esc_html($msg), E_USER_NOTICE); + return; + } - // @phpstan-ignore-next-line - $this->config = Yaml::parseFile( $this->configuration_filepath ); + // @phpstan-ignore-next-line + $this->config = Yaml::parseFile($this->configuration_filepath); - if ( $this->webpack_manifest_filepath ) { - if ( ! file_exists( $this->webpack_manifest_filepath ) ) { - $msg = sprintf( 'No webpack manifest file found in `%s`.', $this->webpack_manifest_filepath ); + if ($this->webpack_manifest_filepath) { + if (! file_exists($this->webpack_manifest_filepath)) { + $msg = sprintf('No webpack manifest file found in `%s`.', $this->webpack_manifest_filepath); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error - trigger_error( esc_html( $msg ), E_USER_NOTICE ); - return; - } - - $this->webpack_manifest = new Manifest( - $this->webpack_manifest_filepath, - $this->get_webpack_public_path_relative_to_theme() - ); - } - - add_action( 'wp_enqueue_scripts', array( $this, 'register_all' ) ); - add_filter( 'template_include', array( $this, 'enqueue_all' ) ); - } - - /** - * Get Webpack dist folder relative to the theme. - * - * @returns string - */ - private function get_webpack_public_path_relative_to_theme():string { - return trim( str_replace( get_template_directory(), '', dirname( $this->webpack_manifest_filepath ) ), '/' ) . '/'; - } - - /** - * Register all defined JS and CSS assets with automatic - * versioning based on their content's MD5 hash. - * - * @return void - */ - public function register_all() { - foreach ( $this->config as $name => $config ) { - if ( isset( $config['entries'] ) && is_array( $config['entries'] ) ) { - foreach ( $config['entries'] as $entry ) { - $pathinfo = pathinfo( $entry ); - $entry = implode( - DIRECTORY_SEPARATOR, - array( $pathinfo['dirname'] ?? '', $pathinfo['filename'] ) - ); - - $webpack_entry = $this->webpack_manifest->entry( $entry ); - - if ( ! $webpack_entry ) { - continue; - } - - $webpack_entry->styles->each( - function ( $style, $handle ) { - $this->register( 'style', $handle, $style->getAttribute( 'href' ) ); - } - ); - - $webpack_entry->scripts->each( - function ( $script, $handle ) { - $this->register( 'script', $handle, $script->getAttribute( 'src' ) ); - } - ); - } - } - - if ( isset( $config['css'] ) ) { - foreach ( $config['css'] as $handle => $path ) { - $this->register( 'style', $handle, $path ); - - // Enqueue directly if the name of the config is 'all'. - if ( 'all' === $name ) { - wp_enqueue_style( $handle ); - } - } - } - - if ( isset( $config['js'] ) ) { - foreach ( $config['js'] as $handle => $path ) { - $this->register( 'script', $handle, $path ); - - // Enqueue directly if the name of the config is 'all'. - if ( 'all' === $name ) { - wp_enqueue_script( $handle ); - } - } - } - } - } - - /** - * Enqueue CSS and JS files based on the WordPress template. - * - * @param string $template The template path. - * @return string The template path. - */ - public function enqueue_all( $template ) { - $potential_names = array( 'all' ) + $this->get_potential_names( $template ); - - foreach ( $potential_names as $potential_name ) { - foreach ( $this->config as $name => $config ) { - if ( (string) $name !== $potential_name ) { - continue; - } - - if ( isset( $config['entries'] ) && is_array( $config['entries'] ) ) { - foreach ( $config['entries'] as $entry ) { - $pathinfo = pathinfo( $entry ); - $entry = implode( - DIRECTORY_SEPARATOR, - array( $pathinfo['dirname'] ?? '', $pathinfo['filename'] ) - ); - - $webpack_entry = $this->webpack_manifest->entry( $entry ); - - if ( ! $webpack_entry ) { - continue; - } - - $webpack_entry->styles->keys()->each( - function ( $handle ) { - $this->enqueue( 'style', $handle ); - } - ); - - $webpack_entry->scripts->keys()->each( - function ( $handle ) { - $this->enqueue( 'script', $handle ); - } - ); - } - } - - if ( isset( $config['css'] ) ) { - foreach ( $config['css'] as $handle => $path ) { - $this->enqueue( 'style', $handle ); - } - } - - if ( isset( $config['js'] ) ) { - foreach ( $config['js'] as $handle => $path ) { - $this->enqueue( 'script', $handle ); - } - } - } - } - - return $template; - } - - /** - * Get all the potential assets group name. - * For a template file `single-post-hello.php`, the following group names - * will be returned: - * - * - single - * - single-post - * - single-post-hello - * - * @param string $template The full template path. - * @return array A list of potential assets name. - */ - protected function get_potential_names( string $template ):array { - $pathinfo = pathinfo( $template ); - $parts = explode( '-', $pathinfo['filename'] ); - - return array_reduce( - $parts, - function ( $acc, $part ) { - if ( empty( $acc ) ) { - return array( $part ); - } - - $previous_part = $acc[ count( $acc ) - 1 ]; - $acc[] = $previous_part . '-' . $part; - - return $acc; - }, - array() - ); - } - - - /** - * Register a single asset. - * - * @param string $type The type of the asset: 'style' or 'script'. - * @param string $handle The asset's handle. - * @param string|array $path The asset's path in the theme. - * @return void - */ - protected function register( string $type, string $handle, $path ):void { - $handle = $this->format_handle( $handle ); - - if ( is_array( $path ) ) { - $_path = $path; - $path = $_path['path']; - $media = $_path['media'] ?? 'all'; - $in_footer = $_path['footer'] ?? true; - } else { - $media = 'all'; - $in_footer = true; - } - - $webpack_path = str_replace( $this->get_webpack_public_path_relative_to_theme(), '', $path ); - - // Read path from Webpack manifest if it exists. - if ( $this->webpack_manifest instanceof Manifest && $this->webpack_manifest->asset( $webpack_path ) ) { - $path = $this->webpack_manifest->asset( $webpack_path ); - } - - $path = trim( $path, '/' ); - $full_path = get_template_directory() . '/' . $path; - $public_uri = get_template_directory_uri() . '/' . $path; - - $hash = null; - if ( file_exists( $full_path ) ) { - $hash = md5_file( $full_path ); - } - - if ( 'style' === $type ) { - wp_register_style( - $handle, - $public_uri, - array(), - $hash, - $media - ); - } else { - wp_register_script( - $handle, - $public_uri, - array(), - $hash, - $in_footer - ); - } - } - - /** - * Enqueue an asset given its handle. - * - * @param string $type The type of the asset: 'style' or 'script'. - * @param string $handle The asset's handle. - * @return void - */ - protected function enqueue( $type, $handle ) { - $handle = $this->format_handle( $handle ); - - add_action( - 'wp_enqueue_scripts', - function () use ( $type, $handle ) { - if ( 'style' === $type ) { - wp_enqueue_style( $handle ); - } else { - wp_enqueue_script( $handle ); - } - } - ); - } - - /** - * Prefix all handles with `theme-`. - * - * @param string $handle The handle to format. - * @return string - */ - protected function format_handle( string $handle ):string { - return 'theme-' . str_replace( '.', '-', $handle ); - } + trigger_error(esc_html($msg), E_USER_NOTICE); + return; + } + + $this->webpack_manifest = new Manifest( + $this->webpack_manifest_filepath, + $this->get_webpack_public_path_relative_to_theme() + ); + } + + add_action('wp_enqueue_scripts', array( $this, 'register_all' )); + add_filter('template_include', array( $this, 'enqueue_all' )); + } + + /** + * Get Webpack dist folder relative to the theme. + * + * @returns string + */ + private function get_webpack_public_path_relative_to_theme():string + { + return trim(str_replace(get_template_directory(), '', dirname($this->webpack_manifest_filepath)), '/') . '/'; + } + + /** + * Register all defined JS and CSS assets with automatic + * versioning based on their content's MD5 hash. + * + * @return void + */ + public function register_all() + { + foreach ($this->config as $name => $config) { + if (isset($config['entries']) && is_array($config['entries'])) { + foreach ($config['entries'] as $entry) { + $pathinfo = pathinfo($entry); + $entry = implode( + DIRECTORY_SEPARATOR, + array( $pathinfo['dirname'] ?? '', $pathinfo['filename'] ) + ); + + $webpack_entry = $this->webpack_manifest->entry($entry); + + if (! $webpack_entry) { + continue; + } + + $webpack_entry->styles->each( + function ($style, $handle) { + $this->register('style', $handle, $style->getAttribute('href')); + } + ); + + $webpack_entry->scripts->each( + function ($script, $handle) { + $this->register('script', $handle, $script->getAttribute('src')); + } + ); + } + } + + if (isset($config['css'])) { + foreach ($config['css'] as $handle => $path) { + $this->register('style', $handle, $path); + + // Enqueue directly if the name of the config is 'all'. + if ('all' === $name) { + wp_enqueue_style($handle); + } + } + } + + if (isset($config['js'])) { + foreach ($config['js'] as $handle => $path) { + $this->register('script', $handle, $path); + + // Enqueue directly if the name of the config is 'all'. + if ('all' === $name) { + wp_enqueue_script($handle); + } + } + } + } + } + + /** + * Enqueue CSS and JS files based on the WordPress template. + * + * @param string $template The template path. + * @return string The template path. + */ + public function enqueue_all($template) + { + $potential_names = array( 'all' ) + $this->get_potential_names($template); + + foreach ($potential_names as $potential_name) { + foreach ($this->config as $name => $config) { + if ((string) $name !== $potential_name) { + continue; + } + + if (isset($config['entries']) && is_array($config['entries'])) { + foreach ($config['entries'] as $entry) { + $pathinfo = pathinfo($entry); + $entry = implode( + DIRECTORY_SEPARATOR, + array( $pathinfo['dirname'] ?? '', $pathinfo['filename'] ) + ); + + $webpack_entry = $this->webpack_manifest->entry($entry); + + if (! $webpack_entry) { + continue; + } + + $webpack_entry->styles->keys()->each( + function ($handle) { + $this->enqueue('style', $handle); + } + ); + + $webpack_entry->scripts->keys()->each( + function ($handle) { + $this->enqueue('script', $handle); + } + ); + } + } + + if (isset($config['css'])) { + foreach ($config['css'] as $handle => $path) { + $this->enqueue('style', $handle); + } + } + + if (isset($config['js'])) { + foreach ($config['js'] as $handle => $path) { + $this->enqueue('script', $handle); + } + } + } + } + + return $template; + } + + /** + * Get all the potential assets group name. + * For a template file `single-post-hello.php`, the following group names + * will be returned: + * + * - single + * - single-post + * - single-post-hello + * + * @param string $template The full template path. + * @return array A list of potential assets name. + */ + protected function get_potential_names(string $template):array + { + $pathinfo = pathinfo($template); + $parts = explode('-', $pathinfo['filename']); + + return array_reduce( + $parts, + function ($acc, $part) { + if (empty($acc)) { + return array( $part ); + } + + $previous_part = $acc[ count($acc) - 1 ]; + $acc[] = $previous_part . '-' . $part; + + return $acc; + }, + array() + ); + } + + + /** + * Register a single asset. + * + * @param string $type The type of the asset: 'style' or 'script'. + * @param string $handle The asset's handle. + * @param string|array $path The asset's path in the theme. + * @return void + */ + protected function register(string $type, string $handle, $path):void + { + $handle = $this->format_handle($handle); + + if (is_array($path)) { + $_path = $path; + $path = $_path['path']; + $media = $_path['media'] ?? 'all'; + $in_footer = $_path['footer'] ?? true; + } else { + $media = 'all'; + $in_footer = true; + } + + $webpack_path = str_replace($this->get_webpack_public_path_relative_to_theme(), '', $path); + + // Read path from Webpack manifest if it exists. + if ($this->webpack_manifest instanceof Manifest && $this->webpack_manifest->asset($webpack_path)) { + $path = $this->webpack_manifest->asset($webpack_path); + } + + $path = trim($path, '/'); + $full_path = get_template_directory() . '/' . $path; + $public_uri = get_template_directory_uri() . '/' . $path; + + $hash = null; + if (file_exists($full_path)) { + $hash = md5_file($full_path); + } + + if ('style' === $type) { + wp_register_style( + $handle, + $public_uri, + array(), + $hash, + $media + ); + } else { + wp_register_script( + $handle, + $public_uri, + array(), + $hash, + $in_footer + ); + } + } + + /** + * Enqueue an asset given its handle. + * + * @param string $type The type of the asset: 'style' or 'script'. + * @param string $handle The asset's handle. + * @return void + */ + protected function enqueue($type, $handle) + { + $handle = $this->format_handle($handle); + + add_action( + 'wp_enqueue_scripts', + function () use ($type, $handle) { + if ('style' === $type) { + wp_enqueue_style($handle); + } else { + wp_enqueue_script($handle); + } + } + ); + } + + /** + * Prefix all handles with `theme-`. + * + * @param string $handle The handle to format. + * @return string + */ + protected function format_handle(string $handle):string + { + return 'theme-' . str_replace('.', '-', $handle); + } } diff --git a/src/Managers/CleanupManager.php b/src/Managers/CleanupManager.php index e29d52a..0236221 100644 --- a/src/Managers/CleanupManager.php +++ b/src/Managers/CleanupManager.php @@ -17,163 +17,175 @@ /** * Cleanup a WordPress project for security and performance. */ -class CleanupManager implements ManagerInterface { - /** - * Wether to enable XML RPC endpoint or not. - * - * @var bool - */ - protected $xml_rpc; - - /** - * Constructor. - * - * @param bool $xml_rpc Enable or disable XML RPC. - */ - public function __construct( bool $xml_rpc = false ) { - $this->xml_rpc = $xml_rpc; - } - - /** - * {@inheritdoc} - */ - public function run() { - // Clean up . - add_action( 'init', array( $this, 'cleanup_head' ) ); - - // Remove WP version from RSS. - add_filter( 'the_generator', array( $this, 'remove_version' ) ); - - // Remove WordPress version from js & css enqueued files. - add_filter( 'style_loader_src', array( $this, 'remove_version_css_js' ), 9999 ); - add_filter( 'script_loader_src', array( $this, 'remove_version_css_js' ), 9999 ); - - // Make login error message the same. - add_filter( 'login_errors', array( $this, 'simple_wordpress_errors' ) ); - - // Remove emojis related files. - add_action( 'init', array( $this, 'disable_emojis' ) ); - - // Remove useless widgets from the dashboard. - add_action( 'wp_dashboard_setup', array( $this, 'remove_dashboard_widgets' ) ); - - // Remove comments from the admin bar. - add_action( 'wp_before_admin_bar_render', array( $this, 'remove_comments_from_admin_bar' ) ); - - // Remove comments from the admin menu. - add_action( 'admin_menu', array( $this, 'remove_comments_from_admin_menu' ) ); - - add_filter( 'xmlrpc_enabled', array( $this, 'xmlrpc_enabled' ) ); - } - - /** - * Remove a lot of useless stuff added by default in WordPress - */ - public function cleanup_head():void { - // EditURI link. - remove_action( 'wp_head', 'rsd_link' ); - // Category feed links. - remove_action( 'wp_head', 'feed_links_extra', 3 ); - // Post and comment feed links. - remove_action( 'wp_head', 'feed_links', 2 ); - // Windows Live Writer. - remove_action( 'wp_head', 'wlwmanifest_link' ); - // Index link. - remove_action( 'wp_head', 'index_rel_link' ); - // Previous link. - remove_action( 'wp_head', 'parent_post_rel_link', 10 ); - // Start link. - remove_action( 'wp_head', 'start_post_rel_link', 10 ); - // Canonical. - remove_action( 'wp_head', 'rel_canonical', 10 ); - // Shortlink. - remove_action( 'wp_head', 'wp_shortlink_wp_head', 10 ); - // Links for adjacent posts. - remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 ); - // WP version. - remove_action( 'wp_head', 'wp_generator' ); - } - - /** - * Remove WordPress version number in meta tags - * - * @return String - */ - public function remove_version() { - return ''; - } - - /** - * Suppress version number in enqued css & js files. - * Except for themes assets where version isn't a security breach. - * - * @see Studiometa\WP\Assets::register() - * - * @param string $src The source path of the asset. - * @return string - */ - public function remove_version_css_js( string $src ):string { - if ( strpos( $src, 'ver=' ) && false === strpos( $src, content_url( 'themes' ) ) ) { - $src = remove_query_arg( 'ver', $src ); - } - - return $src; - } - - /** - * Make all login faillure message the same - * - * @return string Basic login error message - */ - public function simple_wordpress_errors():string { - return __( 'Login credentials are incorrect', 'studio-meta-cleaner' ); - } - - /** - * Remove all occurence of Emoji's in WordPress - */ - public function disable_emojis():void { - remove_action( 'admin_print_styles', 'print_emoji_styles' ); - remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); - remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ); - remove_action( 'wp_print_styles', 'print_emoji_styles' ); - remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' ); - remove_filter( 'the_content_feed', 'wp_staticize_emoji' ); - remove_filter( 'comment_text_rss', 'wp_staticize_emoji' ); - } - - /** - * Remove useless widgets from the dashboard - */ - public function remove_dashboard_widgets():void { - // Remove WordPress activities. - remove_meta_box( 'dashboard_activity', 'dashboard', 'normal' ); - // Remove WordPress events. - remove_meta_box( 'dashboard_primary', 'dashboard', 'side' ); - // Remove WordPress welcome board. - remove_action( 'welcome_panel', 'wp_welcome_panel' ); - } - - /** - * Remove comments from admin Bar - */ - public function remove_comments_from_admin_bar():void { - global $wp_admin_bar; - $wp_admin_bar->remove_menu( 'comments' ); - } - - /** - * Remove comments from admin menu - */ - public function remove_comments_from_admin_menu():void { - // Remove comments admin menu item. - remove_menu_page( 'edit-comments.php' ); - } - - /** - * Enable or disable XML RPC endpoint. - */ - public function xmlrpc_enabled():bool { - return $this->xml_rpc; - } +class CleanupManager implements ManagerInterface +{ + /** + * Wether to enable XML RPC endpoint or not. + * + * @var bool + */ + protected $xml_rpc; + + /** + * Constructor. + * + * @param bool $xml_rpc Enable or disable XML RPC. + */ + public function __construct(bool $xml_rpc = false) + { + $this->xml_rpc = $xml_rpc; + } + + /** + * {@inheritdoc} + */ + public function run() + { + // Clean up . + add_action('init', array( $this, 'cleanup_head' )); + + // Remove WP version from RSS. + add_filter('the_generator', array( $this, 'remove_version' )); + + // Remove WordPress version from js & css enqueued files. + add_filter('style_loader_src', array( $this, 'remove_version_css_js' ), 9999); + add_filter('script_loader_src', array( $this, 'remove_version_css_js' ), 9999); + + // Make login error message the same. + add_filter('login_errors', array( $this, 'simple_wordpress_errors' )); + + // Remove emojis related files. + add_action('init', array( $this, 'disable_emojis' )); + + // Remove useless widgets from the dashboard. + add_action('wp_dashboard_setup', array( $this, 'remove_dashboard_widgets' )); + + // Remove comments from the admin bar. + add_action('wp_before_admin_bar_render', array( $this, 'remove_comments_from_admin_bar' )); + + // Remove comments from the admin menu. + add_action('admin_menu', array( $this, 'remove_comments_from_admin_menu' )); + + add_filter('xmlrpc_enabled', array( $this, 'xmlrpc_enabled' )); + } + + /** + * Remove a lot of useless stuff added by default in WordPress + */ + public function cleanup_head():void + { + // EditURI link. + remove_action('wp_head', 'rsd_link'); + // Category feed links. + remove_action('wp_head', 'feed_links_extra', 3); + // Post and comment feed links. + remove_action('wp_head', 'feed_links', 2); + // Windows Live Writer. + remove_action('wp_head', 'wlwmanifest_link'); + // Index link. + remove_action('wp_head', 'index_rel_link'); + // Previous link. + remove_action('wp_head', 'parent_post_rel_link', 10); + // Start link. + remove_action('wp_head', 'start_post_rel_link', 10); + // Canonical. + remove_action('wp_head', 'rel_canonical', 10); + // Shortlink. + remove_action('wp_head', 'wp_shortlink_wp_head', 10); + // Links for adjacent posts. + remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10); + // WP version. + remove_action('wp_head', 'wp_generator'); + } + + /** + * Remove WordPress version number in meta tags + * + * @return String + */ + public function remove_version() + { + return ''; + } + + /** + * Suppress version number in enqued css & js files. + * Except for themes assets where version isn't a security breach. + * + * @see Studiometa\WP\Assets::register() + * + * @param string $src The source path of the asset. + * @return string + */ + public function remove_version_css_js(string $src):string + { + if (strpos($src, 'ver=') && false === strpos($src, content_url('themes'))) { + $src = remove_query_arg('ver', $src); + } + + return $src; + } + + /** + * Make all login faillure message the same + * + * @return string Basic login error message + */ + public function simple_wordpress_errors():string + { + return __('Login credentials are incorrect', 'studio-meta-cleaner'); + } + + /** + * Remove all occurence of Emoji's in WordPress + */ + public function disable_emojis():void + { + remove_action('admin_print_styles', 'print_emoji_styles'); + remove_action('wp_head', 'print_emoji_detection_script', 7); + remove_action('admin_print_scripts', 'print_emoji_detection_script'); + remove_action('wp_print_styles', 'print_emoji_styles'); + remove_filter('wp_mail', 'wp_staticize_emoji_for_email'); + remove_filter('the_content_feed', 'wp_staticize_emoji'); + remove_filter('comment_text_rss', 'wp_staticize_emoji'); + } + + /** + * Remove useless widgets from the dashboard + */ + public function remove_dashboard_widgets():void + { + // Remove WordPress activities. + remove_meta_box('dashboard_activity', 'dashboard', 'normal'); + // Remove WordPress events. + remove_meta_box('dashboard_primary', 'dashboard', 'side'); + // Remove WordPress welcome board. + remove_action('welcome_panel', 'wp_welcome_panel'); + } + + /** + * Remove comments from admin Bar + */ + public function remove_comments_from_admin_bar():void + { + global $wp_admin_bar; + $wp_admin_bar->remove_menu('comments'); + } + + /** + * Remove comments from admin menu + */ + public function remove_comments_from_admin_menu():void + { + // Remove comments admin menu item. + remove_menu_page('edit-comments.php'); + } + + /** + * Enable or disable XML RPC endpoint. + */ + public function xmlrpc_enabled():bool + { + return $this->xml_rpc; + } } diff --git a/src/Managers/ManagerFactory.php b/src/Managers/ManagerFactory.php index ce0efad..51711fc 100644 --- a/src/Managers/ManagerFactory.php +++ b/src/Managers/ManagerFactory.php @@ -15,16 +15,18 @@ /** * Manager factory class. */ -class ManagerFactory { - /** - * Run the given managers. - * - * @param ManagerInterface[] $managers A list of manager instances. - * @return void - */ - public static function init( array $managers ):void { - foreach ( $managers as $manager ) { - $manager->run(); - } - } +class ManagerFactory +{ + /** + * Run the given managers. + * + * @param ManagerInterface[] $managers A list of manager instances. + * @return void + */ + public static function init(array $managers):void + { + foreach ($managers as $manager) { + $manager->run(); + } + } } diff --git a/src/Managers/ManagerInterface.php b/src/Managers/ManagerInterface.php index 2b6c786..5761b79 100644 --- a/src/Managers/ManagerInterface.php +++ b/src/Managers/ManagerInterface.php @@ -15,11 +15,12 @@ /** * Manager interface. */ -interface ManagerInterface { - /** - * Runs initialization tasks. - * - * @return void - */ - public function run(); +interface ManagerInterface +{ + /** + * Runs initialization tasks. + * + * @return void + */ + public function run(); } diff --git a/src/TransientCleaner.php b/src/TransientCleaner.php index 2fb80d6..1ddbf76 100644 --- a/src/TransientCleaner.php +++ b/src/TransientCleaner.php @@ -15,301 +15,319 @@ /** * TransientCleaner class. */ -class TransientCleaner { - const PREFIX = 'wp_toolkit_transient_cleaner_'; - const OPTION_STORED_TRANSIENTS = self::PREFIX . 'stored_transients'; +class TransientCleaner +{ + const PREFIX = 'wp_toolkit_transient_cleaner_'; + const OPTION_STORED_TRANSIENTS = self::PREFIX . 'stored_transients'; - /** - * Class instance - * - * @var TransientCleaner|null - */ - private static $instance = null; + /** + * Class instance + * + * @var TransientCleaner|null + */ + private static $instance = null; - /** - * Transients configuration. - * - * @var array - */ - private $config = array(); + /** + * Transients configuration. + * + * @var array + */ + private $config = array(); - /** - * Stored transients. - * - * @var array|bool - */ - private $stored_transients; + /** + * Stored transients. + * + * @var array|bool + */ + private $stored_transients; - /** - * Constructor. - * - * @param array $config Configuration. - */ - public function __construct( array $config = array() ) { - // @phpstan-ignore-next-line - $this->set_stored_transients( get_option( self::OPTION_STORED_TRANSIENTS ) ); - $this->set_config( $config ); - $this->define_public_hooks(); - } + /** + * Constructor. + * + * @param array $config Configuration. + */ + public function __construct(array $config = array()) + { + // @phpstan-ignore-next-line + $this->set_stored_transients(get_option(self::OPTION_STORED_TRANSIENTS)); + $this->set_config($config); + $this->define_public_hooks(); + } - /** - * Get class instance. - * - * {@example} - * ```php - * TransientCleaner::get_instance( - * array( - * 'post' => array( - * 'all' => array( - * TransientCleaner::PREFIX . 'transient_key', - * ), - * 'post_type_key' => array( - * TransientCleaner::PREFIX . 'transient_key', - * TransientCleaner::PREFIX . 'transient_key_1', - * ) - * ), - * 'term' => array( - * 'all' => array(), - * 'your_taxonomy_type_key' => array(), - * 'category' => array(), - * ), - * 'option' => array( - * 'all' => array(), - * 'option_key' => array(), - * 'blogdescription' => array(), - * ), - * ) - * ); - * ``` - * - * @param array $config Configuration. - * - * @return TransientCleaner Class instance - */ - public static function get_instance( array $config = array() ) : TransientCleaner { - if ( is_null( self::$instance ) ) { - self::$instance = new TransientCleaner( $config ); - } + /** + * Get class instance. + * + * {@example} + * ```php + * TransientCleaner::get_instance( + * array( + * 'post' => array( + * 'all' => array( + * TransientCleaner::PREFIX . 'transient_key', + * ), + * 'post_type_key' => array( + * TransientCleaner::PREFIX . 'transient_key', + * TransientCleaner::PREFIX . 'transient_key_1', + * ) + * ), + * 'term' => array( + * 'all' => array(), + * 'your_taxonomy_type_key' => array(), + * 'category' => array(), + * ), + * 'option' => array( + * 'all' => array(), + * 'option_key' => array(), + * 'blogdescription' => array(), + * ), + * ) + * ); + * ``` + * + * @param array $config Configuration. + * + * @return TransientCleaner Class instance + */ + public static function get_instance(array $config = array()) : TransientCleaner + { + if (is_null(self::$instance)) { + self::$instance = new TransientCleaner($config); + } - return self::$instance; - } + return self::$instance; + } - /** - * Initialize hooks and filters. - * - * @return void - */ - public function define_public_hooks() { - add_action( 'save_post', array( $this, 'post_transient_cleaner' ), 10, 2 ); - add_action( 'edit_term', array( $this, 'term_transient_cleaner' ), 10, 3 ); - add_action( 'updated_option', array( $this, 'option_transient_cleaner' ), 10, 2 ); - add_action( 'setted_transient', array( $this, 'store_transient_key' ) ); - add_filter( 'pre_update_option_' . self::OPTION_STORED_TRANSIENTS, array( $this, 'merge_stored_transients_option_values' ), 10, 3 ); - add_filter( 'update_option_' . self::OPTION_STORED_TRANSIENTS, array( $this, 'set_stored_transients' ), 20, 1 ); - } + /** + * Initialize hooks and filters. + * + * @return void + */ + public function define_public_hooks() + { + add_action('save_post', array( $this, 'post_transient_cleaner' ), 10, 2); + add_action('edit_term', array( $this, 'term_transient_cleaner' ), 10, 3); + add_action('updated_option', array( $this, 'option_transient_cleaner' ), 10, 2); + add_action('setted_transient', array( $this, 'store_transient_key' )); + add_filter( + 'pre_update_option_' . self::OPTION_STORED_TRANSIENTS, + array( $this, 'merge_stored_transients_option_values' ), + 10, + 3 + ); + add_filter('update_option_' . self::OPTION_STORED_TRANSIENTS, array( $this, 'set_stored_transients' ), 20, 1); + } - /** - * Get config. - * - * @return array - */ - public function get_config() : array { - return $this->config; - } + /** + * Get config. + * + * @return array + */ + public function get_config() : array + { + return $this->config; + } - /** - * Set config. - * - * {@example} - * ```php - * TransientCleaner::get_instance() - * ->set_config( - * array( - * 'post' => array( - * 'all' => array( - * TransientCleaner::PREFIX . 'transient_key', - * ), - * 'post_type_key' => array( - * TransientCleaner::PREFIX . 'transient_key', - * TransientCleaner::PREFIX . 'transient_key_1', - * ) - * ), - * 'term' => array( - * 'all' => array(), - * 'your_taxonomy_type_key' => array(), - * 'category' => array(), - * ), - * 'option' => array( - * 'all' => array(), - * 'option_key' => array(), - * 'blogdescription' => array(), - * ), - * ) - * ); - * ``` - * - * @param array $config Configuration. - * - * @return TransientCleaner - */ - public function set_config( array $config ) : TransientCleaner { - $this->config = $config; + /** + * Set config. + * + * {@example} + * ```php + * TransientCleaner::get_instance() + * ->set_config( + * array( + * 'post' => array( + * 'all' => array( + * TransientCleaner::PREFIX . 'transient_key', + * ), + * 'post_type_key' => array( + * TransientCleaner::PREFIX . 'transient_key', + * TransientCleaner::PREFIX . 'transient_key_1', + * ) + * ), + * 'term' => array( + * 'all' => array(), + * 'your_taxonomy_type_key' => array(), + * 'category' => array(), + * ), + * 'option' => array( + * 'all' => array(), + * 'option_key' => array(), + * 'blogdescription' => array(), + * ), + * ) + * ); + * ``` + * + * @param array $config Configuration. + * + * @return TransientCleaner + */ + public function set_config(array $config) : TransientCleaner + { + $this->config = $config; - return $this; - } + return $this; + } - /** - * Get stored_transients. - * - * @return array|bool - */ - public function get_stored_transients() { - return $this->stored_transients; - } + /** + * Get stored_transients. + * + * @return array|bool + */ + public function get_stored_transients() + { + return $this->stored_transients; + } - /** - * Set stored_transients. - * - * @param array|bool $value New value. - * - * @return TransientCleaner - */ - public function set_stored_transients( $value ) : TransientCleaner { - $this->stored_transients = $value; + /** + * Set stored_transients. + * + * @param array|bool $value New value. + * + * @return TransientCleaner + */ + public function set_stored_transients($value) : TransientCleaner + { + $this->stored_transients = $value; - return $this; - } + return $this; + } - /** - * Merge new stored transient key with others if exists. - * - * @param array|bool $value New value. - * @param array|bool $old_value Old value. - * - * @return array|bool New value - */ - public function merge_stored_transients_option_values( $value, $old_value ) { - // Return `$value` if no previous value. - if ( false === $old_value ) { - return $value; - } + /** + * Merge new stored transient key with others if exists. + * + * @param array|bool $value New value. + * @param array|bool $old_value Old value. + * + * @return array|bool New value + */ + public function merge_stored_transients_option_values($value, $old_value) + { + // Return `$value` if no previous value. + if (false === $old_value) { + return $value; + } - // Do nothing if transient key already exists in stored transients. - if ( is_array( $value ) && is_array( $old_value ) ) { - if ( isset( $value[0] ) && true === in_array( $value[0], $old_value, true ) ) { - return $old_value; - } + // Do nothing if transient key already exists in stored transients. + if (is_array($value) && is_array($old_value)) { + if (isset($value[0]) && true === in_array($value[0], $old_value, true)) { + return $old_value; + } - // Merge old and new values. - return array_merge( $old_value, $value ); - } + // Merge old and new values. + return array_merge($old_value, $value); + } - return $old_value; - } + return $old_value; + } - /** - * Store transient key in option on save. - * - * @param string $transient_key Transient key. - * - * @see self::merge_stored_transients_option_values - * - * @return bool - */ - public function store_transient_key( string $transient_key ) : bool { - if ( - false === strpos( $transient_key, self::PREFIX ) - || false !== strpos( $transient_key, '_lock' ) - ) { - return false; - } + /** + * Store transient key in option on save. + * + * @param string $transient_key Transient key. + * + * @see self::merge_stored_transients_option_values + * + * @return bool + */ + public function store_transient_key(string $transient_key) : bool + { + if (false === strpos($transient_key, self::PREFIX) + || false !== strpos($transient_key, '_lock') + ) { + return false; + } - return update_option( - self::OPTION_STORED_TRANSIENTS, - array( $transient_key ) - ); - } + return update_option( + self::OPTION_STORED_TRANSIENTS, + array( $transient_key ) + ); + } - /** - * Delete transient based on current content and transient key. - * - * @param string $type Content type. - * @param callable $validator Function who control if the transient must be validate or no (must return boolean). - * - * @return bool - */ - protected function object_transient_cleaner( string $type, callable $validator ) : bool { - if ( ! is_array( $this->stored_transients ) || empty( $this->config[ $type ] ) ) { - return false; - } + /** + * Delete transient based on current content and transient key. + * + * @param string $type Content type. + * @param callable $validator Function who control if the transient must be validate or no (must return boolean). + * + * @return bool + */ + protected function object_transient_cleaner(string $type, callable $validator) : bool + { + if (! is_array($this->stored_transients) || empty($this->config[ $type ])) { + return false; + } - foreach ( $this->config[ $type ] as $type_key => $type_values ) { - if ( 'all' !== $type_key && false === call_user_func( $validator, $type_key ) ) { - continue; - } + foreach ($this->config[ $type ] as $type_key => $type_values) { + if ('all' !== $type_key && false === call_user_func($validator, $type_key)) { + continue; + } - foreach ( $type_values as $transient_key ) { - foreach ( $this->stored_transients as $stored_transient ) { - if ( false === strpos( $stored_transient, $transient_key ) ) { - continue; - } + foreach ($type_values as $transient_key) { + foreach ($this->stored_transients as $stored_transient) { + if (false === strpos($stored_transient, $transient_key)) { + continue; + } - delete_transient( $stored_transient ); - } - } - } + delete_transient($stored_transient); + } + } + } - return true; - } + return true; + } - /** - * Clear transient on post save. - * - * @param mixed $post_id post id. - * @param \WP_Post $post post. - * - * @return bool - */ - public function post_transient_cleaner( $post_id, \WP_Post $post ) : bool { - return $this->object_transient_cleaner( - 'post', - function( $key ) use ( $post ) { - return $key === $post->post_type; - } - ); - } + /** + * Clear transient on post save. + * + * @param mixed $post_id post id. + * @param \WP_Post $post post. + * + * @return bool + */ + public function post_transient_cleaner($post_id, \WP_Post $post) : bool + { + return $this->object_transient_cleaner( + 'post', + function ($key) use ($post) { + return $key === $post->post_type; + } + ); + } - /** - * Clear transient on term save. - * - * @param int $term_id Term ID. - * @param int $tt_id Term taxonomy ID. - * @param string $taxonomy Taxonomy. - * - * @return bool - */ - public function term_transient_cleaner( int $term_id, int $tt_id, string $taxonomy ) : bool { - return $this->object_transient_cleaner( - 'term', - function( $key ) use ( $taxonomy ) { - return $key === $taxonomy; - } - ); - } + /** + * Clear transient on term save. + * + * @param int $term_id Term ID. + * @param int $tt_id Term taxonomy ID. + * @param string $taxonomy Taxonomy. + * + * @return bool + */ + public function term_transient_cleaner(int $term_id, int $tt_id, string $taxonomy) : bool + { + return $this->object_transient_cleaner( + 'term', + function ($key) use ($taxonomy) { + return $key === $taxonomy; + } + ); + } - /** - * Clear transient on option save. - * - * @param string $option Option key. - * - * @return bool - */ - public function option_transient_cleaner( string $option ) : bool { - return $this->object_transient_cleaner( - 'option', - function( $key ) use ( $option ) { - return strpos( $option, $key ); - } - ); - } + /** + * Clear transient on option save. + * + * @param string $option Option key. + * + * @return bool + */ + public function option_transient_cleaner(string $option) : bool + { + return $this->object_transient_cleaner( + 'option', + function ($key) use ($option) { + return strpos($option, $key); + } + ); + } } diff --git a/src/helpers.php b/src/helpers.php index dc3fc66..72c6bd4 100644 --- a/src/helpers.php +++ b/src/helpers.php @@ -17,8 +17,9 @@ * @param string $key The variable name. * @return string */ -function env( string $key ): string { - return Env::get( $key ); +function env(string $key): string +{ + return Env::get($key); } /** @@ -28,6 +29,7 @@ function env( string $key ): string { * * @return SymfonyRequest */ -function request(): SymfonyRequest { - return Request::request(); +function request(): SymfonyRequest +{ + return Request::request(); } diff --git a/tests/Builder/PostTypeBuilderTest.php b/tests/Builder/PostTypeBuilderTest.php index 651968f..b7ce983 100644 --- a/tests/Builder/PostTypeBuilderTest.php +++ b/tests/Builder/PostTypeBuilderTest.php @@ -1,43 +1,50 @@ post_type_builder = new PostTypeBuilder( 'product' ); - } - - /** - * Test register function. - * - * @return void - */ - public function test_post_type_builder_register() { - $this->post_type_builder->register(); - - $this->assertTrue( post_type_exists( 'product' ) ); - } - - /** - * Test set_labels function. - * - * @return void - */ - public function test_post_type_builder_set_labels() { - $this->post_type_builder->set_labels( 'Product', 'Products' ); - - $config = $this->post_type_builder->get_config(); - - $this->assertTrue( isset( $config['labels'] ) ); - $this->assertEquals( 'Product', $config['labels']['singular_name'] ); - $this->assertEquals( 'Products', $config['labels']['menu_name'] ); - } +class PostTypeBuilderTest extends WP_UnitTestCase +{ + /** + * Store a PostTypeBuilder instance. + */ + public function setUp():void + { + parent::setUp(); + + $this->post_type_builder = new PostTypeBuilder('product'); + } + + /** + * Test register function. + * + * @return void + */ + public function test_post_type_builder_register() + { + $this->post_type_builder->register(); + + $this->assertTrue(post_type_exists('product')); + } + + /** + * Test set_labels function. + * + * @return void + */ + public function test_post_type_builder_set_labels() + { + $this->post_type_builder->set_labels('Product', 'Products'); + + $config = $this->post_type_builder->get_config(); + + $this->assertTrue(isset($config['labels'])); + $this->assertEquals('Product', $config['labels']['singular_name']); + $this->assertEquals('Products', $config['labels']['menu_name']); + } } diff --git a/tests/Builder/TaxonomyBuilderTest.php b/tests/Builder/TaxonomyBuilderTest.php index 1b09795..462dfdc 100644 --- a/tests/Builder/TaxonomyBuilderTest.php +++ b/tests/Builder/TaxonomyBuilderTest.php @@ -1,56 +1,64 @@ taxonomy_builder = new TaxonomyBuilder( 'category' ); - } - - /** - * Test register function. - * - * @return void - */ - public function test_taxonomy_builder_register() { - $this->taxonomy_builder->register(); - - $this->assertTrue( taxonomy_exists( 'category' ) ); - } - - /** - * Test set_labels function. - * - * @return void - */ - public function test_taxonomy_builder_set_labels() { - $this->taxonomy_builder->set_labels( 'Category', 'Categories' ); - - $config = $this->taxonomy_builder->get_config(); - - $this->assertTrue( isset( $config['labels'] ) ); - $this->assertEquals( 'Category', $config['labels']['singular_name'] ); - $this->assertEquals( 'Categories', $config['labels']['menu_name'] ); - } - - /** - * Test set_post_types function. - * - * @return void - */ - public function test_taxonomy_builder_set_post_types() { - $this->taxonomy_builder->set_post_types( 'tag' ); - - $post_types = $this->taxonomy_builder->get_post_types(); - - $this->assertEquals( 'tag', $post_types ); - } +class TaxonomyBuilderTest extends WP_UnitTestCase +{ + /** + * Store a TaxonomyBuilder instance. + */ + public function setUp():void + { + parent::setUp(); + + $this->taxonomy_builder = new TaxonomyBuilder('category'); + } + + /** + * Test register function. + * + * @return void + */ + public function test_taxonomy_builder_register() + { + $this->taxonomy_builder->register(); + + $this->assertTrue(taxonomy_exists('category')); + } + + /** + * Test set_labels function. + * + * @return void + */ + public function test_taxonomy_builder_set_labels() + { + $this->taxonomy_builder->set_labels('Category', 'Categories'); + + $config = $this->taxonomy_builder->get_config(); + + $this->assertTrue(isset($config['labels'])); + $this->assertEquals('Category', $config['labels']['singular_name']); + $this->assertEquals('Categories', $config['labels']['menu_name']); + } + + /** + * Test set_post_types function. + * + * @return void + */ + public function test_taxonomy_builder_set_post_types() + { + $this->taxonomy_builder->set_post_types('tag'); + + $post_types = $this->taxonomy_builder->get_post_types(); + + $this->assertEquals('tag', $post_types); + } } diff --git a/tests/Helpers/EnvTest.php b/tests/Helpers/EnvTest.php index 5a8e7c7..a986ecc 100644 --- a/tests/Helpers/EnvTest.php +++ b/tests/Helpers/EnvTest.php @@ -1,20 +1,25 @@ assertTrue(is_string(env('missing'))); - $this->assertTrue(is_string(EnvClass::get('missing'))); - } + /** + * Test the request() function + * + * @return void + */ + public function test_type_of_request_function_helper() + { + $this->assertTrue(is_string(env('missing'))); + $this->assertTrue(is_string(EnvClass::get('missing'))); + } } diff --git a/tests/Helpers/PluginTest.php b/tests/Helpers/PluginTest.php index 22be2ac..0a32b82 100644 --- a/tests/Helpers/PluginTest.php +++ b/tests/Helpers/PluginTest.php @@ -1,36 +1,43 @@ assertTrue( - is_bool( Plugin::is_plugin_enabled( 'my-plugin/my-plugin.php' ) ) - ); - } + /** + * Test `is_plugin_enabled` function. + * + * @return void + */ + public function test_is_plugin_enabled() + { + $this->assertTrue( + is_bool(Plugin::is_plugin_enabled('my-plugin/my-plugin.php')) + ); + } - /** - * Test the `disable` method. - * - * @return void - */ - public function test_plugins_have_been_disabled() { - $this->assertTrue( is_plugin_active( 'akismet/akismet.php' ) ); - Plugin::disable( array( 'akismet/akismet.php' ) ); - $this->assertFalse( is_plugin_active( 'akismet/akismet.php' ) ); - } + /** + * Test the `disable` method. + * + * @return void + */ + public function test_plugins_have_been_disabled() + { + $this->assertTrue(is_plugin_active('akismet/akismet.php')); + Plugin::disable(array( 'akismet/akismet.php' )); + $this->assertFalse(is_plugin_active('akismet/akismet.php')); + } } diff --git a/tests/Helpers/RequestTest.php b/tests/Helpers/RequestTest.php index 0b39486..efd2691 100644 --- a/tests/Helpers/RequestTest.php +++ b/tests/Helpers/RequestTest.php @@ -1,5 +1,8 @@ assertTrue($request1 instanceof SymfonyRequest); - $this->assertTrue($request2 instanceof SymfonyRequest); - $this->assertTrue($request1 === $request2); - } + /** + * Test the request() function + * + * @return void + */ + public function test_type_of_request_function_helper() + { + $request1 = RequestClass::request(); + $request2 = request(); + $this->assertTrue($request1 instanceof SymfonyRequest); + $this->assertTrue($request2 instanceof SymfonyRequest); + $this->assertTrue($request1 === $request2); + } } diff --git a/tests/Managers/AssetsManagerTest.php b/tests/Managers/AssetsManagerTest.php index b2d15c4..a23cc4b 100644 --- a/tests/Managers/AssetsManagerTest.php +++ b/tests/Managers/AssetsManagerTest.php @@ -1,88 +1,97 @@ assets_manager = new AssetsManager(); + $this->assets_manager = new AssetsManager(); - // @todo put stubs file in current theme folder for tests - $this->theme_path = realpath( get_template_directory() ); - $this->stubs_path = realpath( __DIR__ . '/__stubs__/theme/' ); + // @todo put stubs file in current theme folder for tests + $this->theme_path = realpath(get_template_directory()); + $this->stubs_path = realpath(__DIR__ . '/__stubs__/theme/'); // phpcs:ignore exec( sprintf( 'rsync -avh %s %s', $this->stubs_path . '/', $this->theme_path . '/' ) ); - $this->assets_manager->run(); - } - - /** - * Test remove css and js version. - * - * @return void - */ - public function test_configs_are_read() { - $this->assertEqualSets( - $this->assets_manager->config, - array( - 'all' => array( - 'entries' => array( - 'css/app.scss', - 'js/app.js', - ), - 'css' => array( - 'editor' => 'dist/editor.css', - ), - ), - 'post' => array( - 'css' => array( - 'post' => 'dist/post.css', - ), - ), - ) - ); - - $this->assertTrue( - $this->assets_manager->webpack_manifest instanceof \Studiometa\WebpackConfig\Manifest - ); - - $this->assertTrue( - $this->assets_manager->webpack_manifest->entry( 'css/app' ) instanceof \Studiometa\WebpackConfig\Entry - ); - - $this->assertTrue( - $this->assets_manager->webpack_manifest->entry( 'js/app' ) instanceof \Studiometa\WebpackConfig\Entry - ); - } - - public function test_assets_are_registered() { - do_action( 'wp_enqueue_scripts' ); - $this->assertTrue( isset( wp_styles()->registered['theme-styles-1234-css'] ) ); - $this->assertTrue( isset( wp_styles()->registered['theme-editor'] ) ); - $this->assertTrue( isset( wp_scripts()->registered['theme-app-1234-js'] ) ); - } - - public function test_entries_are_enqueued() { - apply_filters( 'template_include', 'frontpage' ); - do_action( 'wp_enqueue_scripts' ); - - $this->assertTrue( in_array( 'theme-styles-1234-css', wp_styles()->queue, true ) ); - $this->assertTrue( in_array( 'theme-editor', wp_styles()->queue, true ) ); - $this->assertFalse( in_array( 'theme-post', wp_styles()->queue, true ) ); - - $this->assertTrue( in_array( 'theme-app-1234-js', wp_scripts()->queue, true ) ); - } - - public function test_entries_are_enqueued_by_template() { - apply_filters( 'template_include', 'single-post.php' ); - do_action( 'wp_enqueue_scripts' ); - - $this->assertTrue( in_array( 'theme-styles-1234-css', wp_styles()->queue, true ) ); - $this->assertTrue( in_array( 'theme-editor', wp_styles()->queue, true ) ); - $this->assertTrue( in_array( 'theme-post', wp_styles()->queue, true ) ); - } + $this->assets_manager->run(); + } + + /** + * Test remove css and js version. + * + * @return void + */ + public function test_configs_are_read() + { + $this->assertEqualSets( + $this->assets_manager->config, + array( + 'all' => array( + 'entries' => array( + 'css/app.scss', + 'js/app.js', + ), + 'css' => array( + 'editor' => 'dist/editor.css', + ), + ), + 'post' => array( + 'css' => array( + 'post' => 'dist/post.css', + ), + ), + ) + ); + + $this->assertTrue( + $this->assets_manager->webpack_manifest instanceof \Studiometa\WebpackConfig\Manifest + ); + + $this->assertTrue( + $this->assets_manager->webpack_manifest->entry('css/app') instanceof \Studiometa\WebpackConfig\Entry + ); + + $this->assertTrue( + $this->assets_manager->webpack_manifest->entry('js/app') instanceof \Studiometa\WebpackConfig\Entry + ); + } + + public function test_assets_are_registered() + { + do_action('wp_enqueue_scripts'); + $this->assertTrue(isset(wp_styles()->registered['theme-styles-1234-css'])); + $this->assertTrue(isset(wp_styles()->registered['theme-editor'])); + $this->assertTrue(isset(wp_scripts()->registered['theme-app-1234-js'])); + } + + public function test_entries_are_enqueued() + { + apply_filters('template_include', 'frontpage'); + do_action('wp_enqueue_scripts'); + + $this->assertTrue(in_array('theme-styles-1234-css', wp_styles()->queue, true)); + $this->assertTrue(in_array('theme-editor', wp_styles()->queue, true)); + $this->assertFalse(in_array('theme-post', wp_styles()->queue, true)); + + $this->assertTrue(in_array('theme-app-1234-js', wp_scripts()->queue, true)); + } + + public function test_entries_are_enqueued_by_template() + { + apply_filters('template_include', 'single-post.php'); + do_action('wp_enqueue_scripts'); + + $this->assertTrue(in_array('theme-styles-1234-css', wp_styles()->queue, true)); + $this->assertTrue(in_array('theme-editor', wp_styles()->queue, true)); + $this->assertTrue(in_array('theme-post', wp_styles()->queue, true)); + } } diff --git a/tests/Managers/CleanupManagerTest.php b/tests/Managers/CleanupManagerTest.php index 88d43da..9010fff 100644 --- a/tests/Managers/CleanupManagerTest.php +++ b/tests/Managers/CleanupManagerTest.php @@ -1,49 +1,56 @@ cleanup_manager = new CleanupManager(); - } - - /** - * Test remove css and js version. - * - * @return void - */ - public function test_remove_version_css_js() { - $themes_uri = content_url( 'themes' ); - $theme_src = $themes_uri . '/example/example.js?ver=2.0.0'; - $other_src = 'https://example.org/example.js?ver=2.0.0'; - - $updated_theme_src = $this->cleanup_manager->remove_version_css_js( $theme_src ); - $updated_other_src = $this->cleanup_manager->remove_version_css_js( $other_src ); - - $this->assertFalse( strpos( $updated_other_src, 'ver=' ) ); - $this->assertNotFalse( strpos( $updated_theme_src, 'ver=' ) ); - } - - /** - * Test disable XML RPC. - * - * @return void - */ - public function test_xml_rpc_disabled() { - $this->cleanup_manager->run(); - $this->assertFalse( apply_filters( 'xmlrpc_enabled', true ) ); - } +class CleanupManagerTest extends WP_UnitTestCase +{ + + /** + * CleanupManager. + * + * @var CleanupManager + */ + public $cleanup_manager; + + public function setUp():void + { + parent::setUp(); + + $this->cleanup_manager = new CleanupManager(); + } + + /** + * Test remove css and js version. + * + * @return void + */ + public function test_remove_version_css_js() + { + $themes_uri = content_url('themes'); + $theme_src = $themes_uri . '/example/example.js?ver=2.0.0'; + $other_src = 'https://example.org/example.js?ver=2.0.0'; + + $updated_theme_src = $this->cleanup_manager->remove_version_css_js($theme_src); + $updated_other_src = $this->cleanup_manager->remove_version_css_js($other_src); + + $this->assertFalse(strpos($updated_other_src, 'ver=')); + $this->assertNotFalse(strpos($updated_theme_src, 'ver=')); + } + + /** + * Test disable XML RPC. + * + * @return void + */ + public function test_xml_rpc_disabled() + { + $this->cleanup_manager->run(); + $this->assertFalse(apply_filters('xmlrpc_enabled', true)); + } } diff --git a/tests/Managers/ManagerFactoryTest.php b/tests/Managers/ManagerFactoryTest.php index 9810e13..64d7a4c 100644 --- a/tests/Managers/ManagerFactoryTest.php +++ b/tests/Managers/ManagerFactoryTest.php @@ -1,41 +1,48 @@ assertFalse( self::$has_run ); + /** + * Test init method. + * Should trigger the manager instances `run` method. + * + * @return void + */ + public function test_init() + { + $this->assertFalse(self::$has_run); - ManagerFactory::init( - array( new Manager() ) - ); + ManagerFactory::init( + array( new Manager() ) + ); - $this->assertTrue( self::$has_run ); - } + $this->assertTrue(self::$has_run); + } } diff --git a/tests/TransientCleanerTest.php b/tests/TransientCleanerTest.php index 913111f..6d98266 100644 --- a/tests/TransientCleanerTest.php +++ b/tests/TransientCleanerTest.php @@ -1,174 +1,195 @@ config = array( - 'post' => array( - 'post' => array( - self::POST_TRANSIENT_KEY, - ), - ), - 'term' => array( - 'post_tag' => array( - self::TERM_TRANSIENT_KEY, - ), - ), - 'option' => array( - 'baz_option' => array( - self::OPTION_TRANSIENT_KEY, - ), - ), - ); - - $this->transient_cleaner = TransientCleaner::get_instance( $this->config ); - - set_transient( self::POST_TRANSIENT_KEY, 'foo' ); - set_transient( self::TERM_TRANSIENT_KEY, 'bar' ); - set_transient( self::OPTION_TRANSIENT_KEY, 'baz' ); - - // Mock stored transient because WordPress `update_option` don't work in tests. - $this->transient_cleaner->set_stored_transients( - array( - self::POST_TRANSIENT_KEY, - self::TERM_TRANSIENT_KEY, - self::OPTION_TRANSIENT_KEY, - ) - ); - } - - /** - * Test set/get config. - * - * @return void - */ - public function test_set_get_config() { - $config_1 = $this->transient_cleaner->get_config(); - $this->transient_cleaner->set_config( - array_merge( - $config_1, - array( 'foo' => array() ) - ) - ); - $config_2 = $this->transient_cleaner->get_config(); - - $this->assertIsArray( $config_2 ); - $this->assertNotEmpty( $config_2 ); - $this->assertEquals( count( $config_1 ), count( $config_2 ) - 1 ); - } - - /** - * Test set/get stored_transients. - * - * @return void - */ - public function test_set_get_stored_transients() { - $stored_transients_1 = $this->transient_cleaner->get_stored_transients(); - $this->transient_cleaner->set_stored_transients( - array( 'foo' ) - ); - $stored_transients_2 = $this->transient_cleaner->get_stored_transients(); - - $this->assertEquals( array( 'foo' ), $stored_transients_2 ); - } - - /** - * Test merge_stored_transients_option_values. - * - * @return void - */ - public function test_merge_stored_transients_option_values() { - $test_no_old_value = $this->transient_cleaner->merge_stored_transients_option_values( 'foo', false ); - $test_old_value = $this->transient_cleaner->merge_stored_transients_option_values( 'foo', 'foo_old' ); - $test_merge_values = $this->transient_cleaner->merge_stored_transients_option_values( array( 'foo' ), array( 'foo_old' ) ); - $test_merge_values_already_exists = $this->transient_cleaner->merge_stored_transients_option_values( array( 'foo' ), array( 'foo_old', 'foo' ) ); - - $this->assertEquals( 'foo', $test_no_old_value ); - $this->assertEquals( 'foo_old', $test_old_value ); - $this->assertEquals( array( 'foo_old', 'foo' ), $test_merge_values ); - $this->assertEquals( array( 'foo_old', 'foo' ), $test_merge_values_already_exists ); - } - - /** - * Test store transient. - * - * @return void - */ - public function test_store_transient_key() { - $test_fail = $this->transient_cleaner->store_transient_key( 'foo' ); - $test_success = $this->transient_cleaner->store_transient_key( TransientCleaner::PREFIX . 'foo' ); - - $this->assertFalse( $test_fail ); - $this->assertTrue( $test_success ); - } - - /** - * Test post transient cleaner. - * - * @return void - */ - public function test_post_transient_cleaner() { - $post = $this->factory->post->create_and_get(); - $test_success = $this->transient_cleaner->post_transient_cleaner( 1, $post ); - - $config_1 = $this->transient_cleaner->get_config(); - unset( $config_1['post'] ); - $this->transient_cleaner->set_config( $config_1 ); - - $test_fail = $this->transient_cleaner->post_transient_cleaner( 1, $post ); - - $this->assertTrue( $test_success ); - $this->assertFalse( $test_fail ); - } - - /** - * Test term transient cleaner. - * - * @return void - */ - public function test_term_transient_cleaner() { - $taxonomy = 'post_tag'; - $test_success = $this->transient_cleaner->term_transient_cleaner( 1, 1, $taxonomy ); - - $config_1 = $this->transient_cleaner->get_config(); - unset( $config_1['term'] ); - $this->transient_cleaner->set_config( $config_1 ); - - $test_fail = $this->transient_cleaner->term_transient_cleaner( 1, 1, $taxonomy ); - - $this->assertTrue( $test_success ); - $this->assertFalse( $test_fail ); - } - - /** - * Test option transient cleaner. - * - * @return void - */ - public function test_option_transient_cleaner() { - $option = 'baz_option'; - $test_success = $this->transient_cleaner->option_transient_cleaner( $option ); - - $config_1 = $this->transient_cleaner->get_config(); - unset( $config_1['option'] ); - $this->transient_cleaner->set_config( $config_1 ); - - $test_fail = $this->transient_cleaner->option_transient_cleaner( $option ); - - $this->assertTrue( $test_success ); - $this->assertFalse( $test_fail ); - } +class TransientCleanerTest extends WP_UnitTestCase +{ + const POST_TRANSIENT_KEY = TransientCleaner::PREFIX . 'transient_cleaner_post'; + const TERM_TRANSIENT_KEY = TransientCleaner::PREFIX . 'transient_cleaner_term'; + const OPTION_TRANSIENT_KEY = TransientCleaner::PREFIX . 'transient_cleaner_option'; + + public $transient_cleaner; + + /** + * Initialize transient cleaner based on config. + */ + public function setUp():void + { + parent::setUp(); + + $this->config = array( + 'post' => array( + 'post' => array( + self::POST_TRANSIENT_KEY, + ), + ), + 'term' => array( + 'post_tag' => array( + self::TERM_TRANSIENT_KEY, + ), + ), + 'option' => array( + 'baz_option' => array( + self::OPTION_TRANSIENT_KEY, + ), + ), + ); + + $this->transient_cleaner = TransientCleaner::get_instance($this->config); + + set_transient(self::POST_TRANSIENT_KEY, 'foo'); + set_transient(self::TERM_TRANSIENT_KEY, 'bar'); + set_transient(self::OPTION_TRANSIENT_KEY, 'baz'); + + // Mock stored transient because WordPress `update_option` don't work in tests. + $this->transient_cleaner->set_stored_transients( + array( + self::POST_TRANSIENT_KEY, + self::TERM_TRANSIENT_KEY, + self::OPTION_TRANSIENT_KEY, + ) + ); + } + + /** + * Test set/get config. + * + * @return void + */ + public function test_set_get_config() + { + $config_1 = $this->transient_cleaner->get_config(); + $this->transient_cleaner->set_config( + array_merge( + $config_1, + array( 'foo' => array() ) + ) + ); + $config_2 = $this->transient_cleaner->get_config(); + + $this->assertIsArray($config_2); + $this->assertNotEmpty($config_2); + $this->assertEquals(count($config_1), count($config_2) - 1); + } + + /** + * Test set/get stored_transients. + * + * @return void + */ + public function test_set_get_stored_transients() + { + $stored_transients_1 = $this->transient_cleaner->get_stored_transients(); + $this->transient_cleaner->set_stored_transients( + array( 'foo' ) + ); + $stored_transients_2 = $this->transient_cleaner->get_stored_transients(); + + $this->assertEquals(array( 'foo' ), $stored_transients_2); + } + + /** + * Test merge_stored_transients_option_values. + * + * @return void + */ + public function test_merge_stored_transients_option_values() + { + $test_no_old_value = $this->transient_cleaner->merge_stored_transients_option_values('foo', false); + $test_old_value = $this->transient_cleaner->merge_stored_transients_option_values('foo', 'foo_old'); + + $test_merge_values = $this->transient_cleaner->merge_stored_transients_option_values( + array( 'foo' ), + array( 'foo_old' ) + ); + $test_merge_values_already_exists = $this->transient_cleaner->merge_stored_transients_option_values( + array( 'foo' ), + array( 'foo_old', 'foo' ) + ); + + $this->assertEquals('foo', $test_no_old_value); + $this->assertEquals('foo_old', $test_old_value); + $this->assertEquals(array( 'foo_old', 'foo' ), $test_merge_values); + $this->assertEquals(array( 'foo_old', 'foo' ), $test_merge_values_already_exists); + } + + /** + * Test store transient. + * + * @return void + */ + public function test_store_transient_key() + { + $test_fail = $this->transient_cleaner->store_transient_key('foo'); + $test_success = $this->transient_cleaner->store_transient_key(TransientCleaner::PREFIX . 'foo'); + + $this->assertFalse($test_fail); + $this->assertTrue($test_success); + } + + /** + * Test post transient cleaner. + * + * @return void + */ + public function test_post_transient_cleaner() + { + $post = $this->factory->post->create_and_get(); + $test_success = $this->transient_cleaner->post_transient_cleaner(1, $post); + + $config_1 = $this->transient_cleaner->get_config(); + unset($config_1['post']); + $this->transient_cleaner->set_config($config_1); + + $test_fail = $this->transient_cleaner->post_transient_cleaner(1, $post); + + $this->assertTrue($test_success); + $this->assertFalse($test_fail); + } + + /** + * Test term transient cleaner. + * + * @return void + */ + public function test_term_transient_cleaner() + { + $taxonomy = 'post_tag'; + $test_success = $this->transient_cleaner->term_transient_cleaner(1, 1, $taxonomy); + + $config_1 = $this->transient_cleaner->get_config(); + unset($config_1['term']); + $this->transient_cleaner->set_config($config_1); + + $test_fail = $this->transient_cleaner->term_transient_cleaner(1, 1, $taxonomy); + + $this->assertTrue($test_success); + $this->assertFalse($test_fail); + } + + /** + * Test option transient cleaner. + * + * @return void + */ + public function test_option_transient_cleaner() + { + $option = 'baz_option'; + $test_success = $this->transient_cleaner->option_transient_cleaner($option); + + $config_1 = $this->transient_cleaner->get_config(); + unset($config_1['option']); + $this->transient_cleaner->set_config($config_1); + + $test_fail = $this->transient_cleaner->option_transient_cleaner($option); + + $this->assertTrue($test_success); + $this->assertFalse($test_fail); + } } diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 30ef095..2b45e25 100755 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -5,18 +5,16 @@ * @package studiometa/wp-toolkit */ -$_tests_dir = getenv( 'WP_TESTS_DIR' ); +$_tests_dir = getenv('WP_TESTS_DIR'); -if ( ! $_tests_dir ) { - $_tests_dir = rtrim( sys_get_temp_dir(), '/\\' ) . '/wordpress-tests-lib'; +if (! $_tests_dir) { + $_tests_dir = rtrim(sys_get_temp_dir(), '/\\') . '/wordpress-tests-lib'; } -if ( ! file_exists( $_tests_dir . '/includes/functions.php' ) ) { - echo "Could not find $_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped - exit( 1 ); +if (! file_exists($_tests_dir . '/includes/functions.php')) { + echo "Could not find $_tests_dir/includes/functions.php, have you run bin/install-wp-tests.sh ?" . PHP_EOL; + exit(1); } // Start up the WP testing environment. require $_tests_dir . '/includes/bootstrap.php'; - - From 55f4da162cb9c872f3da8cd869f2e108d046a316 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:46:36 +0100 Subject: [PATCH 09/25] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d77ed8a..ed54684 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,3 +18,4 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), - ⚠️ Rename the `PluginHelper` class to `Plugin` ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - **CleanupManager:** Disable XML-RPC by default ([#21](https://github.com/studiometa/wp-toolkit/pull/21)) +- Remove WordPress Code Standard sniffs for PHPCS ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) From 8419b9ad3fd34661ff3e66b6a18ee3ada660b7af Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 19 Oct 2023 14:02:10 +0200 Subject: [PATCH 10/25] Add an email manager --- src/Managers/EmailManager.php | 41 +++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 src/Managers/EmailManager.php diff --git a/src/Managers/EmailManager.php b/src/Managers/EmailManager.php new file mode 100644 index 0000000..b73d7bc --- /dev/null +++ b/src/Managers/EmailManager.php @@ -0,0 +1,41 @@ +Host = env( 'MAIL_HOST' ); + $mailer->Port = (int) env( 'MAIL_PORT' ); + $mailer->Username = env( 'MAIL_USERNAME' ); + $mailer->Password = env( 'MAIL_PASSWORD' ); + $mailer->SMTPAuth = 'true' === env( 'MAIL_AUTH' ); + $mailer->SMTPSecure = env( 'MAIL_ENCRYPTION' ); + $mailer->IsSMTP(); + // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + } +} From ab511af214186f132cc7625c87c0c812a422c340 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Thu, 19 Oct 2023 14:26:20 +0200 Subject: [PATCH 11/25] Add support for email success and failure logs --- composer.json | 11 ++- composer.lock | 154 +++++++++++++++++++++++++++++++++- src/Managers/EmailManager.php | 64 +++++++++++++- 3 files changed, 223 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 6b7679a..638a769 100644 --- a/composer.json +++ b/composer.json @@ -6,10 +6,12 @@ "type": "library", "require": { "php": "^8.1", - "symfony/yaml": "^6.4|^7.0", + "monolog/monolog": "^2.9|^3.0", + "psr/log": "^1.1", "studiometa/webpack-config": "^5.0", - "wecodemore/wordpress-early-hook": "^1.2", - "symfony/http-foundation": "^6.4|^7.0" + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "wecodemore/wordpress-early-hook": "^1.2" }, "require-dev": { "squizlabs/php_codesniffer": "^3.4", @@ -46,6 +48,7 @@ "allow-plugins": { "dealerdirect/phpcodesniffer-composer-installer": true, "phpstan/extension-installer": true - } + }, + "sort-packages": true } } diff --git a/composer.lock b/composer.lock index 405f3e3..f87375c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "f46208b8750d1d7d0f6a899a2cf219b8", + "content-hash": "89f9329c94e91984010b7c885d1eda52", "packages": [ { "name": "anahkiasen/html-object", @@ -52,6 +52,158 @@ }, "time": "2017-05-31T07:52:45+00:00" }, + { + "name": "monolog/monolog", + "version": "2.9.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "reference": "f259e2b15fb95494c83f52d3caad003bbf5ffaa1", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "1.0.0 || 2.0.0 || 3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^2.4.9 || ^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2@dev", + "guzzlehttp/guzzle": "^7.4", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "phpspec/prophecy": "^1.15", + "phpstan/phpstan": "^0.12.91", + "phpunit/phpunit": "^8.5.14", + "predis/predis": "^1.1 || ^2.0", + "rollbar/rollbar": "^1.3 || ^2 || ^3", + "ruflin/elastica": "^7", + "swiftmailer/swiftmailer": "^5.3|^6.0", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/2.9.1" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2023-02-06T13:44:46+00:00" + }, + { + "name": "psr/log", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11", + "reference": "d49695b909c3b7628b6289db5479a1c204601f11", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "Psr/Log/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/1.1.4" + }, + "time": "2021-05-03T11:20:27+00:00" + }, { "name": "studiometa/webpack-config", "version": "5.3.0", diff --git a/src/Managers/EmailManager.php b/src/Managers/EmailManager.php index b73d7bc..d75b0e4 100644 --- a/src/Managers/EmailManager.php +++ b/src/Managers/EmailManager.php @@ -7,17 +7,47 @@ namespace Studiometa\WPToolkit\Managers; +use WP_Error; +use Monolog\Logger; +use Monolog\Handler\StreamHandler; +use Psr\Log\LoggerInterface; use PHPMailer\PHPMailer\PHPMailer; use function Studiometa\WPToolkit\env; /** Class **/ class EmailManager implements ManagerInterface { + /** + * Logger instance. + * + * @var LoggerInterface|null; + */ + private $logger; + + /** + * Class constructor. + * + * @param LoggerInterface|null $logger A logger instance to log mail actions. + */ + public function __construct( ?LoggerInterface $logger = null ) { + if ( ! is_null( $logger ) ) { + $this->logger = $logger; + } elseif ( env( 'MAIL_LOG' ) ) { + $this->logger = new Logger( 'email' ); + $this->logger->pushHandler( new StreamHandler( env( 'MAIL_LOG' ) ) ); + } + } + /** * {@inheritdoc} */ public function run() { if ( 'smtp' === env( 'MAIL_MAILER' ) ) { - add_action( 'phpmailer_init', array( $this, 'configure_smtp' ), 10, 1 ); + add_action( 'phpmailer_init', array( $this, 'configure_smtp' ) ); + } + + if ( $this->logger ) { + add_action( 'wp_mail_succeeded', array( $this, 'log_success' ) ); + add_action( 'wp_mail_failed', array( $this, 'log_failure' ) ); } } @@ -38,4 +68,36 @@ public function configure_smtp( PHPMailer $mailer ): void { $mailer->IsSMTP(); // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase } + + /** + * Log successfully sent mails. + * + * @param array{to: string[], subject: string, message: string, headers: string[], attachments: string[]} $mail_data An array containing the email recipient(s), subject, message, headers, and attachments. + * + * @return void + */ + public function log_success( array $mail_data ): void { + if ( $this->logger ) { + $this->logger->info( 'Mail sent', $mail_data ); + } + } + + /** + * Log failure happening when sending mails. + * + * @param WP_Error $error The error sent. + * + * @return void + */ + public function log_failure( WP_Error $error ): void { + if ( $this->logger ) { + /** + * Mail data. + * + * @var array + */ + $mail_data = $error->get_error_data(); + $this->logger->error( $error->get_error_message(), $mail_data ); + } + } } From 9cb754e5aa9c19bd75bd340b5222f8dc1a7750c2 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 20 Oct 2023 11:30:45 +0200 Subject: [PATCH 12/25] Add PHPMailer configuration tests --- tests/Managers/EmailManagerTest.php | 42 +++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 tests/Managers/EmailManagerTest.php diff --git a/tests/Managers/EmailManagerTest.php b/tests/Managers/EmailManagerTest.php new file mode 100644 index 0000000..7f7fb5d --- /dev/null +++ b/tests/Managers/EmailManagerTest.php @@ -0,0 +1,42 @@ +run(); + + // Trigger phpmailer configuration action. + global $phpmailer; + assert( $phpmailer instanceof PHPMailer\PHPMailer\PHPMailer ); + do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); + + // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + $this->assertSame( $phpmailer->Mailer, 'smtp' ); + $this->assertSame( $phpmailer->Host, '127.0.0.1' ); + $this->assertSame( $phpmailer->Port, 1025 ); + $this->assertSame( $phpmailer->Username, 'test' ); + $this->assertSame( $phpmailer->Password, 'test' ); + $this->assertSame( $phpmailer->SMTPAuth, true ); + $this->assertSame( $phpmailer->SMTPSecure, 'tls' ); + // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase + } +} From 4a7d74f0337374e84eb097432e7d3ce50d97a221 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:54:05 +0100 Subject: [PATCH 13/25] Lint files --- src/Managers/EmailManager.php | 166 +++++++++++++++------------- tests/Managers/EmailManagerTest.php | 61 +++++----- 2 files changed, 122 insertions(+), 105 deletions(-) diff --git a/src/Managers/EmailManager.php b/src/Managers/EmailManager.php index d75b0e4..eeda05d 100644 --- a/src/Managers/EmailManager.php +++ b/src/Managers/EmailManager.php @@ -15,89 +15,101 @@ use function Studiometa\WPToolkit\env; /** Class **/ -class EmailManager implements ManagerInterface { - /** - * Logger instance. - * - * @var LoggerInterface|null; - */ - private $logger; +class EmailManager implements ManagerInterface +{ + /** + * Logger instance. + * + * @var LoggerInterface|null; + */ + private $logger; - /** - * Class constructor. - * - * @param LoggerInterface|null $logger A logger instance to log mail actions. - */ - public function __construct( ?LoggerInterface $logger = null ) { - if ( ! is_null( $logger ) ) { - $this->logger = $logger; - } elseif ( env( 'MAIL_LOG' ) ) { - $this->logger = new Logger( 'email' ); - $this->logger->pushHandler( new StreamHandler( env( 'MAIL_LOG' ) ) ); - } - } + /** + * Class constructor. + * + * @param LoggerInterface|null $logger A logger instance to log mail actions. + */ + public function __construct(?LoggerInterface $logger = null) + { + if (! is_null($logger)) { + $this->logger = $logger; + } elseif (env('MAIL_LOG')) { + $this->logger = new Logger('email'); + $this->logger->pushHandler(new StreamHandler(env('MAIL_LOG'))); + } + } - /** - * {@inheritdoc} - */ - public function run() { - if ( 'smtp' === env( 'MAIL_MAILER' ) ) { - add_action( 'phpmailer_init', array( $this, 'configure_smtp' ) ); - } + /** + * {@inheritdoc} + */ + public function run() + { + if ('smtp' === env('MAIL_MAILER')) { + add_action('phpmailer_init', array( $this, 'configure_smtp' )); + } - if ( $this->logger ) { - add_action( 'wp_mail_succeeded', array( $this, 'log_success' ) ); - add_action( 'wp_mail_failed', array( $this, 'log_failure' ) ); - } - } + if ($this->logger) { + add_action('wp_mail_succeeded', array( $this, 'log_success' )); + add_action('wp_mail_failed', array( $this, 'log_failure' )); + } + } - /** - * Configure SMTP server to send mails. - * - * @param PHPMailer $mailer The PHPMailer instance. - * @return void - */ - public function configure_smtp( PHPMailer $mailer ): void { + /** + * Configure SMTP server to send mails. + * + * @param PHPMailer $mailer The PHPMailer instance. + * @return void + */ + public function configure_smtp(PHPMailer $mailer): void + { // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $mailer->Host = env( 'MAIL_HOST' ); - $mailer->Port = (int) env( 'MAIL_PORT' ); - $mailer->Username = env( 'MAIL_USERNAME' ); - $mailer->Password = env( 'MAIL_PASSWORD' ); - $mailer->SMTPAuth = 'true' === env( 'MAIL_AUTH' ); - $mailer->SMTPSecure = env( 'MAIL_ENCRYPTION' ); - $mailer->IsSMTP(); + $mailer->Host = env('MAIL_HOST'); + $mailer->Port = (int) env('MAIL_PORT'); + $mailer->Username = env('MAIL_USERNAME'); + $mailer->Password = env('MAIL_PASSWORD'); + $mailer->SMTPAuth = 'true' === env('MAIL_AUTH'); + $mailer->SMTPSecure = env('MAIL_ENCRYPTION'); + $mailer->IsSMTP(); // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } + } - /** - * Log successfully sent mails. - * - * @param array{to: string[], subject: string, message: string, headers: string[], attachments: string[]} $mail_data An array containing the email recipient(s), subject, message, headers, and attachments. - * - * @return void - */ - public function log_success( array $mail_data ): void { - if ( $this->logger ) { - $this->logger->info( 'Mail sent', $mail_data ); - } - } + /** + * Log successfully sent mails. + * + * @param array{ + * to: string[], + * subject: string, + * message: string, + * headers: string[], + * attachments: string[] + * } $mail_data An array containing the email recipient(s), subject, message, headers, and attachments. + * + * @return void + */ + public function log_success(array $mail_data): void + { + if ($this->logger) { + $this->logger->info('Mail sent', $mail_data); + } + } - /** - * Log failure happening when sending mails. - * - * @param WP_Error $error The error sent. - * - * @return void - */ - public function log_failure( WP_Error $error ): void { - if ( $this->logger ) { - /** - * Mail data. - * - * @var array - */ - $mail_data = $error->get_error_data(); - $this->logger->error( $error->get_error_message(), $mail_data ); - } - } + /** + * Log failure happening when sending mails. + * + * @param WP_Error $error The error sent. + * + * @return void + */ + public function log_failure(WP_Error $error): void + { + if ($this->logger) { + /** + * Mail data. + * + * @var array + */ + $mail_data = $error->get_error_data(); + $this->logger->error($error->get_error_message(), $mail_data); + } + } } diff --git a/tests/Managers/EmailManagerTest.php b/tests/Managers/EmailManagerTest.php index 7f7fb5d..3d25f08 100644 --- a/tests/Managers/EmailManagerTest.php +++ b/tests/Managers/EmailManagerTest.php @@ -1,42 +1,47 @@ run(); + $manager = new EmailManager(); + $manager->run(); - // Trigger phpmailer configuration action. - global $phpmailer; - assert( $phpmailer instanceof PHPMailer\PHPMailer\PHPMailer ); - do_action_ref_array( 'phpmailer_init', array( &$phpmailer ) ); + // Trigger phpmailer configuration action. + global $phpmailer; + assert($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer); + do_action_ref_array('phpmailer_init', array( &$phpmailer )); // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - $this->assertSame( $phpmailer->Mailer, 'smtp' ); - $this->assertSame( $phpmailer->Host, '127.0.0.1' ); - $this->assertSame( $phpmailer->Port, 1025 ); - $this->assertSame( $phpmailer->Username, 'test' ); - $this->assertSame( $phpmailer->Password, 'test' ); - $this->assertSame( $phpmailer->SMTPAuth, true ); - $this->assertSame( $phpmailer->SMTPSecure, 'tls' ); + $this->assertSame($phpmailer->Mailer, 'smtp'); + $this->assertSame($phpmailer->Host, '127.0.0.1'); + $this->assertSame($phpmailer->Port, 1025); + $this->assertSame($phpmailer->Username, 'test'); + $this->assertSame($phpmailer->Password, 'test'); + $this->assertSame($phpmailer->SMTPAuth, true); + $this->assertSame($phpmailer->SMTPSecure, 'tls'); // phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase - } + } } From a38670b9ebd662766c1d0723faad240225873eb9 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:55:19 +0100 Subject: [PATCH 14/25] Fix tests --- tests/Managers/EmailManagerTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/Managers/EmailManagerTest.php b/tests/Managers/EmailManagerTest.php index 3d25f08..617fe1f 100644 --- a/tests/Managers/EmailManagerTest.php +++ b/tests/Managers/EmailManagerTest.php @@ -4,6 +4,7 @@ use WP_UnitTestCase; use Studiometa\WPToolkit\Managers\EmailManager; +use PHPMailer\PHPMailer\PHPMailer; /** * EmailManagerTest test case. @@ -31,7 +32,7 @@ public function test_smtp_configuration() // Trigger phpmailer configuration action. global $phpmailer; - assert($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer); + assert($phpmailer instanceof PHPMailer); do_action_ref_array('phpmailer_init', array( &$phpmailer )); // phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase From dd593597110a13857e2d6b335788443c76a9c989 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 16:56:38 +0100 Subject: [PATCH 15/25] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed54684..790ea77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added +- Add an `EmailManager` to configure `PHPMailer` via environment variables ([#22](https://github.com/studiometa/wp-toolkit/pull/22)) - Add a `Plugin::disable` method to the `Plugin` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `request` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `Request` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) From 3b9a7043b7a03f414c916c65f8d75e0103f1f73d Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:01:44 +0100 Subject: [PATCH 16/25] Fix GitHub actions --- .github/workflows/tests.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2a1b28b..3dd9f52 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -15,10 +15,9 @@ jobs: fail-fast: false matrix: php-versions: - - '7.3' - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' steps: - uses: actions/checkout@v2 @@ -52,10 +51,9 @@ jobs: fail-fast: false matrix: php-versions: - - '7.3' - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' steps: - uses: actions/checkout@v2 @@ -90,10 +88,9 @@ jobs: fail-fast: false matrix: php-versions: - - '7.3' - - '7.4' - - '8.0' - '8.1' + - '8.2' + - '8.3' services: mysql: From d423aa4a41a28b9917cbe6d98aae1f90b2a91dfa Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:05:45 +0100 Subject: [PATCH 17/25] Remove the version from the composer.json file --- composer.json | 1 - composer.lock | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 638a769..4525fbd 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,5 @@ { "name": "studiometa/wp-toolkit", - "version": "2.0.0", "description": "WordPress utilities for Studio Meta.", "license": "MIT", "type": "library", diff --git a/composer.lock b/composer.lock index f87375c..5ad034e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "89f9329c94e91984010b7c885d1eda52", + "content-hash": "4ae9d81b385c475f971ba5f532cf6190", "packages": [ { "name": "anahkiasen/html-object", From 90baa9ebe710c6d83d4c3acf9240dc1d8daa7537 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:06:52 +0100 Subject: [PATCH 18/25] Lint files --- phpstan.neon | 2 +- src/TransientCleaner.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/phpstan.neon b/phpstan.neon index e94f403..12467c4 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -11,5 +11,5 @@ parameters: paths: - ./src/ ignoreErrors: - - message: '#^Parameter \#1 \$value of method\.#' + - message: '#^Action callback returns bool but should not return anything\.$#' path: ./src/TransientCleaner.php diff --git a/src/TransientCleaner.php b/src/TransientCleaner.php index 1ddbf76..04f0d91 100644 --- a/src/TransientCleaner.php +++ b/src/TransientCleaner.php @@ -198,10 +198,11 @@ public function set_stored_transients($value) : TransientCleaner * * @param array|bool $value New value. * @param array|bool $old_value Old value. + * @param string $option Option name. * * @return array|bool New value */ - public function merge_stored_transients_option_values($value, $old_value) + public function merge_stored_transients_option_values($value, $old_value, $option) { // Return `$value` if no previous value. if (false === $old_value) { From 711741138a0f4fe84fc8db995078e658b8ea002a Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:10:33 +0100 Subject: [PATCH 19/25] Add methods to easily enqueue assets --- src/Managers/AssetsManager.php | 77 +++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/src/Managers/AssetsManager.php b/src/Managers/AssetsManager.php index 050892a..02137ea 100644 --- a/src/Managers/AssetsManager.php +++ b/src/Managers/AssetsManager.php @@ -69,15 +69,14 @@ public function __construct(?string $configuration_filepath = null, ?string $web } } - // phpcs:ignore Generic.Commenting.DocComment.MissingShort /** - * @inheritdoc + * {@inheritdoc} */ public function run() { if (! file_exists($this->configuration_filepath)) { $msg = 'No assets configuration file found.'; - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error trigger_error(esc_html($msg), E_USER_NOTICE); return; } @@ -88,7 +87,7 @@ public function run() if ($this->webpack_manifest_filepath) { if (! file_exists($this->webpack_manifest_filepath)) { $msg = sprintf('No webpack manifest file found in `%s`.', $this->webpack_manifest_filepath); - // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error trigger_error(esc_html($msg), E_USER_NOTICE); return; } @@ -103,6 +102,34 @@ public function run() add_filter('template_include', array( $this, 'enqueue_all' )); } + /** + * Enqueue a stylesheet. + * + * @param string $handle The handle for this stylesheet. + * @param string $path The stylesheet path in the theme `src/` folder. + * + * @return void + */ + public function enqueue_style(string $handle, string $path): void + { + $this->register('style', $handle, $path); + $this->enqueue('style', $handle); + } + + /** + * Enqueue a script. + * + * @param string $handle The handle for this script. + * @param string $path The stylesheet path in the theme `src/` folder. + * + * @return void + */ + public function enqueue_script(string $handle, string $path): void + { + $this->register('script', $handle, $path); + $this->enqueue('script', $handle); + } + /** * Get Webpack dist folder relative to the theme. * @@ -156,7 +183,7 @@ function ($script, $handle) { // Enqueue directly if the name of the config is 'all'. if ('all' === $name) { - wp_enqueue_style($handle); + $this->enqueue_in_action('style', $handle); } } } @@ -167,7 +194,7 @@ function ($script, $handle) { // Enqueue directly if the name of the config is 'all'. if ('all' === $name) { - wp_enqueue_script($handle); + $this->enqueue_in_action('script', $handle); } } } @@ -206,13 +233,13 @@ public function enqueue_all($template) $webpack_entry->styles->keys()->each( function ($handle) { - $this->enqueue('style', $handle); + $this->enqueue_in_action('style', $handle); } ); $webpack_entry->scripts->keys()->each( function ($handle) { - $this->enqueue('script', $handle); + $this->enqueue_in_action('script', $handle); } ); } @@ -220,13 +247,13 @@ function ($handle) { if (isset($config['css'])) { foreach ($config['css'] as $handle => $path) { - $this->enqueue('style', $handle); + $this->enqueue_in_action('style', $handle); } } if (isset($config['js'])) { foreach ($config['js'] as $handle => $path) { - $this->enqueue('script', $handle); + $this->enqueue_in_action('script', $handle); } } } @@ -327,28 +354,40 @@ protected function register(string $type, string $handle, $path):void } /** - * Enqueue an asset given its handle. + * Enqueue an asset given its handle in the `wp_enqueue_scripts` action. * * @param string $type The type of the asset: 'style' or 'script'. * @param string $handle The asset's handle. * @return void */ - protected function enqueue($type, $handle) + protected function enqueue_in_action($type, $handle) { - $handle = $this->format_handle($handle); - add_action( 'wp_enqueue_scripts', function () use ($type, $handle) { - if ('style' === $type) { - wp_enqueue_style($handle); - } else { - wp_enqueue_script($handle); - } + $this->enqueue($type, $handle); } ); } + /** + * Enqueue an asset directly given its handle. + * + * @param string $type The type of the asset: 'style' or 'script'. + * @param string $handle The asset's handle. + * @return void + */ + protected function enqueue($type, $handle) + { + $handle = $this->format_handle($handle); + + if ('style' === $type) { + wp_enqueue_style($handle); + } else { + wp_enqueue_script($handle); + } + } + /** * Prefix all handles with `theme-`. * From 7d3521be528d8b39a8c87eedc609ae94ddee63c6 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:20:27 +0100 Subject: [PATCH 20/25] Add tests --- tests/Managers/AssetsManagerTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/Managers/AssetsManagerTest.php b/tests/Managers/AssetsManagerTest.php index a23cc4b..16ec741 100644 --- a/tests/Managers/AssetsManagerTest.php +++ b/tests/Managers/AssetsManagerTest.php @@ -10,6 +10,8 @@ */ class AssetsManagerTest extends WP_UnitTestCase { + public AssetsManager $assets_manager; + public function set_up():void { parent::set_up(); @@ -94,4 +96,15 @@ public function test_entries_are_enqueued_by_template() $this->assertTrue(in_array('theme-editor', wp_styles()->queue, true)); $this->assertTrue(in_array('theme-post', wp_styles()->queue, true)); } + + + public function test_entries_are_enqeued_by_method() { + $this->assets_manager->enqueue_script( 'method-app', 'app.js' ); + $this->assertTrue(in_array('theme-method-app', wp_scripts()->queue, true)); + $this->assertTrue(str_ends_with(wp_scripts()->query('theme-method-app')->src, '/app.1234.js')); + + $this->assets_manager->enqueue_style( 'method-styles', 'styles.css' ); + $this->assertTrue(in_array('theme-method-styles', wp_styles()->queue, true)); + $this->assertTrue(str_ends_with(wp_styles()->query('theme-method-styles')->src, '/styles.1234.css')); + } } From b0464753135a3b1fcf1b1d0efd3cb6b7ae989728 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:21:36 +0100 Subject: [PATCH 21/25] Update the changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 790ea77..bfc6879 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Added - Add an `EmailManager` to configure `PHPMailer` via environment variables ([#22](https://github.com/studiometa/wp-toolkit/pull/22)) +- Add `enqueue_script($handle, $path)` and `enqueue_style($handle, $path)` method to the `AssetsManager` class ([#23](https://github.com/studiometa/wp-toolkit/pull/23)) - Add a `Plugin::disable` method to the `Plugin` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `request` helper function ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) - Add a `Request` helper class ([#26](https://github.com/studiometa/wp-toolkit/pull/26)) From 765468f71bf93cffeaa65c5542010a04d936ee5c Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:21:58 +0100 Subject: [PATCH 22/25] Lint files --- tests/Managers/AssetsManagerTest.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/Managers/AssetsManagerTest.php b/tests/Managers/AssetsManagerTest.php index 16ec741..fa569c9 100644 --- a/tests/Managers/AssetsManagerTest.php +++ b/tests/Managers/AssetsManagerTest.php @@ -98,12 +98,13 @@ public function test_entries_are_enqueued_by_template() } - public function test_entries_are_enqeued_by_method() { - $this->assets_manager->enqueue_script( 'method-app', 'app.js' ); + public function test_entries_are_enqeued_by_method() + { + $this->assets_manager->enqueue_script('method-app', 'app.js'); $this->assertTrue(in_array('theme-method-app', wp_scripts()->queue, true)); $this->assertTrue(str_ends_with(wp_scripts()->query('theme-method-app')->src, '/app.1234.js')); - $this->assets_manager->enqueue_style( 'method-styles', 'styles.css' ); + $this->assets_manager->enqueue_style('method-styles', 'styles.css'); $this->assertTrue(in_array('theme-method-styles', wp_styles()->queue, true)); $this->assertTrue(str_ends_with(wp_styles()->query('theme-method-styles')->src, '/styles.1234.css')); } From 0d61749a924a6b3267d694233d63fe3a86e8e9ed Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:24:50 +0100 Subject: [PATCH 23/25] Fix tests --- src/TransientCleaner.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/TransientCleaner.php b/src/TransientCleaner.php index 04f0d91..1019c86 100644 --- a/src/TransientCleaner.php +++ b/src/TransientCleaner.php @@ -202,7 +202,7 @@ public function set_stored_transients($value) : TransientCleaner * * @return array|bool New value */ - public function merge_stored_transients_option_values($value, $old_value, $option) + public function merge_stored_transients_option_values($value, $old_value, ?string $option = '') { // Return `$value` if no previous value. if (false === $old_value) { From bd8ec7633fb642cb18508f18618efc81b178e867 Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:27:47 +0100 Subject: [PATCH 24/25] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfc6879..68db2aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## [Unreleased] +## v2.0.0 - 2024.03.08 + ### Added - Add an `EmailManager` to configure `PHPMailer` via environment variables ([#22](https://github.com/studiometa/wp-toolkit/pull/22)) From e19c308c9846770f4f2f81c90d2b4e15ed09532d Mon Sep 17 00:00:00 2001 From: Titouan Mathis Date: Fri, 8 Mar 2024 17:28:49 +0100 Subject: [PATCH 25/25] Add a GitHub action to create releases --- .github/workflows/release.yml | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0d4e296 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,40 @@ +name: Release + +on: + push: + tags: + - '*.*.*' + +jobs: + release: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: '0' + + # @see https://github.com/actions/create-release/issues/38#issuecomment-715327220 + # @see https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#environment-files + - name: Prepare the changelog from the tag message + id: prepare_changelog + run: | + PRERELEASE=false + # Check release type + if [[ $GITHUB_REF_NAME =~ 'alpha' || $GITHUB_REF_NAME =~ 'beta' || $GITHUB_REF_NAME =~ 'rc' ]]; then + echo "This is a prerelease." + PRERELEASE=true + fi + echo "is_prerelease=$PRERELEASE" >> $GITHUB_ENV + + # @see https://github.com/actions/create-release + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: v${{ github.ref_name }} + body: Please refer to [CHANGELOG.md](https://github.com/studiometa/wp-toolkit/blob/${{ github.ref_name }}/CHANGELOG.md) for details. + draft: false + prerelease: ${{ env.is_prerelease }}