From 2cb1ce471faf305bd0f9a7d1c179cf62e1f4126c Mon Sep 17 00:00:00 2001 From: Marie Comet Date: Tue, 19 May 2026 14:26:47 +0200 Subject: [PATCH 01/18] add example to FAQ block --- src/faq/block.json | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/faq/block.json b/src/faq/block.json index 024a625..372550f 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -16,6 +16,30 @@ "default": true } }, + "example": { + "attributes": { + "isAccordion": true + }, + "innerBlocks": [ + { + "name": "blockparty/faq-item", + "innerBlocks": [ + { + "name": "blockparty/faq-question", + "attributes": { + "question": "Lorem ipsum" + } + }, + { + "name": "blockparty/faq-answer", + "attributes": { + "answer": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." + } + } + ] + } + ] + }, "textdomain": "blockparty-faq", "editorScript": "file:./index.js", "viewScript": "file:./script.js", From 4bc48a5d24d50377072a8103172696c7a67df760 Mon Sep 17 00:00:00 2001 From: mricoul Date: Fri, 26 Jun 2026 12:17:51 +0200 Subject: [PATCH 02/18] chore: reformat package.json scripts --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index b604620..f44064b 100644 --- a/package.json +++ b/package.json @@ -12,11 +12,11 @@ "lint:js": "wp-scripts lint-js", "start": "wp-scripts start", "packages-update": "wp-scripts packages-update", - "start:env": "wp-env start --config=./wp-env.json", - "stop:env": "wp-env stop --config=./wp-env.json", - "setup:env": "wp-env run cli wp plugin install wordpress-seo --activate --allow-root", "make-pot": "wp i18n make-pot . languages/blockparty-faq.pot --exclude=\"src\" --domain=blockparty-faq", - "make-json": "wp i18n make-json languages/blockparty-faq-fr_FR.po languages/ --no-purge" + "make-json": "wp i18n make-json languages/blockparty-faq-fr_FR.po languages/ --no-purge", + "env:start": "wp-env start --config=./wp-env.json", + "env:stop": "wp-env stop --config=./wp-env.json", + "env:setup": "wp-env run cli wp plugin install wordpress-seo --activate --allow-root" }, "dependencies": { "@beapi/be-a11y": "^1.7.2", From e5fcee68cd3ccfb8b56e7c636e080b7279c11add Mon Sep 17 00:00:00 2001 From: mricoul Date: Fri, 26 Jun 2026 12:19:50 +0200 Subject: [PATCH 03/18] chore: untrack composer.lock --- .gitignore | 3 + composer.lock | 5322 ------------------------------------------------- 2 files changed, 3 insertions(+), 5322 deletions(-) delete mode 100644 composer.lock diff --git a/.gitignore b/.gitignore index 839a99e..e5abd4a 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,6 @@ Thumbs.db .wp-env.override.json phpcs.xml phpunit.xml + +# Composer +composer.lock diff --git a/composer.lock b/composer.lock deleted file mode 100644 index b7817aa..0000000 --- a/composer.lock +++ /dev/null @@ -1,5322 +0,0 @@ -{ - "_readme": [ - "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", - "This file is @generated automatically" - ], - "content-hash": "aa0afa15dfd3fc66e77eb40bb4450781", - "packages": [ - { - "name": "composer/installers", - "version": "v2.3.0", - "source": { - "type": "git", - "url": "https://github.com/composer/installers.git", - "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/12fb2dfe5e16183de69e784a7b84046c43d97e8e", - "reference": "12fb2dfe5e16183de69e784a7b84046c43d97e8e", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^1.0 || ^2.0", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "composer/composer": "^1.10.27 || ^2.7", - "composer/semver": "^1.7.2 || ^3.4.0", - "phpstan/phpstan": "^1.11", - "phpstan/phpstan-phpunit": "^1", - "symfony/phpunit-bridge": "^7.1.1", - "symfony/process": "^5 || ^6 || ^7" - }, - "type": "composer-plugin", - "extra": { - "class": "Composer\\Installers\\Plugin", - "branch-alias": { - "dev-main": "2.x-dev" - }, - "plugin-modifies-install-path": true - }, - "autoload": { - "psr-4": { - "Composer\\Installers\\": "src/Composer/Installers" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Kyle Robinson Young", - "email": "kyle@dontkry.com", - "homepage": "https://github.com/shama" - } - ], - "description": "A multi-framework Composer library installer", - "homepage": "https://composer.github.io/installers/", - "keywords": [ - "Dolibarr", - "Eliasis", - "Hurad", - "ImageCMS", - "Kanboard", - "Lan Management System", - "MODX Evo", - "MantisBT", - "Mautic", - "Maya", - "OXID", - "Plentymarkets", - "Porto", - "RadPHP", - "SMF", - "Starbug", - "Thelia", - "Whmcs", - "WolfCMS", - "agl", - "annotatecms", - "attogram", - "bitrix", - "cakephp", - "chef", - "cockpit", - "codeigniter", - "concrete5", - "concreteCMS", - "croogo", - "dokuwiki", - "drupal", - "eZ Platform", - "elgg", - "expressionengine", - "fuelphp", - "grav", - "installer", - "itop", - "known", - "kohana", - "laravel", - "lavalite", - "lithium", - "magento", - "majima", - "mako", - "matomo", - "mediawiki", - "miaoxing", - "modulework", - "modx", - "moodle", - "osclass", - "pantheon", - "phpbb", - "piwik", - "ppi", - "processwire", - "puppet", - "pxcms", - "reindex", - "roundcube", - "shopware", - "silverstripe", - "sydes", - "sylius", - "tastyigniter", - "wordpress", - "yawik", - "zend", - "zikula" - ], - "support": { - "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v2.3.0" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-06-24T20:46:46+00:00" - } - ], - "packages-dev": [ - { - "name": "amphp/amp", - "version": "v2.6.5", - "source": { - "type": "git", - "url": "https://github.com/amphp/amp.git", - "reference": "d7dda98dae26e56f3f6fcfbf1c1f819c9a993207" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/amp/zipball/d7dda98dae26e56f3f6fcfbf1c1f819c9a993207", - "reference": "d7dda98dae26e56f3f6fcfbf1c1f819c9a993207", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1", - "ext-json": "*", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^7 | ^8 | ^9", - "react/promise": "^2", - "vimeo/psalm": "^3.12" - }, - "type": "library", - "autoload": { - "files": [ - "lib/functions.php", - "lib/Internal/functions.php" - ], - "psr-4": { - "Amp\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Daniel Lowrey", - "email": "rdlowrey@php.net" - }, - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Bob Weinand", - "email": "bobwei9@hotmail.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A non-blocking concurrency framework for PHP applications.", - "homepage": "https://amphp.org/amp", - "keywords": [ - "async", - "asynchronous", - "awaitable", - "concurrency", - "event", - "event-loop", - "future", - "non-blocking", - "promise" - ], - "support": { - "irc": "irc://irc.freenode.org/amphp", - "issues": "https://github.com/amphp/amp/issues", - "source": "https://github.com/amphp/amp/tree/v2.6.5" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2025-09-03T19:41:28+00:00" - }, - { - "name": "amphp/byte-stream", - "version": "v1.8.2", - "source": { - "type": "git", - "url": "https://github.com/amphp/byte-stream.git", - "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/amphp/byte-stream/zipball/4f0e968ba3798a423730f567b1b50d3441c16ddc", - "reference": "4f0e968ba3798a423730f567b1b50d3441c16ddc", - "shasum": "" - }, - "require": { - "amphp/amp": "^2", - "php": ">=7.1" - }, - "require-dev": { - "amphp/php-cs-fixer-config": "dev-master", - "amphp/phpunit-util": "^1.4", - "friendsofphp/php-cs-fixer": "^2.3", - "jetbrains/phpstorm-stubs": "^2019.3", - "phpunit/phpunit": "^6 || ^7 || ^8", - "psalm/phar": "^3.11.4" - }, - "type": "library", - "autoload": { - "files": [ - "lib/functions.php" - ], - "psr-4": { - "Amp\\ByteStream\\": "lib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Aaron Piotrowski", - "email": "aaron@trowski.com" - }, - { - "name": "Niklas Keller", - "email": "me@kelunik.com" - } - ], - "description": "A stream abstraction to make working with non-blocking I/O simple.", - "homepage": "https://amphp.org/byte-stream", - "keywords": [ - "amp", - "amphp", - "async", - "io", - "non-blocking", - "stream" - ], - "support": { - "issues": "https://github.com/amphp/byte-stream/issues", - "source": "https://github.com/amphp/byte-stream/tree/v1.8.2" - }, - "funding": [ - { - "url": "https://github.com/amphp", - "type": "github" - } - ], - "time": "2024-04-13T18:00:56+00:00" - }, - { - "name": "composer/pcre", - "version": "3.3.2", - "source": { - "type": "git", - "url": "https://github.com/composer/pcre.git", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "conflict": { - "phpstan/phpstan": "<1.11.10" - }, - "require-dev": { - "phpstan/phpstan": "^1.12 || ^2", - "phpstan/phpstan-strict-rules": "^1 || ^2", - "phpunit/phpunit": "^8 || ^9" - }, - "type": "library", - "extra": { - "phpstan": { - "includes": [ - "extension.neon" - ] - }, - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Pcre\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - } - ], - "description": "PCRE wrapping library that offers type-safe preg_* replacements.", - "keywords": [ - "PCRE", - "preg", - "regex", - "regular expression" - ], - "support": { - "issues": "https://github.com/composer/pcre/issues", - "source": "https://github.com/composer/pcre/tree/3.3.2" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-11-12T16:29:46+00:00" - }, - { - "name": "composer/semver", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/composer/semver.git", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", - "shasum": "" - }, - "require": { - "php": "^5.3.2 || ^7.0 || ^8.0" - }, - "require-dev": { - "phpstan/phpstan": "^1.11", - "symfony/phpunit-bridge": "^3 || ^7" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Composer\\Semver\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Nils Adermann", - "email": "naderman@naderman.de", - "homepage": "http://www.naderman.de" - }, - { - "name": "Jordi Boggiano", - "email": "j.boggiano@seld.be", - "homepage": "http://seld.be" - }, - { - "name": "Rob Bast", - "email": "rob.bast@gmail.com", - "homepage": "http://robbast.nl" - } - ], - "description": "Semver library that offers utilities, version constraint parsing and validation.", - "keywords": [ - "semantic", - "semver", - "validation", - "versioning" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/semver/issues", - "source": "https://github.com/composer/semver/tree/3.4.4" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - } - ], - "time": "2025-08-20T19:15:30+00:00" - }, - { - "name": "composer/xdebug-handler", - "version": "3.0.5", - "source": { - "type": "git", - "url": "https://github.com/composer/xdebug-handler.git", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/composer/xdebug-handler/zipball/6c1925561632e83d60a44492e0b344cf48ab85ef", - "reference": "6c1925561632e83d60a44492e0b344cf48ab85ef", - "shasum": "" - }, - "require": { - "composer/pcre": "^1 || ^2 || ^3", - "php": "^7.2.5 || ^8.0", - "psr/log": "^1 || ^2 || ^3" - }, - "require-dev": { - "phpstan/phpstan": "^1.0", - "phpstan/phpstan-strict-rules": "^1.1", - "phpunit/phpunit": "^8.5 || ^9.6 || ^10.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Composer\\XdebugHandler\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "John Stevenson", - "email": "john-stevenson@blueyonder.co.uk" - } - ], - "description": "Restarts a process without Xdebug.", - "keywords": [ - "Xdebug", - "performance" - ], - "support": { - "irc": "ircs://irc.libera.chat:6697/composer", - "issues": "https://github.com/composer/xdebug-handler/issues", - "source": "https://github.com/composer/xdebug-handler/tree/3.0.5" - }, - "funding": [ - { - "url": "https://packagist.com", - "type": "custom" - }, - { - "url": "https://github.com/composer", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/composer/composer", - "type": "tidelift" - } - ], - "time": "2024-05-06T16:37:16+00:00" - }, - { - "name": "dealerdirect/phpcodesniffer-composer-installer", - "version": "v1.2.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/composer-installer.git", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/845eb62303d2ca9b289ef216356568ccc075ffd1", - "reference": "845eb62303d2ca9b289ef216356568ccc075ffd1", - "shasum": "" - }, - "require": { - "composer-plugin-api": "^2.2", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.1.0 || ^4.0" - }, - "require-dev": { - "composer/composer": "^2.2", - "ext-json": "*", - "ext-zip": "*", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^9.0 || ^10.0.0@dev", - "yoast/phpunit-polyfills": "^1.0" - }, - "type": "composer-plugin", - "extra": { - "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" - }, - "autoload": { - "psr-4": { - "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Franck Nijhof", - "email": "opensource@frenck.dev", - "homepage": "https://frenck.dev", - "role": "Open source developer" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" - } - ], - "description": "PHP_CodeSniffer Standards Composer Installer Plugin", - "keywords": [ - "PHPCodeSniffer", - "PHP_CodeSniffer", - "code quality", - "codesniffer", - "composer", - "installer", - "phpcbf", - "phpcs", - "plugin", - "qa", - "quality", - "standard", - "standards", - "style guide", - "stylecheck", - "tests" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/composer-installer/issues", - "security": "https://github.com/PHPCSStandards/composer-installer/security/policy", - "source": "https://github.com/PHPCSStandards/composer-installer" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-11-11T04:32:07+00:00" - }, - { - "name": "dnoegel/php-xdg-base-dir", - "version": "v0.1.1", - "source": { - "type": "git", - "url": "https://github.com/dnoegel/php-xdg-base-dir.git", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dnoegel/php-xdg-base-dir/zipball/8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "reference": "8f8a6e48c5ecb0f991c2fdcf5f154a47d85f9ffd", - "shasum": "" - }, - "require": { - "php": ">=5.3.2" - }, - "require-dev": { - "phpunit/phpunit": "~7.0|~6.0|~5.0|~4.8.35" - }, - "type": "library", - "autoload": { - "psr-4": { - "XdgBaseDir\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "implementation of xdg base directory specification for php", - "support": { - "issues": "https://github.com/dnoegel/php-xdg-base-dir/issues", - "source": "https://github.com/dnoegel/php-xdg-base-dir/tree/v0.1.1" - }, - "time": "2019-12-04T15:06:13+00:00" - }, - { - "name": "doctrine/deprecations", - "version": "1.1.5", - "source": { - "type": "git", - "url": "https://github.com/doctrine/deprecations.git", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/doctrine/deprecations/zipball/459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "reference": "459c2f5dd3d6a4633d3b5f46ee2b1c40f57d3f38", - "shasum": "" - }, - "require": { - "php": "^7.1 || ^8.0" - }, - "conflict": { - "phpunit/phpunit": "<=7.5 || >=13" - }, - "require-dev": { - "doctrine/coding-standard": "^9 || ^12 || ^13", - "phpstan/phpstan": "1.4.10 || 2.1.11", - "phpstan/phpstan-phpunit": "^1.0 || ^2", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6 || ^10.5 || ^11.5 || ^12", - "psr/log": "^1 || ^2 || ^3" - }, - "suggest": { - "psr/log": "Allows logging deprecations via PSR-3 logger implementation" - }, - "type": "library", - "autoload": { - "psr-4": { - "Doctrine\\Deprecations\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "A small layer on top of trigger_error(E_USER_DEPRECATED) or PSR-3 logging with options to disable all deprecations or selectively for packages.", - "homepage": "https://www.doctrine-project.org/", - "support": { - "issues": "https://github.com/doctrine/deprecations/issues", - "source": "https://github.com/doctrine/deprecations/tree/1.1.5" - }, - "time": "2025-04-07T20:06:18+00:00" - }, - { - "name": "felixfbecker/advanced-json-rpc", - "version": "v3.2.1", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-advanced-json-rpc.git", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/b5f37dbff9a8ad360ca341f3240dc1c168b45447", - "reference": "b5f37dbff9a8ad360ca341f3240dc1c168b45447", - "shasum": "" - }, - "require": { - "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "php": "^7.1 || ^8.0", - "phpdocumentor/reflection-docblock": "^4.3.4 || ^5.0.0" - }, - "require-dev": { - "phpunit/phpunit": "^7.0 || ^8.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "AdvancedJsonRpc\\": "lib/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "A more advanced JSONRPC implementation", - "support": { - "issues": "https://github.com/felixfbecker/php-advanced-json-rpc/issues", - "source": "https://github.com/felixfbecker/php-advanced-json-rpc/tree/v3.2.1" - }, - "time": "2021-06-11T22:34:44+00:00" - }, - { - "name": "felixfbecker/language-server-protocol", - "version": "v1.5.3", - "source": { - "type": "git", - "url": "https://github.com/felixfbecker/php-language-server-protocol.git", - "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/felixfbecker/php-language-server-protocol/zipball/a9e113dbc7d849e35b8776da39edaf4313b7b6c9", - "reference": "a9e113dbc7d849e35b8776da39edaf4313b7b6c9", - "shasum": "" - }, - "require": { - "php": ">=7.1" - }, - "require-dev": { - "phpstan/phpstan": "*", - "squizlabs/php_codesniffer": "^3.1", - "vimeo/psalm": "^4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "LanguageServerProtocol\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "ISC" - ], - "authors": [ - { - "name": "Felix Becker", - "email": "felix.b@outlook.com" - } - ], - "description": "PHP classes for the Language Server Protocol", - "keywords": [ - "language", - "microsoft", - "php", - "server" - ], - "support": { - "issues": "https://github.com/felixfbecker/php-language-server-protocol/issues", - "source": "https://github.com/felixfbecker/php-language-server-protocol/tree/v1.5.3" - }, - "time": "2024-04-30T00:40:11+00:00" - }, - { - "name": "fidry/cpu-core-counter", - "version": "1.3.0", - "source": { - "type": "git", - "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", - "reference": "db9508f7b1474469d9d3c53b86f817e344732678", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "fidry/makefile": "^0.2.0", - "fidry/php-cs-fixer-config": "^1.1.2", - "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-deprecation-rules": "^2.0.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^8.5.31 || ^9.5.26", - "webmozarts/strict-phpunit": "^7.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Fidry\\CpuCoreCounter\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Théo FIDRY", - "email": "theo.fidry@gmail.com" - } - ], - "description": "Tiny utility to get the number of CPU cores.", - "keywords": [ - "CPU", - "core" - ], - "support": { - "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" - }, - "funding": [ - { - "url": "https://github.com/theofidry", - "type": "github" - } - ], - "time": "2025-08-14T07:29:31+00:00" - }, - { - "name": "humanmade/psalm-plugin-wordpress", - "version": "3.1.2", - "source": { - "type": "git", - "url": "https://github.com/psalm/psalm-plugin-wordpress.git", - "reference": "3f4689ad5264eee7b37121053cec810a3754f7e4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/psalm/psalm-plugin-wordpress/zipball/3f4689ad5264eee7b37121053cec810a3754f7e4", - "reference": "3f4689ad5264eee7b37121053cec810a3754f7e4", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "php-stubs/wordpress-globals": "^0.2.0", - "php-stubs/wordpress-stubs": "^6.0", - "php-stubs/wp-cli-stubs": "^2.7", - "vimeo/psalm": "^5 || ^6", - "wp-hooks/wordpress-core": "^1.3.0" - }, - "require-dev": { - "humanmade/coding-standards": "^1.2", - "phpunit/phpunit": "^9.0", - "psalm/plugin-phpunit": "^0.18.4" - }, - "type": "psalm-plugin", - "extra": { - "psalm": { - "pluginClass": "PsalmWordPress\\Plugin" - } - }, - "autoload": { - "psr-4": { - "PsalmWordPress\\": [ - "." - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "kkmuffme", - "role": "Maintainer" - }, - { - "name": "Joe Hoyle", - "role": "Creator" - } - ], - "description": "WordPress stubs and plugin for Psalm static analysis.", - "support": { - "issues": "https://github.com/psalm/psalm-plugin-wordpress/issues", - "source": "https://github.com/psalm/psalm-plugin-wordpress" - }, - "time": "2024-04-01T10:36:11+00:00" - }, - { - "name": "netresearch/jsonmapper", - "version": "v4.5.0", - "source": { - "type": "git", - "url": "https://github.com/cweiske/jsonmapper.git", - "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/8e76efb98ee8b6afc54687045e1b8dba55ac76e5", - "reference": "8e76efb98ee8b6afc54687045e1b8dba55ac76e5", - "shasum": "" - }, - "require": { - "ext-json": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*", - "php": ">=7.1" - }, - "require-dev": { - "phpunit/phpunit": "~7.5 || ~8.0 || ~9.0 || ~10.0", - "squizlabs/php_codesniffer": "~3.5" - }, - "type": "library", - "autoload": { - "psr-0": { - "JsonMapper": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "OSL-3.0" - ], - "authors": [ - { - "name": "Christian Weiske", - "email": "cweiske@cweiske.de", - "homepage": "http://github.com/cweiske/jsonmapper/", - "role": "Developer" - } - ], - "description": "Map nested JSON structures onto PHP classes", - "support": { - "email": "cweiske@cweiske.de", - "issues": "https://github.com/cweiske/jsonmapper/issues", - "source": "https://github.com/cweiske/jsonmapper/tree/v4.5.0" - }, - "time": "2024-09-08T10:13:13+00:00" - }, - { - "name": "nikic/php-parser", - "version": "v4.19.5", - "source": { - "type": "git", - "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/51bd93cc741b7fc3d63d20b6bdcd99fdaa359837", - "reference": "51bd93cc741b7fc3d63d20b6bdcd99fdaa359837", - "shasum": "" - }, - "require": { - "ext-tokenizer": "*", - "php": ">=7.1" - }, - "require-dev": { - "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" - }, - "bin": [ - "bin/php-parse" - ], - "type": "library", - "autoload": { - "psr-4": { - "PhpParser\\": "lib/PhpParser" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Nikita Popov" - } - ], - "description": "A PHP parser written in PHP", - "keywords": [ - "parser", - "php" - ], - "support": { - "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.5" - }, - "time": "2025-12-06T11:45:25+00:00" - }, - { - "name": "overtrue/phplint", - "version": "9.6.3", - "source": { - "type": "git", - "url": "https://github.com/overtrue/phplint.git", - "reference": "b0ec1d07b37a37e7fc872c8bdbddacadcecbe047" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/overtrue/phplint/zipball/b0ec1d07b37a37e7fc872c8bdbddacadcecbe047", - "reference": "b0ec1d07b37a37e7fc872c8bdbddacadcecbe047", - "shasum": "" - }, - "require": { - "composer-runtime-api": "^2.0", - "ext-dom": "*", - "ext-json": "*", - "ext-mbstring": "*", - "php": "^8.1", - "symfony/cache": "^6.4 || ^7.0", - "symfony/console": "^6.4 || ^7.0", - "symfony/event-dispatcher": "^6.4 || ^7.0", - "symfony/finder": "^6.4 || ^7.0", - "symfony/options-resolver": "^6.4 || ^7.0", - "symfony/process": "^6.4 || ^7.0", - "symfony/yaml": "^6.4 || ^7.0" - }, - "require-dev": { - "bamarni/composer-bin-plugin": "^1.4", - "brainmaestro/composer-git-hooks": "^3.0.0", - "jetbrains/phpstorm-stubs": "^2024.1", - "php-parallel-lint/php-console-highlighter": "^1.0" - }, - "bin": [ - "bin/phplint" - ], - "type": "library", - "extra": { - "hooks": { - "pre-commit": [ - "composer style:fix", - "composer code:check" - ] - }, - "bamarni-bin": { - "bin-links": true, - "forward-command": true, - "target-directory": "vendor-bin" - }, - "branch-alias": { - "dev-main": "9.6.x-dev" - } - }, - "autoload": { - "psr-4": { - "Overtrue\\PHPLint\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "overtrue", - "email": "anzhengchao@gmail.com" - }, - { - "name": "Laurent Laville", - "homepage": "https://github.com/llaville" - } - ], - "description": "`phplint` is a tool that can speed up linting of php files by running several lint processes at once.", - "keywords": [ - "check", - "lint", - "phplint", - "static analysis", - "syntax" - ], - "support": { - "issues": "https://github.com/overtrue/phplint/issues", - "source": "https://github.com/overtrue/phplint/tree/9.6.3" - }, - "funding": [ - { - "url": "https://github.com/overtrue", - "type": "github" - } - ], - "time": "2025-11-27T13:49:59+00:00" - }, - { - "name": "php-parallel-lint/php-parallel-lint", - "version": "v1.4.0", - "source": { - "type": "git", - "url": "https://github.com/php-parallel-lint/PHP-Parallel-Lint.git", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-parallel-lint/PHP-Parallel-Lint/zipball/6db563514f27e19595a19f45a4bf757b6401194e", - "reference": "6db563514f27e19595a19f45a4bf757b6401194e", - "shasum": "" - }, - "require": { - "ext-json": "*", - "php": ">=5.3.0" - }, - "replace": { - "grogy/php-parallel-lint": "*", - "jakub-onderka/php-parallel-lint": "*" - }, - "require-dev": { - "nette/tester": "^1.3 || ^2.0", - "php-parallel-lint/php-console-highlighter": "0.* || ^1.0", - "squizlabs/php_codesniffer": "^3.6" - }, - "suggest": { - "php-parallel-lint/php-console-highlighter": "Highlight syntax in code snippet" - }, - "bin": [ - "parallel-lint" - ], - "type": "library", - "autoload": { - "classmap": [ - "./src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-2-Clause" - ], - "authors": [ - { - "name": "Jakub Onderka", - "email": "ahoj@jakubonderka.cz" - } - ], - "description": "This tool checks the syntax of PHP files about 20x faster than serial check.", - "homepage": "https://github.com/php-parallel-lint/PHP-Parallel-Lint", - "keywords": [ - "lint", - "static analysis" - ], - "support": { - "issues": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/issues", - "source": "https://github.com/php-parallel-lint/PHP-Parallel-Lint/tree/v1.4.0" - }, - "time": "2024-03-27T12:14:49+00:00" - }, - { - "name": "php-stubs/wordpress-globals", - "version": "v0.2.0", - "source": { - "type": "git", - "url": "https://github.com/php-stubs/wordpress-globals.git", - "reference": "748a1fb2ae8fda94844bd0545935095dbf404b32" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-globals/zipball/748a1fb2ae8fda94844bd0545935095dbf404b32", - "reference": "748a1fb2ae8fda94844bd0545935095dbf404b32", - "shasum": "" - }, - "require-dev": { - "php": "~7.1" - }, - "suggest": { - "php-stubs/wordpress-stubs": "Up-to-date WordPress function and class declaration stubs", - "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Global variables and global constants from WordPress core.", - "homepage": "https://github.com/php-stubs/wordpress-globals", - "keywords": [ - "PHPStan", - "constants", - "globals", - "static analysis", - "wordpress" - ], - "support": { - "issues": "https://github.com/php-stubs/wordpress-globals/issues", - "source": "https://github.com/php-stubs/wordpress-globals/tree/master" - }, - "time": "2020-01-13T06:12:59+00:00" - }, - { - "name": "php-stubs/wordpress-seo-stubs", - "version": "v20.5.1", - "source": { - "type": "git", - "url": "https://github.com/php-stubs/wordpress-seo-stubs.git", - "reference": "67c69a1a6dfeabd600498b3f8239c5b531dc8156" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-seo-stubs/zipball/67c69a1a6dfeabd600498b3f8239c5b531dc8156", - "reference": "67c69a1a6dfeabd600498b3f8239c5b531dc8156", - "shasum": "" - }, - "require": { - "php-stubs/wordpress-stubs": "^5.3.0 || ^6.0" - }, - "require-dev": { - "php": "~7.1", - "php-stubs/generator": "^0.8" - }, - "suggest": { - "symfony/polyfill-php73": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Yoas SEO function and class declaration stubs for static analysis.", - "homepage": "https://github.com/php-stubs/wordpress-seo-stubs", - "keywords": [ - "PHPStan", - "seo", - "static analysis", - "wordpress", - "yoast" - ], - "support": { - "issues": "https://github.com/php-stubs/wordpress-seo-stubs/issues", - "source": "https://github.com/php-stubs/wordpress-seo-stubs/tree/v20.5.1" - }, - "time": "2023-04-21T20:41:07+00:00" - }, - { - "name": "php-stubs/wordpress-stubs", - "version": "v6.9.0", - "source": { - "type": "git", - "url": "https://github.com/php-stubs/wordpress-stubs.git", - "reference": "5171cb6650e6c583a96943fd6ea0dfa3e1089a8a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wordpress-stubs/zipball/5171cb6650e6c583a96943fd6ea0dfa3e1089a8a", - "reference": "5171cb6650e6c583a96943fd6ea0dfa3e1089a8a", - "shasum": "" - }, - "conflict": { - "phpdocumentor/reflection-docblock": "5.6.1" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "nikic/php-parser": "^5.5", - "php": "^7.4 || ^8.0", - "php-stubs/generator": "^0.8.3", - "phpdocumentor/reflection-docblock": "^5.4.1", - "phpstan/phpstan": "^2.1", - "phpunit/phpunit": "^9.5", - "szepeviktor/phpcs-psr-12-neutron-hybrid-ruleset": "^1.1.1", - "wp-coding-standards/wpcs": "3.1.0 as 2.3.0" - }, - "suggest": { - "paragonie/sodium_compat": "Pure PHP implementation of libsodium", - "symfony/polyfill-php80": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", - "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WordPress function and class declaration stubs for static analysis.", - "homepage": "https://github.com/php-stubs/wordpress-stubs", - "keywords": [ - "PHPStan", - "static analysis", - "wordpress" - ], - "support": { - "issues": "https://github.com/php-stubs/wordpress-stubs/issues", - "source": "https://github.com/php-stubs/wordpress-stubs/tree/v6.9.0" - }, - "time": "2025-12-03T23:06:24+00:00" - }, - { - "name": "php-stubs/wp-cli-stubs", - "version": "v2.12.0", - "source": { - "type": "git", - "url": "https://github.com/php-stubs/wp-cli-stubs.git", - "reference": "af16401e299a3fd2229bd0fa9a037638a4174a9d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-stubs/wp-cli-stubs/zipball/af16401e299a3fd2229bd0fa9a037638a4174a9d", - "reference": "af16401e299a3fd2229bd0fa9a037638a4174a9d", - "shasum": "" - }, - "require": { - "php-stubs/wordpress-stubs": "^4.7 || ^5.0 || ^6.0" - }, - "require-dev": { - "php": "~7.3 || ~8.0", - "php-stubs/generator": "^0.8.0" - }, - "suggest": { - "symfony/polyfill-php73": "Symfony polyfill backporting some PHP 7.3+ features to lower PHP versions", - "szepeviktor/phpstan-wordpress": "WordPress extensions for PHPStan" - }, - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "WP-CLI function and class declaration stubs for static analysis.", - "homepage": "https://github.com/php-stubs/wp-cli-stubs", - "keywords": [ - "PHPStan", - "static analysis", - "wordpress", - "wp-cli" - ], - "support": { - "issues": "https://github.com/php-stubs/wp-cli-stubs/issues", - "source": "https://github.com/php-stubs/wp-cli-stubs/tree/v2.12.0" - }, - "time": "2025-06-10T09:58:05+00:00" - }, - { - "name": "phpcompatibility/php-compatibility", - "version": "9.3.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibility.git", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9fb324479acf6f39452e0655d2429cc0d3914243", - "reference": "9fb324479acf6f39452e0655d2429cc0d3914243", - "shasum": "" - }, - "require": { - "php": ">=5.3", - "squizlabs/php_codesniffer": "^2.3 || ^3.0.2" - }, - "conflict": { - "squizlabs/php_codesniffer": "2.6.2" - }, - "require-dev": { - "phpunit/phpunit": "~4.5 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "homepage": "https://github.com/wimg", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" - } - ], - "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", - "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", - "keywords": [ - "compatibility", - "phpcs", - "standards" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues", - "source": "https://github.com/PHPCompatibility/PHPCompatibility" - }, - "time": "2019-12-27T09:44:58+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-paragonie", - "version": "1.3.4", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git", - "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", - "reference": "244d7b04fc4bc2117c15f5abe23eb933b5f02bbf", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "paragonie/random_compat": "dev-master", - "paragonie/sodium_compat": "dev-master" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A set of rulesets for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by the Paragonie polyfill libraries.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "paragonie", - "phpcs", - "polyfill", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues", - "security": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/security/policy", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie" - }, - "funding": [ - { - "url": "https://github.com/PHPCompatibility", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcompatibility", - "type": "thanks_dev" - } - ], - "time": "2025-09-19T17:43:28+00:00" - }, - { - "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.8", - "source": { - "type": "git", - "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/7c8d18b4d90dac9e86b0869a608fa09158e168fa", - "reference": "7c8d18b4d90dac9e86b0869a608fa09158e168fa", - "shasum": "" - }, - "require": { - "phpcompatibility/php-compatibility": "^9.0", - "phpcompatibility/phpcompatibility-paragonie": "^1.0", - "squizlabs/php_codesniffer": "^3.3" - }, - "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0" - }, - "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^1.0 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", - "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." - }, - "type": "phpcodesniffer-standard", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Wim Godden", - "role": "lead" - }, - { - "name": "Juliette Reinders Folmer", - "role": "lead" - } - ], - "description": "A ruleset for PHP_CodeSniffer to check for PHP cross-version compatibility issues in projects, while accounting for polyfills provided by WordPress.", - "homepage": "http://phpcompatibility.com/", - "keywords": [ - "compatibility", - "phpcs", - "standards", - "static analysis", - "wordpress" - ], - "support": { - "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", - "security": "https://github.com/PHPCompatibility/PHPCompatibilityWP/security/policy", - "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" - }, - "funding": [ - { - "url": "https://github.com/PHPCompatibility", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcompatibility", - "type": "thanks_dev" - } - ], - "time": "2025-10-18T00:05:59+00:00" - }, - { - "name": "phpcsstandards/phpcsextra", - "version": "1.5.0", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", - "reference": "b598aa890815b8df16363271b659d73280129101" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/b598aa890815b8df16363271b659d73280129101", - "reference": "b598aa890815b8df16363271b659d73280129101", - "shasum": "" - }, - "require": { - "php": ">=5.4", - "phpcsstandards/phpcsutils": "^1.2.0", - "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" - }, - "require-dev": { - "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.2.0", - "phpcsstandards/phpcsdevtools": "^1.2.1", - "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-stable": "1.x-dev", - "dev-develop": "1.x-dev" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" - } - ], - "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", - "keywords": [ - "PHP_CodeSniffer", - "phpcbf", - "phpcodesniffer-standard", - "phpcs", - "standards", - "static analysis" - ], - "support": { - "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", - "security": "https://github.com/PHPCSStandards/PHPCSExtra/security/policy", - "source": "https://github.com/PHPCSStandards/PHPCSExtra" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-11-12T23:06:57+00:00" - }, - { - "name": "phpcsstandards/phpcsutils", - "version": "1.2.2", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", - "reference": "c216317e96c8b3f5932808f9b0f1f7a14e3bbf55", - "shasum": "" - }, - "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", - "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.13.5 || ^4.0.1" - }, - "require-dev": { - "ext-filter": "*", - "php-parallel-lint/php-console-highlighter": "^1.0", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcsstandards/phpcsdevcs": "^1.2.0", - "yoast/phpunit-polyfills": "^1.1.0 || ^2.0.0 || ^3.0.0" - }, - "type": "phpcodesniffer-standard", - "extra": { - "branch-alias": { - "dev-stable": "1.x-dev", - "dev-develop": "1.x-dev" - } - }, - "autoload": { - "classmap": [ - "PHPCSUtils/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Juliette Reinders Folmer", - "homepage": "https://github.com/jrfnl", - "role": "lead" - }, - { - "name": "Contributors", - "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" - } - ], - "description": "A suite of utility functions for use with PHP_CodeSniffer", - "homepage": "https://phpcsutils.com/", - "keywords": [ - "PHP_CodeSniffer", - "phpcbf", - "phpcodesniffer-standard", - "phpcs", - "phpcs3", - "phpcs4", - "standards", - "static analysis", - "tokens", - "utility" - ], - "support": { - "docs": "https://phpcsutils.com/", - "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", - "security": "https://github.com/PHPCSStandards/PHPCSUtils/security/policy", - "source": "https://github.com/PHPCSStandards/PHPCSUtils" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-12-08T14:27:58+00:00" - }, - { - "name": "phpdocumentor/reflection-common", - "version": "2.2.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "reference": "1d01c49d4ed62f25aa84a747ad35d5a16924662b", - "shasum": "" - }, - "require": { - "php": "^7.2 || ^8.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-2.x": "2.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionCommon/issues", - "source": "https://github.com/phpDocumentor/ReflectionCommon/tree/2.x" - }, - "time": "2020-06-27T09:03:43+00:00" - }, - { - "name": "phpdocumentor/reflection-docblock", - "version": "5.6.6", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/5cee1d3dfc2d2aa6599834520911d246f656bcb8", - "reference": "5cee1d3dfc2d2aa6599834520911d246f656bcb8", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.1", - "ext-filter": "*", - "php": "^7.4 || ^8.0", - "phpdocumentor/reflection-common": "^2.2", - "phpdocumentor/type-resolver": "^1.7", - "phpstan/phpdoc-parser": "^1.7|^2.0", - "webmozart/assert": "^1.9.1 || ^2" - }, - "require-dev": { - "mockery/mockery": "~1.3.5 || ~1.6.0", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-mockery": "^1.1", - "phpstan/phpstan-webmozart-assert": "^1.2", - "phpunit/phpunit": "^9.5", - "psalm/phar": "^5.26" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - }, - { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" - } - ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "support": { - "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.6" - }, - "time": "2025-12-22T21:13:58+00:00" - }, - { - "name": "phpdocumentor/type-resolver", - "version": "1.12.0", - "source": { - "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/92a98ada2b93d9b201a613cb5a33584dde25f195", - "reference": "92a98ada2b93d9b201a613cb5a33584dde25f195", - "shasum": "" - }, - "require": { - "doctrine/deprecations": "^1.0", - "php": "^7.3 || ^8.0", - "phpdocumentor/reflection-common": "^2.0", - "phpstan/phpdoc-parser": "^1.18|^2.0" - }, - "require-dev": { - "ext-tokenizer": "*", - "phpbench/phpbench": "^1.2", - "phpstan/extension-installer": "^1.1", - "phpstan/phpstan": "^1.8", - "phpstan/phpstan-phpunit": "^1.1", - "phpunit/phpunit": "^9.5", - "rector/rector": "^0.13.9", - "vimeo/psalm": "^4.25" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev" - } - }, - "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" - } - ], - "description": "A PSR-5 based resolver of Class names, Types and Structural Element Names", - "support": { - "issues": "https://github.com/phpDocumentor/TypeResolver/issues", - "source": "https://github.com/phpDocumentor/TypeResolver/tree/1.12.0" - }, - "time": "2025-11-21T15:09:14+00:00" - }, - { - "name": "phpro/grumphp-shim", - "version": "v1.16.0", - "source": { - "type": "git", - "url": "https://github.com/phpro/grumphp-shim.git", - "reference": "98f7d27631785b48270af88e33abcc591ae022fc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpro/grumphp-shim/zipball/98f7d27631785b48270af88e33abcc591ae022fc", - "reference": "98f7d27631785b48270af88e33abcc591ae022fc", - "shasum": "" - }, - "require": { - "composer-plugin-api": "~2.0", - "ext-json": "*", - "php": "^8.0" - }, - "replace": { - "phpro/grumphp": "self.version" - }, - "require-dev": { - "humbug/box": "^3.16" - }, - "bin": [ - "grumphp", - "grumphp.phar" - ], - "type": "composer-plugin", - "extra": { - "class": "GrumPHP\\Composer\\GrumPHPPlugin" - }, - "autoload": { - "psr-4": { - "GrumPHP\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Toon Verwerft", - "email": "toon.verwerft@phpro.be" - }, - { - "name": "Community", - "homepage": "https://github.com/phpro/grumphp/graphs/contributors" - } - ], - "description": "GrumPHP Phar distribution", - "support": { - "issues": "https://github.com/phpro/grumphp-shim/issues", - "source": "https://github.com/phpro/grumphp-shim/tree/v1.16.0" - }, - "time": "2023-04-27T11:06:59+00:00" - }, - { - "name": "phpstan/phpdoc-parser", - "version": "2.3.2", - "source": { - "type": "git", - "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/a004701b11273a26cd7955a61d67a7f1e525a45a", - "reference": "a004701b11273a26cd7955a61d67a7f1e525a45a", - "shasum": "" - }, - "require": { - "php": "^7.4 || ^8.0" - }, - "require-dev": { - "doctrine/annotations": "^2.0", - "nikic/php-parser": "^5.3.0", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/extension-installer": "^1.0", - "phpstan/phpstan": "^2.0", - "phpstan/phpstan-phpunit": "^2.0", - "phpstan/phpstan-strict-rules": "^2.0", - "phpunit/phpunit": "^9.6", - "symfony/process": "^5.2" - }, - "type": "library", - "autoload": { - "psr-4": { - "PHPStan\\PhpDocParser\\": [ - "src/" - ] - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "PHPDoc parser with support for nullable, intersection and generic types", - "support": { - "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.2" - }, - "time": "2026-01-25T14:56:51+00:00" - }, - { - "name": "psr/cache", - "version": "3.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/cache.git", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Cache\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common interface for caching libraries", - "keywords": [ - "cache", - "psr", - "psr-6" - ], - "support": { - "source": "https://github.com/php-fig/cache/tree/3.0.0" - }, - "time": "2021-02-03T23:26:27+00:00" - }, - { - "name": "psr/container", - "version": "2.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/container.git", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", - "shasum": "" - }, - "require": { - "php": ">=7.4.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "2.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Container\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "https://www.php-fig.org/" - } - ], - "description": "Common Container Interface (PHP FIG PSR-11)", - "homepage": "https://github.com/php-fig/container", - "keywords": [ - "PSR-11", - "container", - "container-interface", - "container-interop", - "psr" - ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/2.0.2" - }, - "time": "2021-11-05T16:47:00+00:00" - }, - { - "name": "psr/event-dispatcher", - "version": "1.0.0", - "source": { - "type": "git", - "url": "https://github.com/php-fig/event-dispatcher.git", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", - "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", - "shasum": "" - }, - "require": { - "php": ">=7.2.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\EventDispatcher\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "PHP-FIG", - "homepage": "http://www.php-fig.org/" - } - ], - "description": "Standard interfaces for event handling.", - "keywords": [ - "events", - "psr", - "psr-14" - ], - "support": { - "issues": "https://github.com/php-fig/event-dispatcher/issues", - "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" - }, - "time": "2019-01-08T18:20:26+00:00" - }, - { - "name": "psr/log", - "version": "3.0.2", - "source": { - "type": "git", - "url": "https://github.com/php-fig/log.git", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", - "shasum": "" - }, - "require": { - "php": ">=8.0.0" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psr\\Log\\": "src" - } - }, - "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/3.0.2" - }, - "time": "2024-09-11T13:17:53+00:00" - }, - { - "name": "roave/security-advisories", - "version": "dev-latest", - "source": { - "type": "git", - "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "41f66a85ed999edf9e171452b75f642321aa7fcc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/41f66a85ed999edf9e171452b75f642321aa7fcc", - "reference": "41f66a85ed999edf9e171452b75f642321aa7fcc", - "shasum": "" - }, - "conflict": { - "3f/pygmentize": "<1.2", - "adaptcms/adaptcms": "<=1.3", - "admidio/admidio": "<=4.3.16", - "adodb/adodb-php": "<=5.22.9", - "aheinze/cockpit": "<2.2", - "aimeos/ai-admin-graphql": ">=2022.04.1,<2022.10.10|>=2023.04.1,<2023.10.6|>=2024.04.1,<2024.07.2", - "aimeos/ai-admin-jsonadm": "<2020.10.13|>=2021.04.1,<2021.10.6|>=2022.04.1,<2022.10.3|>=2023.04.1,<2023.10.4|==2024.04.1", - "aimeos/ai-client-html": ">=2020.04.1,<2020.10.27|>=2021.04.1,<2021.10.22|>=2022.04.1,<2022.10.13|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.04.7", - "aimeos/ai-cms-grapesjs": ">=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.9|>=2023.04.1,<2023.10.15|>=2024.04.1,<2024.10.8|>=2025.04.1,<2025.10.2", - "aimeos/ai-controller-frontend": "<2020.10.15|>=2021.04.1,<2021.10.8|>=2022.04.1,<2022.10.8|>=2023.04.1,<2023.10.9|==2024.04.1", - "aimeos/aimeos-core": ">=2022.04.1,<2022.10.17|>=2023.04.1,<2023.10.17|>=2024.04.1,<2024.04.7", - "aimeos/aimeos-laravel": "==2021.10", - "aimeos/aimeos-typo3": "<19.10.12|>=20,<20.10.5", - "airesvsg/acf-to-rest-api": "<=3.1", - "akaunting/akaunting": "<2.1.13", - "akeneo/pim-community-dev": "<5.0.119|>=6,<6.0.53", - "alextselegidis/easyappointments": "<=1.5.2", - "alexusmai/laravel-file-manager": "<=3.3.1", - "algolia/algoliasearch-magento-2": "<=3.16.1|>=3.17.0.0-beta1,<=3.17.1", - "alt-design/alt-redirect": "<1.6.4", - "altcha-org/altcha": "<1.3.1", - "alterphp/easyadmin-extension-bundle": ">=1.2,<1.2.11|>=1.3,<1.3.1", - "amazing/media2click": ">=1,<1.3.3", - "ameos/ameos_tarteaucitron": "<1.2.23", - "amphp/artax": "<1.0.6|>=2,<2.0.6", - "amphp/http": "<=1.7.2|>=2,<=2.1", - "amphp/http-client": ">=4,<4.4", - "anchorcms/anchor-cms": "<=0.12.7", - "andreapollastri/cipi": "<=3.1.15", - "andrewhaine/silverstripe-form-capture": ">=0.2,<=0.2.3|>=1,<1.0.2|>=2,<2.2.5", - "aoe/restler": "<1.7.1", - "apache-solr-for-typo3/solr": "<2.8.3", - "apereo/phpcas": "<1.6", - "api-platform/core": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", - "api-platform/graphql": "<3.4.17|>=4,<4.0.22|>=4.1,<4.1.5", - "appwrite/server-ce": "<=1.2.1", - "arc/web": "<3", - "area17/twill": "<1.2.5|>=2,<2.5.3", - "artesaos/seotools": "<0.17.2", - "asymmetricrypt/asymmetricrypt": "<9.9.99", - "athlon1600/php-proxy": "<=5.1", - "athlon1600/php-proxy-app": "<=3", - "athlon1600/youtube-downloader": "<=4", - "austintoddj/canvas": "<=3.4.2", - "auth0/auth0-php": ">=3.3,<8.18", - "auth0/login": "<7.20", - "auth0/symfony": "<=5.5", - "auth0/wordpress": "<=5.4", - "automad/automad": "<2.0.0.0-alpha5", - "automattic/jetpack": "<9.8", - "awesome-support/awesome-support": "<=6.0.7", - "aws/aws-sdk-php": "<3.368", - "azuracast/azuracast": "<=0.23.1", - "b13/seo_basics": "<0.8.2", - "backdrop/backdrop": "<=1.32", - "backpack/crud": "<3.4.9", - "backpack/filemanager": "<2.0.2|>=3,<3.0.9", - "bacula-web/bacula-web": "<9.7.1", - "badaso/core": "<=2.9.11", - "bagisto/bagisto": "<2.3.10", - "barrelstrength/sprout-base-email": "<1.2.7", - "barrelstrength/sprout-forms": "<3.9", - "barryvdh/laravel-translation-manager": "<0.6.8", - "barzahlen/barzahlen-php": "<2.0.1", - "baserproject/basercms": "<=5.1.1", - "bassjobsen/bootstrap-3-typeahead": ">4.0.2", - "bbpress/bbpress": "<2.6.5", - "bcit-ci/codeigniter": "<3.1.3", - "bcosca/fatfree": "<3.7.2", - "bedita/bedita": "<4", - "bednee/cooluri": "<1.0.30", - "bigfork/silverstripe-form-capture": ">=3,<3.1.1", - "billz/raspap-webgui": "<3.3.6", - "binarytorch/larecipe": "<2.8.1", - "bk2k/bootstrap-package": ">=7.1,<7.1.2|>=8,<8.0.8|>=9,<9.0.4|>=9.1,<9.1.3|>=10,<10.0.10|>=11,<11.0.3", - "blueimp/jquery-file-upload": "==6.4.4", - "bmarshall511/wordpress_zero_spam": "<5.2.13", - "bolt/bolt": "<3.7.2", - "bolt/core": "<=4.2", - "born05/craft-twofactorauthentication": "<3.3.4", - "bottelet/flarepoint": "<2.2.1", - "bref/bref": "<2.1.17", - "brightlocal/phpwhois": "<=4.2.5", - "brotkrueml/codehighlight": "<2.7", - "brotkrueml/schema": "<1.13.1|>=2,<2.5.1", - "brotkrueml/typo3-matomo-integration": "<1.3.2", - "buddypress/buddypress": "<7.2.1", - "bugsnag/bugsnag-laravel": ">=2,<2.0.2", - "bvbmedia/multishop": "<2.0.39", - "bytefury/crater": "<6.0.2", - "cachethq/cachet": "<2.5.1", - "cadmium-org/cadmium-cms": "<=0.4.9", - "cakephp/cakephp": "<3.10.3|>=4,<4.0.10|>=4.1,<4.1.4|>=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10|>=5.2.10,<5.2.12|==5.3", - "cakephp/database": ">=4.2,<4.2.12|>=4.3,<4.3.11|>=4.4,<4.4.10", - "cardgate/magento2": "<2.0.33", - "cardgate/woocommerce": "<=3.1.15", - "cart2quote/module-quotation": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cart2quote/module-quotation-encoded": ">=4.1.6,<=4.4.5|>=5,<5.4.4", - "cartalyst/sentry": "<=2.1.6", - "catfan/medoo": "<1.7.5", - "causal/oidc": "<4", - "cecil/cecil": "<7.47.1", - "centreon/centreon": "<22.10.15", - "cesnet/simplesamlphp-module-proxystatistics": "<3.1", - "chriskacerguis/codeigniter-restserver": "<=2.7.1", - "chrome-php/chrome": "<1.14", - "civicrm/civicrm-core": ">=4.2,<4.2.9|>=4.3,<4.3.3", - "ckeditor/ckeditor": "<4.25", - "clickstorm/cs-seo": ">=6,<6.8|>=7,<7.5|>=8,<8.4|>=9,<9.3", - "co-stack/fal_sftp": "<0.2.6", - "cockpit-hq/cockpit": "<2.11.4", - "code16/sharp": "<9.11.1", - "codeception/codeception": "<3.1.3|>=4,<4.1.22", - "codeigniter/framework": "<3.1.10", - "codeigniter4/framework": "<4.6.2", - "codeigniter4/shield": "<1.0.0.0-beta8", - "codiad/codiad": "<=2.8.4", - "codingms/additional-tca": ">=1.7,<1.15.17|>=1.16,<1.16.9", - "codingms/modules": "<4.3.11|>=5,<5.7.4|>=6,<6.4.2|>=7,<7.5.5", - "commerceteam/commerce": ">=0.9.6,<0.9.9", - "components/jquery": ">=1.0.3,<3.5", - "composer/composer": "<1.10.27|>=2,<2.2.26|>=2.3,<2.9.3", - "concrete5/concrete5": "<9.4.3", - "concrete5/core": "<8.5.8|>=9,<9.1", - "contao-components/mediaelement": ">=2.14.2,<2.21.1", - "contao/comments-bundle": ">=2,<4.13.40|>=5.0.0.0-RC1-dev,<5.3.4", - "contao/contao": ">=3,<3.5.37|>=4,<4.4.56|>=4.5,<4.13.56|>=5,<5.3.38|>=5.4.0.0-RC1-dev,<5.6.1", - "contao/core": "<3.5.39", - "contao/core-bundle": "<4.13.57|>=5,<5.3.42|>=5.4,<5.6.5", - "contao/listing-bundle": ">=3,<=3.5.30|>=4,<4.4.8", - "contao/managed-edition": "<=1.5", - "coreshop/core-shop": "<4.1.9", - "corveda/phpsandbox": "<1.3.5", - "cosenary/instagram": "<=2.3", - "couleurcitron/tarteaucitron-wp": "<0.3", - "cpsit/typo3-mailqueue": "<0.4.3|>=0.5,<0.5.1", - "craftcms/cms": "<=4.16.16|>=5,<=5.8.20", - "croogo/croogo": "<=4.0.7", - "cuyz/valinor": "<0.12", - "czim/file-handling": "<1.5|>=2,<2.3", - "czproject/git-php": "<4.0.3", - "damienharper/auditor-bundle": "<5.2.6", - "dapphp/securimage": "<3.6.6", - "darylldoyle/safe-svg": "<1.9.10", - "datadog/dd-trace": ">=0.30,<0.30.2", - "datahihi1/tiny-env": "<1.0.3|>=1.0.9,<1.0.11", - "datatables/datatables": "<1.10.10", - "david-garcia/phpwhois": "<=4.3.1", - "dbrisinajumi/d2files": "<1", - "dcat/laravel-admin": "<=2.1.3|==2.2.0.0-beta|==2.2.2.0-beta", - "derhansen/fe_change_pwd": "<2.0.5|>=3,<3.0.3", - "derhansen/sf_event_mgt": "<4.3.1|>=5,<5.1.1|>=7,<7.4", - "desperado/xml-bundle": "<=0.1.7", - "dev-lancer/minecraft-motd-parser": "<=1.0.5", - "devcode-it/openstamanager": "<=2.9.4", - "devgroup/dotplant": "<2020.09.14-dev", - "digimix/wp-svg-upload": "<=1", - "directmailteam/direct-mail": "<6.0.3|>=7,<7.0.3|>=8,<9.5.2", - "dl/yag": "<3.0.1", - "dmk/webkitpdf": "<1.1.4", - "dnadesign/silverstripe-elemental": "<5.3.12", - "doctrine/annotations": "<1.2.7", - "doctrine/cache": ">=1,<1.3.2|>=1.4,<1.4.2", - "doctrine/common": "<2.4.3|>=2.5,<2.5.1", - "doctrine/dbal": ">=2,<2.0.8|>=2.1,<2.1.2|>=3,<3.1.4", - "doctrine/doctrine-bundle": "<1.5.2", - "doctrine/doctrine-module": "<0.7.2", - "doctrine/mongodb-odm": "<1.0.2", - "doctrine/mongodb-odm-bundle": "<3.0.1", - "doctrine/orm": ">=1,<1.2.4|>=2,<2.4.8|>=2.5,<2.5.1|>=2.8.3,<2.8.4", - "dolibarr/dolibarr": "<21.0.3", - "dompdf/dompdf": "<2.0.4", - "doublethreedigital/guest-entries": "<3.1.2", - "drupal-pattern-lab/unified-twig-extensions": "<=0.1", - "drupal/access_code": "<2.0.5", - "drupal/acquia_dam": "<1.1.5", - "drupal/admin_audit_trail": "<1.0.5", - "drupal/ai": "<1.0.5", - "drupal/alogin": "<2.0.6", - "drupal/cache_utility": "<1.2.1", - "drupal/civictheme": "<1.12", - "drupal/commerce_alphabank_redirect": "<1.0.3", - "drupal/commerce_eurobank_redirect": "<2.1.1", - "drupal/config_split": "<1.10|>=2,<2.0.2", - "drupal/core": ">=6,<6.38|>=7,<7.103|>=8,<10.4.9|>=10.5,<10.5.6|>=11,<11.1.9|>=11.2,<11.2.8", - "drupal/core-recommended": ">=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", - "drupal/currency": "<3.5", - "drupal/drupal": ">=5,<5.11|>=6,<6.38|>=7,<7.102|>=8,<10.2.11|>=10.3,<10.3.9|>=11,<11.0.8", - "drupal/email_tfa": "<2.0.6", - "drupal/formatter_suite": "<2.1", - "drupal/gdpr": "<3.0.1|>=3.1,<3.1.2", - "drupal/google_tag": "<1.8|>=2,<2.0.8", - "drupal/ignition": "<1.0.4", - "drupal/json_field": "<1.5", - "drupal/lightgallery": "<1.6", - "drupal/link_field_display_mode_formatter": "<1.6", - "drupal/matomo": "<1.24", - "drupal/oauth2_client": "<4.1.3", - "drupal/oauth2_server": "<2.1", - "drupal/obfuscate": "<2.0.1", - "drupal/plausible_tracking": "<1.0.2", - "drupal/quick_node_block": "<2", - "drupal/rapidoc_elements_field_formatter": "<1.0.1", - "drupal/reverse_proxy_header": "<1.1.2", - "drupal/simple_multistep": "<2", - "drupal/simple_oauth": ">=6,<6.0.7", - "drupal/spamspan": "<3.2.1", - "drupal/tfa": "<1.10", - "drupal/umami_analytics": "<1.0.1", - "duncanmcclean/guest-entries": "<3.1.2", - "dweeves/magmi": "<=0.7.24", - "ec-cube/ec-cube": "<2.4.4|>=2.11,<=2.17.1|>=3,<=3.0.18.0-patch4|>=4,<=4.1.2", - "ecodev/newsletter": "<=4", - "ectouch/ectouch": "<=2.7.2", - "egroupware/egroupware": "<23.1.20240624", - "elefant/cms": "<2.0.7", - "elgg/elgg": "<3.3.24|>=4,<4.0.5", - "elijaa/phpmemcacheadmin": "<=1.3", - "elmsln/haxcms": "<11.0.14", - "encore/laravel-admin": "<=1.8.19", - "endroid/qr-code-bundle": "<3.4.2", - "enhavo/enhavo-app": "<=0.13.1", - "enshrined/svg-sanitize": "<0.22", - "erusev/parsedown": "<1.7.2", - "ether/logs": "<3.0.4", - "evolutioncms/evolution": "<=3.2.3", - "exceedone/exment": "<4.4.3|>=5,<5.0.3", - "exceedone/laravel-admin": "<2.2.3|==3", - "ezsystems/demobundle": ">=5.4,<5.4.6.1-dev", - "ezsystems/ez-support-tools": ">=2.2,<2.2.3", - "ezsystems/ezdemo-ls-extension": ">=5.4,<5.4.2.1-dev", - "ezsystems/ezfind-ls": ">=5.3,<5.3.6.1-dev|>=5.4,<5.4.11.1-dev|>=2017.12,<2017.12.0.1-dev", - "ezsystems/ezplatform": "<=1.13.6|>=2,<=2.5.24", - "ezsystems/ezplatform-admin-ui": ">=1.3,<1.3.5|>=1.4,<1.4.6|>=1.5,<1.5.29|>=2.3,<2.3.39|>=3.3,<3.3.39", - "ezsystems/ezplatform-admin-ui-assets": ">=4,<4.2.1|>=5,<5.0.1|>=5.1,<5.1.1|>=5.3.0.0-beta1,<5.3.5", - "ezsystems/ezplatform-graphql": ">=1.0.0.0-RC1-dev,<1.0.13|>=2.0.0.0-beta1,<2.3.12", - "ezsystems/ezplatform-http-cache": "<2.3.16", - "ezsystems/ezplatform-kernel": "<1.2.5.1-dev|>=1.3,<1.3.35", - "ezsystems/ezplatform-rest": ">=1.2,<=1.2.2|>=1.3,<1.3.8", - "ezsystems/ezplatform-richtext": ">=2.3,<2.3.26|>=3.3,<3.3.40", - "ezsystems/ezplatform-solr-search-engine": ">=1.7,<1.7.12|>=2,<2.0.2|>=3.3,<3.3.15", - "ezsystems/ezplatform-user": ">=1,<1.0.1", - "ezsystems/ezpublish-kernel": "<6.13.8.2-dev|>=7,<7.5.31", - "ezsystems/ezpublish-legacy": "<=2017.12.7.3|>=2018.6,<=2019.03.5.1", - "ezsystems/platform-ui-assets-bundle": ">=4.2,<4.2.3", - "ezsystems/repository-forms": ">=2.3,<2.3.2.1-dev|>=2.5,<2.5.15", - "ezyang/htmlpurifier": "<=4.2", - "facade/ignition": "<1.16.15|>=2,<2.4.2|>=2.5,<2.5.2", - "facturascripts/facturascripts": "<=2025.4|==2025.11|==2025.41|==2025.43", - "fastly/magento2": "<1.2.26", - "feehi/cms": "<=2.1.1", - "feehi/feehicms": "<=2.1.1", - "fenom/fenom": "<=2.12.1", - "filament/actions": ">=3.2,<3.2.123", - "filament/filament": ">=4,<4.3.1", - "filament/infolists": ">=3,<3.2.115", - "filament/tables": ">=3,<3.2.115", - "filegator/filegator": "<7.8", - "filp/whoops": "<2.1.13", - "fineuploader/php-traditional-server": "<=1.2.2", - "firebase/php-jwt": "<6", - "fisharebest/webtrees": "<=2.1.18", - "fixpunkt/fp-masterquiz": "<2.2.1|>=3,<3.5.2", - "fixpunkt/fp-newsletter": "<1.1.1|>=1.2,<2.1.2|>=2.2,<3.2.6", - "flarum/core": "<1.8.10", - "flarum/flarum": "<0.1.0.0-beta8", - "flarum/framework": "<1.8.10", - "flarum/mentions": "<1.6.3", - "flarum/sticky": ">=0.1.0.0-beta14,<=0.1.0.0-beta15", - "flarum/tags": "<=0.1.0.0-beta13", - "floriangaerber/magnesium": "<0.3.1", - "fluidtypo3/vhs": "<5.1.1", - "fof/byobu": ">=0.3.0.0-beta2,<1.1.7", - "fof/pretty-mail": "<=1.1.2", - "fof/upload": "<1.2.3", - "foodcoopshop/foodcoopshop": ">=3.2,<3.6.1", - "fooman/tcpdf": "<6.2.22", - "forkcms/forkcms": "<5.11.1", - "fossar/tcpdf-parser": "<6.2.22", - "francoisjacquet/rosariosis": "<=11.5.1", - "frappant/frp-form-answers": "<3.1.2|>=4,<4.0.2", - "friendsofsymfony/oauth2-php": "<1.3", - "friendsofsymfony/rest-bundle": ">=1.2,<1.2.2", - "friendsofsymfony/user-bundle": ">=1,<1.3.5", - "friendsofsymfony1/swiftmailer": ">=4,<5.4.13|>=6,<6.2.5", - "friendsofsymfony1/symfony1": ">=1.1,<1.5.19", - "friendsoftypo3/mediace": ">=7.6.2,<7.6.5", - "friendsoftypo3/openid": ">=4.5,<4.5.31|>=4.7,<4.7.16|>=6,<6.0.11|>=6.1,<6.1.6", - "froala/wysiwyg-editor": "<=4.3", - "froxlor/froxlor": "<=2.2.5", - "frozennode/administrator": "<=5.0.12", - "fuel/core": "<1.8.1", - "funadmin/funadmin": "<=5.0.2", - "gaoming13/wechat-php-sdk": "<=1.10.2", - "genix/cms": "<=1.1.11", - "georgringer/news": "<1.3.3", - "geshi/geshi": "<=1.0.9.1", - "getformwork/formwork": "<2.2", - "getgrav/grav": "<1.11.0.0-beta1", - "getkirby/cms": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1|>=5,<=5.2.1", - "getkirby/kirby": "<3.9.8.3-dev|>=3.10,<3.10.1.2-dev|>=4,<4.7.1", - "getkirby/panel": "<2.5.14", - "getkirby/starterkit": "<=3.7.0.2", - "gilacms/gila": "<=1.15.4", - "gleez/cms": "<=1.3|==2", - "globalpayments/php-sdk": "<2", - "goalgorilla/open_social": "<12.3.11|>=12.4,<12.4.10|>=13.0.0.0-alpha1,<13.0.0.0-alpha11", - "gogentooss/samlbase": "<1.2.7", - "google/protobuf": "<3.4", - "gos/web-socket-bundle": "<1.10.4|>=2,<2.6.1|>=3,<3.3", - "gp247/core": "<1.1.24", - "gree/jose": "<2.2.1", - "gregwar/rst": "<1.0.3", - "grumpydictator/firefly-iii": "<6.1.17", - "gugoan/economizzer": "<=0.9.0.0-beta1", - "guzzlehttp/guzzle": "<6.5.8|>=7,<7.4.5", - "guzzlehttp/oauth-subscriber": "<0.8.1", - "guzzlehttp/psr7": "<1.9.1|>=2,<2.4.5", - "haffner/jh_captcha": "<=2.1.3|>=3,<=3.0.2", - "handcraftedinthealps/goodby-csv": "<1.4.3", - "harvesthq/chosen": "<1.8.7", - "helloxz/imgurl": "<=2.31", - "hhxsv5/laravel-s": "<3.7.36", - "hillelcoren/invoice-ninja": "<5.3.35", - "himiklab/yii2-jqgrid-widget": "<1.0.8", - "hjue/justwriting": "<=1", - "hov/jobfair": "<1.0.13|>=2,<2.0.2", - "httpsoft/http-message": "<1.0.12", - "hyn/multi-tenant": ">=5.6,<5.7.2", - "ibexa/admin-ui": ">=4.2,<4.2.3|>=4.6,<4.6.25|>=5,<5.0.3", - "ibexa/admin-ui-assets": ">=4.6.0.0-alpha1,<4.6.21", - "ibexa/core": ">=4,<4.0.7|>=4.1,<4.1.4|>=4.2,<4.2.3|>=4.5,<4.5.6|>=4.6,<4.6.2", - "ibexa/fieldtype-richtext": ">=4.6,<4.6.25|>=5,<5.0.3", - "ibexa/graphql": ">=2.5,<2.5.31|>=3.3,<3.3.28|>=4.2,<4.2.3", - "ibexa/http-cache": ">=4.6,<4.6.14", - "ibexa/post-install": "<1.0.16|>=4.6,<4.6.14", - "ibexa/solr": ">=4.5,<4.5.4", - "ibexa/user": ">=4,<4.4.3|>=5,<5.0.4", - "icecoder/icecoder": "<=8.1", - "idno/known": "<=1.3.1", - "ilicmiljan/secure-props": ">=1.2,<1.2.2", - "illuminate/auth": "<5.5.10", - "illuminate/cookie": ">=4,<=4.0.11|>=4.1,<6.18.31|>=7,<7.22.4", - "illuminate/database": "<6.20.26|>=7,<7.30.5|>=8,<8.40", - "illuminate/encryption": ">=4,<=4.0.11|>=4.1,<=4.1.31|>=4.2,<=4.2.22|>=5,<=5.0.35|>=5.1,<=5.1.46|>=5.2,<=5.2.45|>=5.3,<=5.3.31|>=5.4,<=5.4.36|>=5.5,<5.5.40|>=5.6,<5.6.15", - "illuminate/view": "<6.20.42|>=7,<7.30.6|>=8,<8.75", - "imdbphp/imdbphp": "<=5.1.1", - "impresscms/impresscms": "<=1.4.5", - "impresspages/impresspages": "<1.0.13", - "in2code/femanager": "<6.4.2|>=7,<7.5.3|>=8,<8.3.1", - "in2code/ipandlanguageredirect": "<5.1.2", - "in2code/lux": "<17.6.1|>=18,<24.0.2", - "in2code/powermail": "<7.5.1|>=8,<8.5.1|>=9,<10.9.1|>=11,<12.5.3|==13", - "innologi/typo3-appointments": "<2.0.6", - "intelliants/subrion": "<4.2.2", - "inter-mediator/inter-mediator": "==5.5", - "ipl/web": "<0.10.1", - "islandora/crayfish": "<4.1", - "islandora/islandora": ">=2,<2.4.1", - "ivankristianto/phpwhois": "<=4.3", - "jackalope/jackalope-doctrine-dbal": "<1.7.4", - "jambagecom/div2007": "<0.10.2", - "james-heinrich/getid3": "<1.9.21", - "james-heinrich/phpthumb": "<=1.7.23", - "jasig/phpcas": "<1.3.3", - "jbartels/wec-map": "<3.0.3", - "jcbrand/converse.js": "<3.3.3", - "joelbutcher/socialstream": "<5.6|>=6,<6.2", - "johnbillion/wp-crontrol": "<1.16.2|>=1.17,<1.19.2", - "joomla/application": "<1.0.13", - "joomla/archive": "<1.1.12|>=2,<2.0.1", - "joomla/database": ">=1,<2.2|>=3,<3.4", - "joomla/filesystem": "<1.6.2|>=2,<2.0.1", - "joomla/filter": "<2.0.6|>=3,<3.0.5|==4", - "joomla/framework": "<1.5.7|>=2.5.4,<=3.8.12", - "joomla/input": ">=2,<2.0.2", - "joomla/joomla-cms": "<3.9.12|>=4,<4.4.13|>=5,<5.2.6", - "joomla/joomla-platform": "<1.5.4", - "joomla/session": "<1.3.1", - "joyqi/hyper-down": "<=2.4.27", - "jsdecena/laracom": "<2.0.9", - "jsmitty12/phpwhois": "<5.1", - "juzaweb/cms": "<=3.4.2", - "jweiland/events2": "<8.3.8|>=9,<9.0.6", - "jweiland/kk-downloader": "<1.2.2", - "kazist/phpwhois": "<=4.2.6", - "kelvinmo/simplexrd": "<3.1.1", - "kevinpapst/kimai2": "<1.16.7", - "khodakhah/nodcms": "<=3", - "kimai/kimai": "<2.46", - "kitodo/presentation": "<3.2.3|>=3.3,<3.3.4", - "klaviyo/magento2-extension": ">=1,<3", - "knplabs/knp-snappy": "<=1.4.2", - "kohana/core": "<3.3.3", - "koillection/koillection": "<1.6.12", - "krayin/laravel-crm": "<=1.3", - "kreait/firebase-php": ">=3.2,<3.8.1", - "kumbiaphp/kumbiapp": "<=1.1.1", - "la-haute-societe/tcpdf": "<6.2.22", - "laminas/laminas-diactoros": "<2.18.1|==2.19|==2.20|==2.21|==2.22|==2.23|>=2.24,<2.24.2|>=2.25,<2.25.2", - "laminas/laminas-form": "<2.17.1|>=3,<3.0.2|>=3.1,<3.1.1", - "laminas/laminas-http": "<2.14.2", - "lara-zeus/artemis": ">=1,<=1.0.6", - "lara-zeus/dynamic-dashboard": ">=3,<=3.0.1", - "laravel/fortify": "<1.11.1", - "laravel/framework": "<10.48.29|>=11,<11.44.1|>=12,<12.1.1", - "laravel/laravel": ">=5.4,<5.4.22", - "laravel/pulse": "<1.3.1", - "laravel/reverb": "<1.7", - "laravel/socialite": ">=1,<2.0.10", - "latte/latte": "<2.10.8", - "lavalite/cms": "<=10.1", - "lavitto/typo3-form-to-database": "<2.2.5|>=3,<3.2.2|>=4,<4.2.3|>=5,<5.0.2", - "lcobucci/jwt": ">=3.4,<3.4.6|>=4,<4.0.4|>=4.1,<4.1.5", - "league/commonmark": "<2.7", - "league/flysystem": "<1.1.4|>=2,<2.1.1", - "league/oauth2-server": ">=8.3.2,<8.4.2|>=8.5,<8.5.3", - "leantime/leantime": "<3.3", - "lexik/jwt-authentication-bundle": "<2.10.7|>=2.11,<2.11.3", - "libreform/libreform": ">=2,<=2.0.8", - "librenms/librenms": "<25.12", - "liftkit/database": "<2.13.2", - "lightsaml/lightsaml": "<1.3.5", - "limesurvey/limesurvey": "<6.5.12", - "livehelperchat/livehelperchat": "<=3.91", - "livewire-filemanager/filemanager": "<=1.0.4", - "livewire/livewire": "<2.12.7|>=3.0.0.0-beta1,<3.6.4", - "livewire/volt": "<1.7", - "lms/routes": "<2.1.1", - "localizationteam/l10nmgr": "<7.4|>=8,<8.7|>=9,<9.2", - "lomkit/laravel-rest-api": "<2.13", - "luracast/restler": "<3.1", - "luyadev/yii-helpers": "<1.2.1", - "macropay-solutions/laravel-crud-wizard-free": "<3.4.17", - "maestroerror/php-heic-to-jpg": "<1.0.5", - "magento/community-edition": "<2.4.6.0-patch13|>=2.4.7.0-beta1,<2.4.7.0-patch8|>=2.4.8.0-beta1,<2.4.8.0-patch3|>=2.4.9.0-alpha1,<2.4.9.0-alpha3|==2.4.9", - "magento/core": "<=1.9.4.5", - "magento/magento1ce": "<1.9.4.3-dev", - "magento/magento1ee": ">=1,<1.14.4.3-dev", - "magento/product-community-edition": "<2.4.4.0-patch9|>=2.4.5,<2.4.5.0-patch8|>=2.4.6,<2.4.6.0-patch6|>=2.4.7,<2.4.7.0-patch1", - "magento/project-community-edition": "<=2.0.2", - "magneto/core": "<1.9.4.4-dev", - "mahocommerce/maho": "<25.9", - "maikuolan/phpmussel": ">=1,<1.6", - "mainwp/mainwp": "<=4.4.3.3", - "manogi/nova-tiptap": "<=3.2.6", - "mantisbt/mantisbt": "<2.27.2", - "marcwillmann/turn": "<0.3.3", - "marshmallow/nova-tiptap": "<5.7", - "matomo/matomo": "<1.11", - "matyhtf/framework": "<3.0.6", - "mautic/core": "<5.2.9|>=6,<6.0.7", - "mautic/core-lib": ">=1.0.0.0-beta,<4.4.13|>=5.0.0.0-alpha,<5.1.1", - "mautic/grapes-js-builder-bundle": ">=4,<4.4.18|>=5,<5.2.9|>=6,<6.0.7", - "maximebf/debugbar": "<1.19", - "mdanter/ecc": "<2", - "mediawiki/abuse-filter": "<1.39.9|>=1.40,<1.41.3|>=1.42,<1.42.2", - "mediawiki/cargo": "<3.8.3", - "mediawiki/core": "<1.39.5|==1.40", - "mediawiki/data-transfer": ">=1.39,<1.39.11|>=1.41,<1.41.3|>=1.42,<1.42.2", - "mediawiki/matomo": "<2.4.3", - "mediawiki/semantic-media-wiki": "<4.0.2", - "mehrwert/phpmyadmin": "<3.2", - "melisplatform/melis-asset-manager": "<5.0.1", - "melisplatform/melis-cms": "<5.3.4", - "melisplatform/melis-cms-slider": "<5.3.1", - "melisplatform/melis-core": "<5.3.11", - "melisplatform/melis-front": "<5.0.1", - "mezzio/mezzio-swoole": "<3.7|>=4,<4.3", - "mgallegos/laravel-jqgrid": "<=1.3", - "microsoft/microsoft-graph": ">=1.16,<1.109.1|>=2,<2.0.1", - "microsoft/microsoft-graph-beta": "<2.0.1", - "microsoft/microsoft-graph-core": "<2.0.2", - "microweber/microweber": "<=2.0.19", - "mikehaertl/php-shellcommand": "<1.6.1", - "mineadmin/mineadmin": "<=3.0.9", - "miniorange/miniorange-saml": "<1.4.3", - "mittwald/typo3_forum": "<1.2.1", - "mobiledetect/mobiledetectlib": "<2.8.32", - "modx/revolution": "<=3.1", - "mojo42/jirafeau": "<4.4", - "mongodb/mongodb": ">=1,<1.9.2", - "mongodb/mongodb-extension": "<1.21.2", - "monolog/monolog": ">=1.8,<1.12", - "moodle/moodle": "<4.4.12|>=4.5.0.0-beta,<4.5.8|>=5.0.0.0-beta,<5.0.4|>=5.1.0.0-beta,<5.1.1", - "moonshine/moonshine": "<=3.12.5", - "mos/cimage": "<0.7.19", - "movim/moxl": ">=0.8,<=0.10", - "movingbytes/social-network": "<=1.2.1", - "mpdf/mpdf": "<=7.1.7", - "munkireport/comment": "<4", - "munkireport/managedinstalls": "<2.6", - "munkireport/munki_facts": "<1.5", - "munkireport/reportdata": "<3.5", - "munkireport/softwareupdate": "<1.6", - "mustache/mustache": ">=2,<2.14.1", - "mwdelaney/wp-enable-svg": "<=0.2", - "namshi/jose": "<2.2", - "nasirkhan/laravel-starter": "<11.11", - "nategood/httpful": "<1", - "neoan3-apps/template": "<1.1.1", - "neorazorx/facturascripts": "<2022.04", - "neos/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "neos/form": ">=1.2,<4.3.3|>=5,<5.0.9|>=5.1,<5.1.3", - "neos/media-browser": "<7.3.19|>=8,<8.0.16|>=8.1,<8.1.11|>=8.2,<8.2.11|>=8.3,<8.3.9", - "neos/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<5.3.10|>=7,<7.0.9|>=7.1,<7.1.7|>=7.2,<7.2.6|>=7.3,<7.3.4|>=8,<8.0.2", - "neos/swiftmailer": "<5.4.5", - "nesbot/carbon": "<2.72.6|>=3,<3.8.4", - "netcarver/textile": "<=4.1.2", - "netgen/tagsbundle": ">=3.4,<3.4.11|>=4,<4.0.15", - "nette/application": ">=2,<2.0.19|>=2.1,<2.1.13|>=2.2,<2.2.10|>=2.3,<2.3.14|>=2.4,<2.4.16|>=3,<3.0.6", - "nette/nette": ">=2,<2.0.19|>=2.1,<2.1.13", - "neuron-core/neuron-ai": "<=2.8.11", - "nilsteampassnet/teampass": "<3.1.3.1-dev", - "nitsan/ns-backup": "<13.0.1", - "nonfiction/nterchange": "<4.1.1", - "notrinos/notrinos-erp": "<=0.7", - "noumo/easyii": "<=0.9", - "novaksolutions/infusionsoft-php-sdk": "<1", - "novosga/novosga": "<=2.2.12", - "nukeviet/nukeviet": "<4.5.02", - "nyholm/psr7": "<1.6.1", - "nystudio107/craft-seomatic": "<3.4.12", - "nzedb/nzedb": "<0.8", - "nzo/url-encryptor-bundle": ">=4,<4.3.2|>=5,<5.0.1", - "october/backend": "<1.1.2", - "october/cms": "<1.0.469|==1.0.469|==1.0.471|==1.1.1", - "october/october": "<3.7.5", - "october/rain": "<1.0.472|>=1.1,<1.1.2", - "october/system": "<=3.7.12|>=4,<=4.0.11", - "oliverklee/phpunit": "<3.5.15", - "omeka/omeka-s": "<4.0.3", - "onelogin/php-saml": "<2.21.1|>=3,<3.8.1|>=4,<4.3.1", - "oneup/uploader-bundle": ">=1,<1.9.3|>=2,<2.1.5", - "open-web-analytics/open-web-analytics": "<1.8.1", - "opencart/opencart": ">=0", - "openid/php-openid": "<2.3", - "openmage/magento-lts": "<20.16", - "opensolutions/vimbadmin": "<=3.0.15", - "opensource-workshop/connect-cms": "<1.8.7|>=2,<2.4.7", - "orchid/platform": ">=8,<14.43", - "oro/calendar-bundle": ">=4.2,<=4.2.6|>=5,<=5.0.6|>=5.1,<5.1.1", - "oro/commerce": ">=4.1,<5.0.11|>=5.1,<5.1.1", - "oro/crm": ">=1.7,<1.7.4|>=3.1,<4.1.17|>=4.2,<4.2.7", - "oro/crm-call-bundle": ">=4.2,<=4.2.5|>=5,<5.0.4|>=5.1,<5.1.1", - "oro/customer-portal": ">=4.1,<=4.1.13|>=4.2,<=4.2.10|>=5,<=5.0.11|>=5.1,<=5.1.3", - "oro/platform": ">=1.7,<1.7.4|>=3.1,<3.1.29|>=4.1,<4.1.17|>=4.2,<=4.2.10|>=5,<=5.0.12|>=5.1,<=5.1.3", - "oveleon/contao-cookiebar": "<1.16.3|>=2,<2.1.3", - "oxid-esales/oxideshop-ce": "<=7.0.5", - "oxid-esales/paymorrow-module": ">=1,<1.0.2|>=2,<2.0.1", - "packbackbooks/lti-1-3-php-library": "<5", - "padraic/humbug_get_contents": "<1.1.2", - "pagarme/pagarme-php": "<3", - "pagekit/pagekit": "<=1.0.18", - "paragonie/ecc": "<2.0.1", - "paragonie/random_compat": "<2", - "paragonie/sodium_compat": "<1.24|>=2,<2.5", - "passbolt/passbolt_api": "<4.6.2", - "paypal/adaptivepayments-sdk-php": "<=3.9.2", - "paypal/invoice-sdk-php": "<=3.9", - "paypal/merchant-sdk-php": "<3.12", - "paypal/permissions-sdk-php": "<=3.9.1", - "pear/archive_tar": "<1.4.14", - "pear/auth": "<1.2.4", - "pear/crypt_gpg": "<1.6.7", - "pear/http_request2": "<2.7", - "pear/pear": "<=1.10.1", - "pegasus/google-for-jobs": "<1.5.1|>=2,<2.1.1", - "personnummer/personnummer": "<3.0.2", - "ph7software/ph7builder": "<=17.9.1", - "phanan/koel": "<5.1.4", - "phenx/php-svg-lib": "<0.5.2", - "php-censor/php-censor": "<2.0.13|>=2.1,<2.1.5", - "php-mod/curl": "<2.3.2", - "phpbb/phpbb": "<3.3.11", - "phpems/phpems": ">=6,<=6.1.3", - "phpfastcache/phpfastcache": "<6.1.5|>=7,<7.1.2|>=8,<8.0.7", - "phpmailer/phpmailer": "<6.5", - "phpmussel/phpmussel": ">=1,<1.6", - "phpmyadmin/phpmyadmin": "<5.2.2", - "phpmyfaq/phpmyfaq": "<=4.0.16", - "phpoffice/common": "<0.2.9", - "phpoffice/math": "<=0.2", - "phpoffice/phpexcel": "<=1.8.2", - "phpoffice/phpspreadsheet": "<1.30|>=2,<2.1.12|>=2.2,<2.4|>=3,<3.10|>=4,<5", - "phppgadmin/phppgadmin": "<=7.13", - "phpseclib/phpseclib": "<2.0.47|>=3,<3.0.36", - "phpservermon/phpservermon": "<3.6", - "phpsysinfo/phpsysinfo": "<3.4.3", - "phpunit/phpunit": ">=4.8.19,<4.8.28|>=5.0.10,<5.6.3", - "phpwhois/phpwhois": "<=4.2.5", - "phpxmlrpc/extras": "<0.6.1", - "phpxmlrpc/phpxmlrpc": "<4.9.2", - "pi/pi": "<=2.5", - "pimcore/admin-ui-classic-bundle": "<=1.7.15|>=2.0.0.0-RC1-dev,<=2.2.2", - "pimcore/customer-management-framework-bundle": "<4.2.1", - "pimcore/data-hub": "<1.2.4", - "pimcore/data-importer": "<1.8.9|>=1.9,<1.9.3", - "pimcore/demo": "<10.3", - "pimcore/ecommerce-framework-bundle": "<1.0.10", - "pimcore/perspective-editor": "<1.5.1", - "pimcore/pimcore": "<=11.5.13|>=12.0.0.0-RC1-dev,<12.3.1", - "pimcore/web2print-tools-bundle": "<=5.2.1|>=6.0.0.0-RC1-dev,<=6.1", - "piwik/piwik": "<1.11", - "pixelfed/pixelfed": "<0.12.5", - "plotly/plotly.js": "<2.25.2", - "pocketmine/bedrock-protocol": "<8.0.2", - "pocketmine/pocketmine-mp": "<5.32.1", - "pocketmine/raklib": ">=0.14,<0.14.6|>=0.15,<0.15.1", - "pressbooks/pressbooks": "<5.18", - "prestashop/autoupgrade": ">=4,<4.10.1", - "prestashop/blockreassurance": "<=5.1.3", - "prestashop/blockwishlist": ">=2,<2.1.1", - "prestashop/contactform": ">=1.0.1,<4.3", - "prestashop/gamification": "<2.3.2", - "prestashop/prestashop": "<8.2.3", - "prestashop/productcomments": "<5.0.2", - "prestashop/ps_checkout": "<4.4.1|>=5,<5.0.5", - "prestashop/ps_contactinfo": "<=3.3.2", - "prestashop/ps_emailsubscription": "<2.6.1", - "prestashop/ps_facetedsearch": "<3.4.1", - "prestashop/ps_linklist": "<3.1", - "privatebin/privatebin": "<1.4|>=1.5,<1.7.4|>=1.7.7,<2.0.3", - "processwire/processwire": "<=3.0.246", - "propel/propel": ">=2.0.0.0-alpha1,<=2.0.0.0-alpha7", - "propel/propel1": ">=1,<=1.7.1", - "pterodactyl/panel": "<1.12", - "ptheofan/yii2-statemachine": ">=2.0.0.0-RC1-dev,<=2", - "ptrofimov/beanstalk_console": "<1.7.14", - "pubnub/pubnub": "<6.1", - "punktde/pt_extbase": "<1.5.1", - "pusher/pusher-php-server": "<2.2.1", - "pwweb/laravel-core": "<=0.3.6.0-beta", - "pxlrbt/filament-excel": "<1.1.14|>=2.0.0.0-alpha,<2.3.3", - "pyrocms/pyrocms": "<=3.9.1", - "qcubed/qcubed": "<=3.1.1", - "quickapps/cms": "<=2.0.0.0-beta2", - "rainlab/blog-plugin": "<1.4.1", - "rainlab/debugbar-plugin": "<3.1", - "rainlab/user-plugin": "<=1.4.5", - "rankmath/seo-by-rank-math": "<=1.0.95", - "rap2hpoutre/laravel-log-viewer": "<0.13", - "react/http": ">=0.7,<1.9", - "really-simple-plugins/complianz-gdpr": "<6.4.2", - "redaxo/source": "<=5.20.1", - "remdex/livehelperchat": "<4.29", - "renolit/reint-downloadmanager": "<4.0.2|>=5,<5.0.1", - "reportico-web/reportico": "<=8.1", - "rhukster/dom-sanitizer": "<1.0.7", - "rmccue/requests": ">=1.6,<1.8", - "robrichards/xmlseclibs": "<=3.1.3", - "roots/soil": "<4.1", - "roundcube/roundcubemail": "<1.5.10|>=1.6,<1.6.11", - "rudloff/alltube": "<3.0.3", - "rudloff/rtmpdump-bin": "<=2.3.1", - "s-cart/core": "<=9.0.5", - "s-cart/s-cart": "<6.9", - "sabberworm/php-css-parser": ">=1,<1.0.1|>=2,<2.0.1|>=3,<3.0.1|>=4,<4.0.1|>=5,<5.0.9|>=5.1,<5.1.3|>=5.2,<5.2.1|>=6,<6.0.2|>=7,<7.0.4|>=8,<8.0.1|>=8.1,<8.1.1|>=8.2,<8.2.1|>=8.3,<8.3.1", - "sabre/dav": ">=1.6,<1.7.11|>=1.8,<1.8.9", - "samwilson/unlinked-wikibase": "<1.42", - "scheb/two-factor-bundle": "<3.26|>=4,<4.11", - "sensiolabs/connect": "<4.2.3", - "serluck/phpwhois": "<=4.2.6", - "setasign/fpdi": "<2.6.4", - "sfroemken/url_redirect": "<=1.2.1", - "sheng/yiicms": "<1.2.1", - "shopware/core": "<6.6.10.9-dev|>=6.7,<6.7.6.1-dev", - "shopware/platform": "<6.6.10.7-dev|>=6.7,<6.7.3.1-dev", - "shopware/production": "<=6.3.5.2", - "shopware/shopware": "<=5.7.17|>=6.4.6,<6.6.10.10-dev|>=6.7,<6.7.6.1-dev", - "shopware/storefront": "<6.6.10.10-dev|>=6.7,<6.7.5.1-dev", - "shopxo/shopxo": "<=6.4", - "showdoc/showdoc": "<2.10.4", - "shuchkin/simplexlsx": ">=1.0.12,<1.1.13", - "silverstripe-australia/advancedreports": ">=1,<=2", - "silverstripe/admin": "<1.13.19|>=2,<2.1.8", - "silverstripe/assets": ">=1,<1.11.1", - "silverstripe/cms": "<4.11.3", - "silverstripe/comments": ">=1.3,<3.1.1", - "silverstripe/forum": "<=0.6.1|>=0.7,<=0.7.3", - "silverstripe/framework": "<5.3.23", - "silverstripe/graphql": ">=2,<2.0.5|>=3,<3.8.2|>=4,<4.3.7|>=5,<5.1.3", - "silverstripe/hybridsessions": ">=1,<2.4.1|>=2.5,<2.5.1", - "silverstripe/recipe-cms": ">=4.5,<4.5.3", - "silverstripe/registry": ">=2.1,<2.1.2|>=2.2,<2.2.1", - "silverstripe/reports": "<5.2.3", - "silverstripe/restfulserver": ">=1,<1.0.9|>=2,<2.0.4|>=2.1,<2.1.2", - "silverstripe/silverstripe-omnipay": "<2.5.2|>=3,<3.0.2|>=3.1,<3.1.4|>=3.2,<3.2.1", - "silverstripe/subsites": ">=2,<2.6.1", - "silverstripe/taxonomy": ">=1.3,<1.3.1|>=2,<2.0.1", - "silverstripe/userforms": "<3|>=5,<5.4.2", - "silverstripe/versioned-admin": ">=1,<1.11.1", - "simogeo/filemanager": "<=2.5", - "simple-updates/phpwhois": "<=1", - "simplesamlphp/saml2": "<=4.16.15|>=5.0.0.0-alpha1,<=5.0.0.0-alpha19", - "simplesamlphp/saml2-legacy": "<=4.16.15", - "simplesamlphp/simplesamlphp": "<1.18.6", - "simplesamlphp/simplesamlphp-module-infocard": "<1.0.1", - "simplesamlphp/simplesamlphp-module-openid": "<1", - "simplesamlphp/simplesamlphp-module-openidprovider": "<0.9", - "simplesamlphp/xml-common": "<1.20", - "simplesamlphp/xml-security": "==1.6.11", - "simplito/elliptic-php": "<1.0.6", - "sitegeist/fluid-components": "<3.5", - "sjbr/sr-feuser-register": "<2.6.2|>=5.1,<12.5", - "sjbr/sr-freecap": "<2.4.6|>=2.5,<2.5.3", - "sjbr/static-info-tables": "<2.3.1", - "slim/psr7": "<1.4.1|>=1.5,<1.5.1|>=1.6,<1.6.1", - "slim/slim": "<2.6", - "slub/slub-events": "<3.0.3", - "smarty/smarty": "<4.5.3|>=5,<5.1.1", - "snipe/snipe-it": "<=8.3.4", - "socalnick/scn-social-auth": "<1.15.2", - "socialiteproviders/steam": "<1.1", - "solspace/craft-freeform": "<=5.14.6", - "soosyze/soosyze": "<=2", - "spatie/browsershot": "<5.0.5", - "spatie/image-optimizer": "<1.7.3", - "spencer14420/sp-php-email-handler": "<1", - "spipu/html2pdf": "<5.2.8", - "spiral/roadrunner": "<2025.1", - "spoon/library": "<1.4.1", - "spoonity/tcpdf": "<6.2.22", - "squizlabs/php_codesniffer": ">=1,<2.8.1|>=3,<3.0.1", - "ssddanbrown/bookstack": "<24.05.1", - "starcitizentools/citizen-skin": ">=1.9.4,<3.9", - "starcitizentools/short-description": ">=4,<4.0.1", - "starcitizentools/tabber-neue": ">=1.9.1,<2.7.2|>=3,<3.1.1", - "starcitizenwiki/embedvideo": "<=4", - "statamic/cms": "<=5.22", - "stormpath/sdk": "<9.9.99", - "studio-42/elfinder": "<=2.1.64", - "studiomitte/friendlycaptcha": "<0.1.4", - "subhh/libconnect": "<7.0.8|>=8,<8.1", - "sukohi/surpass": "<1", - "sulu/form-bundle": ">=2,<2.5.3", - "sulu/sulu": "<1.6.44|>=2,<2.5.25|>=2.6,<2.6.9|>=3.0.0.0-alpha1,<3.0.0.0-alpha3", - "sumocoders/framework-user-bundle": "<1.4", - "superbig/craft-audit": "<3.0.2", - "svewap/a21glossary": "<=0.4.10", - "swag/paypal": "<5.4.4", - "swiftmailer/swiftmailer": "<6.2.5", - "swiftyedit/swiftyedit": "<1.2", - "sylius/admin-bundle": ">=1,<1.0.17|>=1.1,<1.1.9|>=1.2,<1.2.2", - "sylius/grid": ">=1,<1.1.19|>=1.2,<1.2.18|>=1.3,<1.3.13|>=1.4,<1.4.5|>=1.5,<1.5.1", - "sylius/grid-bundle": "<1.10.1", - "sylius/paypal-plugin": "<1.6.2|>=1.7,<1.7.2|>=2,<2.0.2", - "sylius/resource-bundle": ">=1,<1.3.14|>=1.4,<1.4.7|>=1.5,<1.5.2|>=1.6,<1.6.4", - "sylius/sylius": "<1.12.19|>=1.13.0.0-alpha1,<1.13.4", - "symbiote/silverstripe-multivaluefield": ">=3,<3.1", - "symbiote/silverstripe-queuedjobs": ">=3,<3.0.2|>=3.1,<3.1.4|>=4,<4.0.7|>=4.1,<4.1.2|>=4.2,<4.2.4|>=4.3,<4.3.3|>=4.4,<4.4.3|>=4.5,<4.5.1|>=4.6,<4.6.4", - "symbiote/silverstripe-seed": "<6.0.3", - "symbiote/silverstripe-versionedfiles": "<=2.0.3", - "symfont/process": ">=0", - "symfony/cache": ">=3.1,<3.4.35|>=4,<4.2.12|>=4.3,<4.3.8", - "symfony/dependency-injection": ">=2,<2.0.17|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/error-handler": ">=4.4,<4.4.4|>=5,<5.0.4", - "symfony/form": ">=2.3,<2.3.35|>=2.4,<2.6.12|>=2.7,<2.7.50|>=2.8,<2.8.49|>=3,<3.4.20|>=4,<4.0.15|>=4.1,<4.1.9|>=4.2,<4.2.1", - "symfony/framework-bundle": ">=2,<2.3.18|>=2.4,<2.4.8|>=2.5,<2.5.2|>=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7|>=5.3.14,<5.3.15|>=5.4.3,<5.4.4|>=6.0.3,<6.0.4", - "symfony/http-client": ">=4.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", - "symfony/http-foundation": "<5.4.50|>=6,<6.4.29|>=7,<7.3.7", - "symfony/http-kernel": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.2.6", - "symfony/intl": ">=2.7,<2.7.38|>=2.8,<2.8.31|>=3,<3.2.14|>=3.3,<3.3.13", - "symfony/maker-bundle": ">=1.27,<1.29.2|>=1.30,<1.31.1", - "symfony/mime": ">=4.3,<4.3.8", - "symfony/phpunit-bridge": ">=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/polyfill": ">=1,<1.10", - "symfony/polyfill-php55": ">=1,<1.10", - "symfony/process": "<5.4.46|>=6,<6.4.14|>=7,<7.1.7", - "symfony/proxy-manager-bridge": ">=2.7,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.1.12|>=4.2,<4.2.7", - "symfony/routing": ">=2,<2.0.19", - "symfony/runtime": ">=5.3,<5.4.46|>=6,<6.4.14|>=7,<7.1.7", - "symfony/security": ">=2,<2.7.51|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.8", - "symfony/security-bundle": ">=2,<4.4.50|>=5,<5.4.20|>=6,<6.0.20|>=6.1,<6.1.12|>=6.2,<6.4.10|>=7,<7.0.10|>=7.1,<7.1.3", - "symfony/security-core": ">=2.4,<2.6.13|>=2.7,<2.7.9|>=2.7.30,<2.7.32|>=2.8,<3.4.49|>=4,<4.4.24|>=5,<5.2.9", - "symfony/security-csrf": ">=2.4,<2.7.48|>=2.8,<2.8.41|>=3,<3.3.17|>=3.4,<3.4.11|>=4,<4.0.11", - "symfony/security-guard": ">=2.8,<3.4.48|>=4,<4.4.23|>=5,<5.2.8", - "symfony/security-http": ">=2.3,<2.3.41|>=2.4,<2.7.51|>=2.8,<2.8.50|>=3,<3.4.26|>=4,<4.2.12|>=4.3,<4.3.8|>=4.4,<4.4.7|>=5,<5.0.7|>=5.1,<5.2.8|>=5.3,<5.4.47|>=6,<6.4.15|>=7,<7.1.8", - "symfony/serializer": ">=2,<2.0.11|>=4.1,<4.4.35|>=5,<5.3.12", - "symfony/symfony": "<5.4.50|>=6,<6.4.29|>=7,<7.3.7", - "symfony/translation": ">=2,<2.0.17", - "symfony/twig-bridge": ">=2,<4.4.51|>=5,<5.4.31|>=6,<6.3.8", - "symfony/ux-autocomplete": "<2.11.2", - "symfony/ux-live-component": "<2.25.1", - "symfony/ux-twig-component": "<2.25.1", - "symfony/validator": "<5.4.43|>=6,<6.4.11|>=7,<7.1.4", - "symfony/var-exporter": ">=4.2,<4.2.12|>=4.3,<4.3.8", - "symfony/web-profiler-bundle": ">=2,<2.3.19|>=2.4,<2.4.9|>=2.5,<2.5.4", - "symfony/webhook": ">=6.3,<6.3.8", - "symfony/yaml": ">=2,<2.0.22|>=2.1,<2.1.7|>=2.2.0.0-beta1,<2.2.0.0-beta2", - "symphonycms/symphony-2": "<2.6.4", - "t3/dce": "<0.11.5|>=2.2,<2.6.2", - "t3g/svg-sanitizer": "<1.0.3", - "t3s/content-consent": "<1.0.3|>=2,<2.0.2", - "tastyigniter/tastyigniter": "<4", - "tcg/voyager": "<=1.8", - "tecnickcom/tc-lib-pdf-font": "<2.6.4", - "tecnickcom/tcpdf": "<6.8", - "terminal42/contao-tablelookupwizard": "<3.3.5", - "thelia/backoffice-default-template": ">=2.1,<2.1.2", - "thelia/thelia": ">=2.1,<2.1.3", - "theonedemon/phpwhois": "<=4.2.5", - "thinkcmf/thinkcmf": "<6.0.8", - "thorsten/phpmyfaq": "<=4.0.16|>=4.1.0.0-alpha,<=4.1.0.0-beta2", - "tikiwiki/tiki-manager": "<=17.1", - "timber/timber": ">=0.16.6,<1.23.1|>=1.24,<1.24.1|>=2,<2.1", - "tinymce/tinymce": "<7.2", - "tinymighty/wiki-seo": "<1.2.2", - "titon/framework": "<9.9.99", - "tltneon/lgsl": "<7", - "tobiasbg/tablepress": "<=2.0.0.0-RC1", - "topthink/framework": "<6.0.17|>=6.1,<=8.0.4", - "topthink/think": "<=6.1.1", - "topthink/thinkphp": "<=3.2.3|>=6.1.3,<=8.0.4", - "torrentpier/torrentpier": "<=2.8.8", - "tpwd/ke_search": "<4.0.3|>=4.1,<4.6.6|>=5,<5.0.2", - "tribalsystems/zenario": "<=9.7.61188", - "truckersmp/phpwhois": "<=4.3.1", - "ttskch/pagination-service-provider": "<1", - "twbs/bootstrap": "<3.4.1|>=4,<4.3.1", - "twig/twig": "<3.11.2|>=3.12,<3.14.1|>=3.16,<3.19", - "typo3/cms": "<9.5.29|>=10,<10.4.35|>=11,<11.5.23|>=12,<12.2", - "typo3/cms-backend": "<4.1.14|>=4.2,<4.2.15|>=4.3,<4.3.7|>=4.4,<4.4.4|>=7,<=7.6.50|>=8,<=8.7.39|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", - "typo3/cms-belog": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-beuser": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-core": "<=8.7.56|>=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", - "typo3/cms-dashboard": ">=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/cms-extbase": "<6.2.24|>=7,<7.6.8|==8.1.1", - "typo3/cms-extensionmanager": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-felogin": ">=4.2,<4.2.3", - "typo3/cms-fluid": "<4.3.4|>=4.4,<4.4.1", - "typo3/cms-form": ">=8,<=8.7.39|>=9,<=9.5.24|>=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-frontend": "<4.3.9|>=4.4,<4.4.5", - "typo3/cms-indexed-search": ">=10,<=10.4.47|>=11,<=11.5.41|>=12,<=12.4.24|>=13,<=13.4.2", - "typo3/cms-install": "<4.1.14|>=4.2,<4.2.16|>=4.3,<4.3.9|>=4.4,<4.4.5|>=12.2,<12.4.8|==13.4.2", - "typo3/cms-lowlevel": ">=11,<=11.5.41", - "typo3/cms-recordlist": ">=11,<11.5.48", - "typo3/cms-recycler": ">=9,<9.5.55|>=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", - "typo3/cms-redirects": ">=10,<=10.4.54|>=11,<=11.5.48|>=12,<=12.4.40|>=13,<=13.4.22|>=14,<=14.0.1", - "typo3/cms-rte-ckeditor": ">=9.5,<9.5.42|>=10,<10.4.39|>=11,<11.5.30", - "typo3/cms-scheduler": ">=11,<=11.5.41", - "typo3/cms-setup": ">=9,<=9.5.50|>=10,<=10.4.49|>=11,<=11.5.43|>=12,<=12.4.30|>=13,<=13.4.11", - "typo3/cms-webhooks": ">=12,<=12.4.30|>=13,<=13.4.11", - "typo3/cms-workspaces": ">=9,<9.5.55|>=10,<10.4.54|>=11,<11.5.48|>=12,<12.4.37|>=13,<13.4.18", - "typo3/flow": ">=1,<1.0.4|>=1.1,<1.1.1|>=2,<2.0.1|>=2.3,<2.3.16|>=3,<3.0.12|>=3.1,<3.1.10|>=3.2,<3.2.13|>=3.3,<3.3.13|>=4,<4.0.6", - "typo3/html-sanitizer": ">=1,<=1.5.2|>=2,<=2.1.3", - "typo3/neos": ">=1.1,<1.1.3|>=1.2,<1.2.13|>=2,<2.0.4|>=2.3,<2.3.99|>=3,<3.0.20|>=3.1,<3.1.18|>=3.2,<3.2.14|>=3.3,<3.3.23|>=4,<4.0.17|>=4.1,<4.1.16|>=4.2,<4.2.12|>=4.3,<4.3.3", - "typo3/phar-stream-wrapper": ">=1,<2.1.1|>=3,<3.1.1", - "typo3/swiftmailer": ">=4.1,<4.1.99|>=5.4,<5.4.5", - "typo3fluid/fluid": ">=2,<2.0.8|>=2.1,<2.1.7|>=2.2,<2.2.4|>=2.3,<2.3.7|>=2.4,<2.4.4|>=2.5,<2.5.11|>=2.6,<2.6.10", - "ua-parser/uap-php": "<3.8", - "uasoft-indonesia/badaso": "<=2.9.7", - "unisharp/laravel-filemanager": "<2.9.1", - "universal-omega/dynamic-page-list3": "<3.6.4", - "unopim/unopim": "<=0.3", - "userfrosting/userfrosting": ">=0.3.1,<4.6.3", - "usmanhalalit/pixie": "<1.0.3|>=2,<2.0.2", - "uvdesk/community-skeleton": "<=1.1.1", - "uvdesk/core-framework": "<=1.1.1", - "vanilla/safecurl": "<0.9.2", - "verbb/comments": "<1.5.5", - "verbb/formie": "<=2.1.43", - "verbb/image-resizer": "<2.0.9", - "verbb/knock-knock": "<1.2.8", - "verot/class.upload.php": "<=2.1.6", - "vertexvaar/falsftp": "<0.2.6", - "villagedefrance/opencart-overclocked": "<=1.11.1", - "vova07/yii2-fileapi-widget": "<0.1.9", - "vrana/adminer": "<=4.8.1", - "vufind/vufind": ">=2,<9.1.1", - "waldhacker/hcaptcha": "<2.1.2", - "wallabag/tcpdf": "<6.2.22", - "wallabag/wallabag": "<2.6.11", - "wanglelecc/laracms": "<=1.0.3", - "wapplersystems/a21glossary": "<=0.4.10", - "web-auth/webauthn-framework": ">=3.3,<3.3.4|>=4.5,<4.9", - "web-auth/webauthn-lib": ">=4.5,<4.9", - "web-feet/coastercms": "==5.5", - "web-tp3/wec_map": "<3.0.3", - "webbuilders-group/silverstripe-kapost-bridge": "<0.4", - "webcoast/deferred-image-processing": "<1.0.2", - "webklex/laravel-imap": "<5.3", - "webklex/php-imap": "<5.3", - "webpa/webpa": "<3.1.2", - "webreinvent/vaahcms": "<=2.3.1", - "wikibase/wikibase": "<=1.39.3", - "wikimedia/parsoid": "<0.12.2", - "willdurand/js-translation-bundle": "<2.1.1", - "winter/wn-backend-module": "<1.2.4", - "winter/wn-cms-module": "<1.0.476|>=1.1,<1.1.11|>=1.2,<1.2.7", - "winter/wn-dusk-plugin": "<2.1", - "winter/wn-system-module": "<1.2.4", - "wintercms/winter": "<=1.2.3", - "wireui/wireui": "<1.19.3|>=2,<2.1.3", - "woocommerce/woocommerce": "<6.6|>=8.8,<8.8.5|>=8.9,<8.9.3", - "wp-cli/wp-cli": ">=0.12,<2.5", - "wp-graphql/wp-graphql": "<=1.14.5", - "wp-premium/gravityforms": "<2.4.21", - "wpanel/wpanel4-cms": "<=4.3.1", - "wpcloud/wp-stateless": "<3.2", - "wpglobus/wpglobus": "<=1.9.6", - "wwbn/avideo": "<14.3", - "xataface/xataface": "<3", - "xpressengine/xpressengine": "<3.0.15", - "yab/quarx": "<2.4.5", - "yeswiki/yeswiki": "<=4.5.4", - "yetiforce/yetiforce-crm": "<6.5", - "yidashi/yii2cmf": "<=2", - "yii2mod/yii2-cms": "<1.9.2", - "yiisoft/yii": "<1.1.31", - "yiisoft/yii2": "<2.0.52", - "yiisoft/yii2-authclient": "<2.2.15", - "yiisoft/yii2-bootstrap": "<2.0.4", - "yiisoft/yii2-dev": "<=2.0.45", - "yiisoft/yii2-elasticsearch": "<2.0.5", - "yiisoft/yii2-gii": "<=2.2.4", - "yiisoft/yii2-jui": "<2.0.4", - "yiisoft/yii2-redis": "<2.0.20", - "yikesinc/yikes-inc-easy-mailchimp-extender": "<6.8.6", - "yoast-seo-for-typo3/yoast_seo": "<7.2.3", - "yourls/yourls": "<=1.10.2", - "yuan1994/tpadmin": "<=1.3.12", - "yungifez/skuul": "<=2.6.5", - "z-push/z-push-dev": "<2.7.6", - "zencart/zencart": "<=1.5.7.0-beta", - "zendesk/zendesk_api_client_php": "<2.2.11", - "zendframework/zend-cache": ">=2.4,<2.4.8|>=2.5,<2.5.3", - "zendframework/zend-captcha": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-crypt": ">=2,<2.4.9|>=2.5,<2.5.2", - "zendframework/zend-db": "<2.2.10|>=2.3,<2.3.5", - "zendframework/zend-developer-tools": ">=1.2.2,<1.2.3", - "zendframework/zend-diactoros": "<1.8.4", - "zendframework/zend-feed": "<2.10.3", - "zendframework/zend-form": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-http": "<2.8.1", - "zendframework/zend-json": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zend-ldap": ">=2,<2.0.99|>=2.1,<2.1.99|>=2.2,<2.2.8|>=2.3,<2.3.3", - "zendframework/zend-mail": "<2.4.11|>=2.5,<2.7.2", - "zendframework/zend-navigation": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-session": ">=2,<2.2.9|>=2.3,<2.3.4", - "zendframework/zend-validator": ">=2.3,<2.3.6", - "zendframework/zend-view": ">=2,<2.2.7|>=2.3,<2.3.1", - "zendframework/zend-xmlrpc": ">=2.1,<2.1.6|>=2.2,<2.2.6", - "zendframework/zendframework": "<=3", - "zendframework/zendframework1": "<1.12.20", - "zendframework/zendopenid": "<2.0.2", - "zendframework/zendrest": "<2.0.2", - "zendframework/zendservice-amazon": "<2.0.3", - "zendframework/zendservice-api": "<1", - "zendframework/zendservice-audioscrobbler": "<2.0.2", - "zendframework/zendservice-nirvanix": "<2.0.2", - "zendframework/zendservice-slideshare": "<2.0.2", - "zendframework/zendservice-technorati": "<2.0.2", - "zendframework/zendservice-windowsazure": "<2.0.2", - "zendframework/zendxml": ">=1,<1.0.1", - "zenstruck/collection": "<0.2.1", - "zetacomponents/mail": "<1.8.2", - "zf-commons/zfc-user": "<1.2.2", - "zfcampus/zf-apigility-doctrine": ">=1,<1.0.3", - "zfr/zfr-oauth2-server-module": "<0.1.2", - "zoujingli/thinkadmin": "<=6.1.53" - }, - "default-branch": true, - "type": "metapackage", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "role": "maintainer" - }, - { - "name": "Ilya Tribusean", - "email": "slash3b@gmail.com", - "role": "maintainer" - } - ], - "description": "Prevents installation of composer packages with known security vulnerabilities: no API, simply require it", - "keywords": [ - "dev" - ], - "support": { - "issues": "https://github.com/Roave/SecurityAdvisories/issues", - "source": "https://github.com/Roave/SecurityAdvisories/tree/latest" - }, - "funding": [ - { - "url": "https://github.com/Ocramius", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/roave/security-advisories", - "type": "tidelift" - } - ], - "time": "2026-01-26T18:09:51+00:00" - }, - { - "name": "roots/wordpress-no-content", - "version": "6.9", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress.git", - "reference": "6.9" - }, - "dist": { - "type": "zip", - "url": "https://downloads.wordpress.org/release/wordpress-6.9-no-content.zip", - "reference": "6.9", - "shasum": "2d8cb4b253b690e255afde1d451e87380e6a5cb5" - }, - "require": { - "php": ">= 7.2.24" - }, - "provide": { - "wordpress/core-implementation": "6.9" - }, - "suggest": { - "ext-curl": "Performs remote request operations.", - "ext-dom": "Used to validate Text Widget content and to automatically configuring IIS7+.", - "ext-exif": "Works with metadata stored in images.", - "ext-fileinfo": "Used to detect mimetype of file uploads.", - "ext-hash": "Used for hashing, including passwords and update packages.", - "ext-imagick": "Provides better image quality for media uploads.", - "ext-json": "Used for communications with other servers.", - "ext-libsodium": "Validates Signatures and provides securely random bytes.", - "ext-mbstring": "Used to properly handle UTF8 text.", - "ext-mysqli": "Connects to MySQL for database interactions.", - "ext-openssl": "Permits SSL-based connections to other hosts.", - "ext-pcre": "Increases performance of pattern matching in code searches.", - "ext-xml": "Used for XML parsing, such as from a third-party site.", - "ext-zip": "Used for decompressing Plugins, Themes, and WordPress update packages." - }, - "type": "wordpress-core", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-2.0-or-later" - ], - "authors": [ - { - "name": "WordPress Community", - "homepage": "https://wordpress.org/about/" - } - ], - "description": "WordPress is open source software you can use to create a beautiful website, blog, or app.", - "homepage": "https://wordpress.org/", - "keywords": [ - "blog", - "cms", - "wordpress" - ], - "support": { - "docs": "https://developer.wordpress.org/", - "forum": "https://wordpress.org/support/", - "irc": "irc://irc.freenode.net/wordpress", - "issues": "https://core.trac.wordpress.org/", - "rss": "https://wordpress.org/news/feed/", - "source": "https://core.trac.wordpress.org/browser", - "wiki": "https://codex.wordpress.org/" - }, - "funding": [ - { - "url": "https://wordpressfoundation.org/donate/", - "type": "other" - } - ], - "time": "2025-12-02T19:09:36+00:00" - }, - { - "name": "sebastian/diff", - "version": "5.1.1", - "source": { - "type": "git", - "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/c41e007b4b62af48218231d6c2275e4c9b975b2e", - "reference": "c41e007b4b62af48218231d6c2275e4c9b975b2e", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "phpunit/phpunit": "^10.0", - "symfony/process": "^6.4" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "5.1-dev" - } - }, - "autoload": { - "classmap": [ - "src/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - } - ], - "description": "Diff implementation", - "homepage": "https://github.com/sebastianbergmann/diff", - "keywords": [ - "diff", - "udiff", - "unidiff", - "unified diff" - ], - "support": { - "issues": "https://github.com/sebastianbergmann/diff/issues", - "security": "https://github.com/sebastianbergmann/diff/security/policy", - "source": "https://github.com/sebastianbergmann/diff/tree/5.1.1" - }, - "funding": [ - { - "url": "https://github.com/sebastianbergmann", - "type": "github" - } - ], - "time": "2024-03-02T07:15:17+00:00" - }, - { - "name": "spatie/array-to-xml", - "version": "3.4.4", - "source": { - "type": "git", - "url": "https://github.com/spatie/array-to-xml.git", - "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/spatie/array-to-xml/zipball/88b2f3852a922dd73177a68938f8eb2ec70c7224", - "reference": "88b2f3852a922dd73177a68938f8eb2ec70c7224", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "php": "^8.0" - }, - "require-dev": { - "mockery/mockery": "^1.2", - "pestphp/pest": "^1.21", - "spatie/pest-plugin-snapshots": "^1.1" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "3.x-dev" - } - }, - "autoload": { - "psr-4": { - "Spatie\\ArrayToXml\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://freek.dev", - "role": "Developer" - } - ], - "description": "Convert an array to xml", - "homepage": "https://github.com/spatie/array-to-xml", - "keywords": [ - "array", - "convert", - "xml" - ], - "support": { - "source": "https://github.com/spatie/array-to-xml/tree/3.4.4" - }, - "funding": [ - { - "url": "https://spatie.be/open-source/support-us", - "type": "custom" - }, - { - "url": "https://github.com/spatie", - "type": "github" - } - ], - "time": "2025-12-15T09:00:41+00:00" - }, - { - "name": "squizlabs/php_codesniffer", - "version": "3.13.5", - "source": { - "type": "git", - "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "reference": "0ca86845ce43291e8f5692c7356fccf3bcf02bf4", - "shasum": "" - }, - "require": { - "ext-simplexml": "*", - "ext-tokenizer": "*", - "ext-xmlwriter": "*", - "php": ">=5.4.0" - }, - "require-dev": { - "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0 || ^8.0 || ^9.3.4" - }, - "bin": [ - "bin/phpcbf", - "bin/phpcs" - ], - "type": "library", - "notification-url": "https://packagist.org/downloads/", - "license": [ - "BSD-3-Clause" - ], - "authors": [ - { - "name": "Greg Sherwood", - "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/PHPCSStandards/PHP_CodeSniffer", - "keywords": [ - "phpcs", - "standards", - "static analysis" - ], - "support": { - "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" - }, - "funding": [ - { - "url": "https://github.com/PHPCSStandards", - "type": "github" - }, - { - "url": "https://github.com/jrfnl", - "type": "github" - }, - { - "url": "https://opencollective.com/php_codesniffer", - "type": "open_collective" - }, - { - "url": "https://thanks.dev/u/gh/phpcsstandards", - "type": "thanks_dev" - } - ], - "time": "2025-11-04T16:30:35+00:00" - }, - { - "name": "symfony/cache", - "version": "v6.4.32", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache.git", - "reference": "1b4c97d554c8c6d2c09546fcdef7f1aa338560a7" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/1b4c97d554c8c6d2c09546fcdef7f1aa338560a7", - "reference": "1b4c97d554c8c6d2c09546fcdef7f1aa338560a7", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^2.0|^3.0", - "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^2.5|^3", - "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.3.6|^7.0" - }, - "conflict": { - "doctrine/dbal": "<2.13.1", - "symfony/dependency-injection": "<5.4", - "symfony/http-kernel": "<5.4", - "symfony/var-dumper": "<5.4" - }, - "provide": { - "psr/cache-implementation": "2.0|3.0", - "psr/simple-cache-implementation": "1.0|2.0|3.0", - "symfony/cache-implementation": "1.1|2.0|3.0" - }, - "require-dev": { - "cache/integration-tests": "dev-master", - "doctrine/dbal": "^2.13.1|^3|^4", - "predis/predis": "^1.1|^2.0", - "psr/simple-cache": "^1.0|^2.0|^3.0", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/filesystem": "^5.4|^6.0|^7.0", - "symfony/http-kernel": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Cache\\": "" - }, - "classmap": [ - "Traits/ValueWrapper.php" - ], - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Provides extended PSR-6, PSR-16 (and tags) implementations", - "homepage": "https://symfony.com", - "keywords": [ - "caching", - "psr6" - ], - "support": { - "source": "https://github.com/symfony/cache/tree/v6.4.32" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-23T12:55:33+00:00" - }, - { - "name": "symfony/cache-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/cache-contracts.git", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", - "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/cache": "^3.0" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Cache\\": "" - } - }, - "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": "Generic abstractions related to caching", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/cache-contracts/tree/v3.6.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": "2025-03-13T15:25:07+00:00" - }, - { - "name": "symfony/console", - "version": "v6.4.32", - "source": { - "type": "git", - "url": "https://github.com/symfony/console.git", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", - "reference": "0bc2199c6c1f05276b05956f1ddc63f6d7eb5fc3", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/string": "^5.4|^6.0|^7.0" - }, - "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/dotenv": "<5.4", - "symfony/event-dispatcher": "<5.4", - "symfony/lock": "<5.4", - "symfony/process": "<5.4" - }, - "provide": { - "psr/log-implementation": "1.0|2.0|3.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/event-dispatcher": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/lock": "^5.4|^6.0|^7.0", - "symfony/messenger": "^5.4|^6.0|^7.0", - "symfony/process": "^5.4|^6.0|^7.0", - "symfony/stopwatch": "^5.4|^6.0|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Console\\": "" - }, - "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": "Eases the creation of beautiful and testable command line interfaces", - "homepage": "https://symfony.com", - "keywords": [ - "cli", - "command-line", - "console", - "terminal" - ], - "support": { - "source": "https://github.com/symfony/console/tree/v6.4.32" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-13T08:45:59+00:00" - }, - { - "name": "symfony/deprecation-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/deprecation-contracts.git", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", - "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "files": [ - "function.php" - ] - }, - "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": "A generic function and convention to trigger deprecation notices", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.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-09-25T14:21:43+00:00" - }, - { - "name": "symfony/event-dispatcher", - "version": "v6.4.32", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "99d7e101826e6610606b9433248f80c1997cd20b" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/99d7e101826e6610606b9433248f80c1997cd20b", - "reference": "99d7e101826e6610606b9433248f80c1997cd20b", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/event-dispatcher-contracts": "^2.5|^3" - }, - "conflict": { - "symfony/dependency-injection": "<5.4", - "symfony/service-contracts": "<2.5" - }, - "provide": { - "psr/event-dispatcher-implementation": "1.0", - "symfony/event-dispatcher-implementation": "2.0|3.0" - }, - "require-dev": { - "psr/log": "^1|^2|^3", - "symfony/config": "^5.4|^6.0|^7.0", - "symfony/dependency-injection": "^5.4|^6.0|^7.0", - "symfony/error-handler": "^5.4|^6.0|^7.0", - "symfony/expression-language": "^5.4|^6.0|^7.0", - "symfony/http-foundation": "^5.4|^6.0|^7.0", - "symfony/service-contracts": "^2.5|^3", - "symfony/stopwatch": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\EventDispatcher\\": "" - }, - "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": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/event-dispatcher/tree/v6.4.32" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-05T11:13:48+00:00" - }, - { - "name": "symfony/event-dispatcher-contracts", - "version": "v3.6.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/event-dispatcher-contracts.git", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", - "reference": "59eb412e93815df44f05f342958efa9f46b1e586", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/event-dispatcher": "^1" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\EventDispatcher\\": "" - } - }, - "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": "Generic abstractions related to dispatching event", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.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-09-25T14:21:43+00:00" - }, - { - "name": "symfony/filesystem", - "version": "v6.4.30", - "source": { - "type": "git", - "url": "https://github.com/symfony/filesystem.git", - "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/441c6b69f7222aadae7cbf5df588496d5ee37789", - "reference": "441c6b69f7222aadae7cbf5df588496d5ee37789", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-mbstring": "~1.8" - }, - "require-dev": { - "symfony/process": "^5.4|^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Filesystem\\": "" - }, - "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": "Provides basic utilities for the filesystem", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/filesystem/tree/v6.4.30" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-11-26T14:43:45+00:00" - }, - { - "name": "symfony/finder", - "version": "v6.4.32", - "source": { - "type": "git", - "url": "https://github.com/symfony/finder.git", - "reference": "3ec24885c1d9ababbb9c8f63bb42fea3c8c9b6de" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/3ec24885c1d9ababbb9c8f63bb42fea3c8c9b6de", - "reference": "3ec24885c1d9ababbb9c8f63bb42fea3c8c9b6de", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "require-dev": { - "symfony/filesystem": "^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Finder\\": "" - }, - "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": "Finds files and directories via an intuitive fluent interface", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/finder/tree/v6.4.32" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-10T14:09:00+00:00" - }, - { - "name": "symfony/options-resolver", - "version": "v6.4.30", - "source": { - "type": "git", - "url": "https://github.com/symfony/options-resolver.git", - "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", - "reference": "eeaa8cabe54c7b3516938c72a4a161c0cc80a34f", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\OptionsResolver\\": "" - }, - "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": "Provides an improved replacement for the array_replace PHP function", - "homepage": "https://symfony.com", - "keywords": [ - "config", - "configuration", - "options" - ], - "support": { - "source": "https://github.com/symfony/options-resolver/tree/v6.4.30" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-11-12T13:06:53+00:00" - }, - { - "name": "symfony/polyfill-ctype", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", - "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "provide": { - "ext-ctype": "*" - }, - "suggest": { - "ext-ctype": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Gert de Pagter", - "email": "BackEndTea@gmail.com" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for ctype functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" - ], - "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-intl-grapheme", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", - "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Grapheme\\": "" - } - }, - "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 for intl's grapheme_* functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "grapheme", - "intl", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-06-27T09:58:17+00:00" - }, - { - "name": "symfony/polyfill-intl-normalizer", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-intl-normalizer.git", - "reference": "3833d7255cc303546435cb650316bff708a1c75c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", - "reference": "3833d7255cc303546435cb650316bff708a1c75c", - "shasum": "" - }, - "require": { - "php": ">=7.2" - }, - "suggest": { - "ext-intl": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Intl\\Normalizer\\": "" - }, - "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 for intl's Normalizer class and related functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "intl", - "normalizer", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-09-09T11:45:10+00:00" - }, - { - "name": "symfony/polyfill-mbstring", - "version": "v1.33.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", - "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": ">=7.2" - }, - "provide": { - "ext-mbstring": "*" - }, - "suggest": { - "ext-mbstring": "For best performance" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/polyfill", - "name": "symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Mbstring\\": "" - } - }, - "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 for the Mbstring extension", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "mbstring", - "polyfill", - "portable", - "shim" - ], - "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2024-12-23T08:48:59+00:00" - }, - { - "name": "symfony/process", - "version": "v6.4.32", - "source": { - "type": "git", - "url": "https://github.com/symfony/process.git", - "reference": "c593135be689b21e6164b1e8f6f5dbf1506b065c" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/c593135be689b21e6164b1e8f6f5dbf1506b065c", - "reference": "c593135be689b21e6164b1e8f6f5dbf1506b065c", - "shasum": "" - }, - "require": { - "php": ">=8.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Process\\": "" - }, - "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": "Executes commands in sub-processes", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/process/tree/v6.4.32" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2026-01-15T13:23:20+00:00" - }, - { - "name": "symfony/service-contracts", - "version": "v3.6.1", - "source": { - "type": "git", - "url": "https://github.com/symfony/service-contracts.git", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43", - "reference": "45112560a3ba2d715666a509a0bc9521d10b6c43", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "conflict": { - "ext-psr": "<1.1|>=2" - }, - "type": "library", - "extra": { - "thanks": { - "url": "https://github.com/symfony/contracts", - "name": "symfony/contracts" - }, - "branch-alias": { - "dev-main": "3.6-dev" - } - }, - "autoload": { - "psr-4": { - "Symfony\\Contracts\\Service\\": "" - }, - "exclude-from-classmap": [ - "/Test/" - ] - }, - "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": "Generic abstractions related to writing services", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/service-contracts/tree/v3.6.1" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-07-15T11:30:57+00:00" - }, - { - "name": "symfony/string", - "version": "v6.4.30", - "source": { - "type": "git", - "url": "https://github.com/symfony/string.git", - "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/50590a057841fa6bf69d12eceffce3465b9e32cb", - "reference": "50590a057841fa6bf69d12eceffce3465b9e32cb", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/polyfill-ctype": "~1.8", - "symfony/polyfill-intl-grapheme": "~1.0", - "symfony/polyfill-intl-normalizer": "~1.0", - "symfony/polyfill-mbstring": "~1.0" - }, - "conflict": { - "symfony/translation-contracts": "<2.5" - }, - "require-dev": { - "symfony/http-client": "^5.4|^6.0|^7.0", - "symfony/intl": "^6.2|^7.0", - "symfony/translation-contracts": "^2.5|^3.0", - "symfony/var-exporter": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "files": [ - "Resources/functions.php" - ], - "psr-4": { - "Symfony\\Component\\String\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", - "homepage": "https://symfony.com", - "keywords": [ - "grapheme", - "i18n", - "string", - "unicode", - "utf-8", - "utf8" - ], - "support": { - "source": "https://github.com/symfony/string/tree/v6.4.30" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-11-21T18:03:05+00:00" - }, - { - "name": "symfony/var-exporter", - "version": "v6.4.26", - "source": { - "type": "git", - "url": "https://github.com/symfony/var-exporter.git", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/466fcac5fa2e871f83d31173f80e9c2684743bfc", - "reference": "466fcac5fa2e871f83d31173f80e9c2684743bfc", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3" - }, - "require-dev": { - "symfony/property-access": "^6.4|^7.0", - "symfony/serializer": "^6.4|^7.0", - "symfony/var-dumper": "^5.4|^6.0|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\VarExporter\\": "" - }, - "exclude-from-classmap": [ - "/Tests/" - ] - }, - "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": "Allows exporting any serializable PHP data structure to plain PHP code", - "homepage": "https://symfony.com", - "keywords": [ - "clone", - "construct", - "export", - "hydrate", - "instantiate", - "lazy-loading", - "proxy", - "serialize" - ], - "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.26" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-09-11T09:57:09+00:00" - }, - { - "name": "symfony/yaml", - "version": "v6.4.30", - "source": { - "type": "git", - "url": "https://github.com/symfony/yaml.git", - "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/8207ae83da19ee3748d6d4f567b4d9a7c656e331", - "reference": "8207ae83da19ee3748d6d4f567b4d9a7c656e331", - "shasum": "" - }, - "require": { - "php": ">=8.1", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/polyfill-ctype": "^1.8" - }, - "conflict": { - "symfony/console": "<5.4" - }, - "require-dev": { - "symfony/console": "^5.4|^6.0|^7.0" - }, - "bin": [ - "Resources/bin/yaml-lint" - ], - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\Yaml\\": "" - }, - "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": "Loads and dumps YAML files", - "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/yaml/tree/v6.4.30" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://github.com/nicolas-grekas", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2025-12-02T11:50:18+00:00" - }, - { - "name": "vimeo/psalm", - "version": "5.26.1", - "source": { - "type": "git", - "url": "https://github.com/vimeo/psalm.git", - "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/vimeo/psalm/zipball/d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", - "reference": "d747f6500b38ac4f7dfc5edbcae6e4b637d7add0", - "shasum": "" - }, - "require": { - "amphp/amp": "^2.4.2", - "amphp/byte-stream": "^1.5", - "composer-runtime-api": "^2", - "composer/semver": "^1.4 || ^2.0 || ^3.0", - "composer/xdebug-handler": "^2.0 || ^3.0", - "dnoegel/php-xdg-base-dir": "^0.1.1", - "ext-ctype": "*", - "ext-dom": "*", - "ext-json": "*", - "ext-libxml": "*", - "ext-mbstring": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*", - "felixfbecker/advanced-json-rpc": "^3.1", - "felixfbecker/language-server-protocol": "^1.5.2", - "fidry/cpu-core-counter": "^0.4.1 || ^0.5.1 || ^1.0.0", - "netresearch/jsonmapper": "^1.0 || ^2.0 || ^3.0 || ^4.0", - "nikic/php-parser": "^4.17", - "php": "^7.4 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0", - "sebastian/diff": "^4.0 || ^5.0 || ^6.0", - "spatie/array-to-xml": "^2.17.0 || ^3.0", - "symfony/console": "^4.1.6 || ^5.0 || ^6.0 || ^7.0", - "symfony/filesystem": "^5.4 || ^6.0 || ^7.0" - }, - "conflict": { - "nikic/php-parser": "4.17.0" - }, - "provide": { - "psalm/psalm": "self.version" - }, - "require-dev": { - "amphp/phpunit-util": "^2.0", - "bamarni/composer-bin-plugin": "^1.4", - "brianium/paratest": "^6.9", - "ext-curl": "*", - "mockery/mockery": "^1.5", - "nunomaduro/mock-final-classes": "^1.1", - "php-parallel-lint/php-parallel-lint": "^1.2", - "phpstan/phpdoc-parser": "^1.6", - "phpunit/phpunit": "^9.6", - "psalm/plugin-mockery": "^1.1", - "psalm/plugin-phpunit": "^0.18", - "slevomat/coding-standard": "^8.4", - "squizlabs/php_codesniffer": "^3.6", - "symfony/process": "^4.4 || ^5.0 || ^6.0 || ^7.0" - }, - "suggest": { - "ext-curl": "In order to send data to shepherd", - "ext-igbinary": "^2.0.5 is required, used to serialize caching data" - }, - "bin": [ - "psalm", - "psalm-language-server", - "psalm-plugin", - "psalm-refactor", - "psalter" - ], - "type": "project", - "extra": { - "branch-alias": { - "dev-1.x": "1.x-dev", - "dev-2.x": "2.x-dev", - "dev-3.x": "3.x-dev", - "dev-4.x": "4.x-dev", - "dev-master": "5.x-dev" - } - }, - "autoload": { - "psr-4": { - "Psalm\\": "src/Psalm/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Matthew Brown" - } - ], - "description": "A static analysis tool for finding errors in PHP applications", - "keywords": [ - "code", - "inspection", - "php", - "static analysis" - ], - "support": { - "docs": "https://psalm.dev/docs", - "issues": "https://github.com/vimeo/psalm/issues", - "source": "https://github.com/vimeo/psalm" - }, - "time": "2024-09-08T18:53:08+00:00" - }, - { - "name": "webmozart/assert", - "version": "1.12.1", - "source": { - "type": "git", - "url": "https://github.com/webmozarts/assert.git", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/webmozarts/assert/zipball/9be6926d8b485f55b9229203f962b51ed377ba68", - "reference": "9be6926d8b485f55b9229203f962b51ed377ba68", - "shasum": "" - }, - "require": { - "ext-ctype": "*", - "ext-date": "*", - "ext-filter": "*", - "php": "^7.2 || ^8.0" - }, - "suggest": { - "ext-intl": "", - "ext-simplexml": "", - "ext-spl": "" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.10-dev" - } - }, - "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" - } - ], - "description": "Assertions to validate method input/output with nice error messages.", - "keywords": [ - "assert", - "check", - "validate" - ], - "support": { - "issues": "https://github.com/webmozarts/assert/issues", - "source": "https://github.com/webmozarts/assert/tree/1.12.1" - }, - "time": "2025-10-29T15:56:20+00:00" - }, - { - "name": "wp-coding-standards/wpcs", - "version": "3.3.0", - "source": { - "type": "git", - "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", - "reference": "7795ec6fa05663d716a549d0b44e47ffc8b0d4a6", - "shasum": "" - }, - "require": { - "ext-filter": "*", - "ext-libxml": "*", - "ext-tokenizer": "*", - "ext-xmlreader": "*", - "php": ">=7.2", - "phpcsstandards/phpcsextra": "^1.5.0", - "phpcsstandards/phpcsutils": "^1.1.0", - "squizlabs/php_codesniffer": "^3.13.4" - }, - "require-dev": { - "php-parallel-lint/php-console-highlighter": "^1.0.0", - "php-parallel-lint/php-parallel-lint": "^1.4.0", - "phpcompatibility/php-compatibility": "^10.0.0@dev", - "phpcsstandards/phpcsdevtools": "^1.2.0", - "phpunit/phpunit": "^8.0 || ^9.0" - }, - "suggest": { - "ext-iconv": "For improved results", - "ext-mbstring": "For improved results" - }, - "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", - "static analysis", - "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" - }, - "funding": [ - { - "url": "https://opencollective.com/php_codesniffer", - "type": "custom" - } - ], - "time": "2025-11-25T12:08:04+00:00" - }, - { - "name": "wp-hooks/wordpress-core", - "version": "1.11.0", - "source": { - "type": "git", - "url": "https://github.com/wp-hooks/wordpress-core-hooks.git", - "reference": "610a3721216797daa72a16044c40938ac040551a" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/wp-hooks/wordpress-core-hooks/zipball/610a3721216797daa72a16044c40938ac040551a", - "reference": "610a3721216797daa72a16044c40938ac040551a", - "shasum": "" - }, - "replace": { - "johnbillion/wp-hooks": "*" - }, - "require-dev": { - "erusev/parsedown": "1.8.0-beta-7", - "oomphinc/composer-installers-extender": "^2", - "roots/wordpress-core-installer": "^1.0.0", - "roots/wordpress-full": "6.9", - "wp-hooks/generator": "1.0.0" - }, - "type": "library", - "extra": { - "wp-hooks": { - "ignore-files": [ - "wp-admin/includes/deprecated.php", - "wp-admin/includes/ms-deprecated.php", - "wp-content/", - "wp-includes/deprecated.php", - "wp-includes/ID3/", - "wp-includes/ms-deprecated.php", - "wp-includes/pomo/", - "wp-includes/random_compat/", - "wp-includes/Requests/", - "wp-includes/SimplePie/", - "wp-includes/sodium_compat/", - "wp-includes/Text/" - ], - "ignore-hooks": [ - "load-categories.php", - "load-edit-link-categories.php", - "load-edit-tags.php", - "load-page-new.php", - "load-page.php", - "option_enable_xmlrpc", - "edit_post_{$field}", - "pre_post_{$field}", - "post_{$field}", - "pre_option_enable_xmlrpc", - "$page_hook", - "$hook", - "$hook_name" - ] - }, - "wordpress-install-dir": "vendor/wordpress/wordpress" - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "GPL-3.0-or-later" - ], - "authors": [ - { - "name": "John Blackbourn", - "homepage": "https://johnblackbourn.com/" - } - ], - "description": "All the actions and filters from WordPress core in machine-readable JSON format.", - "support": { - "issues": "https://github.com/wp-hooks/wordpress-core-hooks/issues", - "source": "https://github.com/wp-hooks/wordpress-core-hooks/tree/1.11.0" - }, - "funding": [ - { - "url": "https://github.com/sponsors/johnbillion", - "type": "github" - } - ], - "time": "2025-12-03T22:11:59+00:00" - } - ], - "aliases": [], - "minimum-stability": "stable", - "stability-flags": { - "roave/security-advisories": 20 - }, - "prefer-stable": false, - "prefer-lowest": false, - "platform": { - "php": "^8.1 | ^8.2 | ^8.3 | ^8.4", - "ext-json": "*" - }, - "platform-dev": {}, - "platform-overrides": { - "php": "8.1" - }, - "plugin-api-version": "2.6.0" -} From 602fe6389132a35dfd2d2f6ca6799ded430782ab Mon Sep 17 00:00:00 2001 From: mricoul Date: Fri, 26 Jun 2026 12:21:52 +0200 Subject: [PATCH 04/18] chore: remove psalm --- composer.json | 10 +++------- grumphp.yml | 4 ---- psalm.xml.dist | 20 -------------------- 3 files changed, 3 insertions(+), 31 deletions(-) delete mode 100644 psalm.xml.dist diff --git a/composer.json b/composer.json index 894b89e..1db1560 100644 --- a/composer.json +++ b/composer.json @@ -34,7 +34,6 @@ }, "require-dev": { "dealerdirect/phpcodesniffer-composer-installer": "^1.0", - "humanmade/psalm-plugin-wordpress": "^3.0", "overtrue/phplint": "^9.1", "php-parallel-lint/php-parallel-lint": "^1.3", "php-stubs/wordpress-seo-stubs": "^20.5", @@ -42,17 +41,14 @@ "phpro/grumphp-shim": "^1.5", "roave/security-advisories": "dev-latest", "roots/wordpress-no-content": "^6.0", - "vimeo/psalm": "^5.20", - "wp-coding-standards/wpcs": "^3.0" + "wp-coding-standards/wpcs": "^3.3" }, "scripts": { "cs": "./vendor/bin/phpcs", - "cb": "./vendor/bin/phpcbf", - "psalm": "./vendor/bin/psalm" + "cb": "./vendor/bin/phpcbf" }, "scripts-descriptions": { "cs": "Run PHP CodeSniffer on codebase using custom ruleset.", - "cb": "Run PHP Code Beautifier and Fixer on codebase using custom ruleset.", - "psalm": "Run psalm on codebase using custom ruleset." + "cb": "Run PHP Code Beautifier and Fixer on codebase using custom ruleset." } } diff --git a/grumphp.yml b/grumphp.yml index d968d08..b2c84ac 100644 --- a/grumphp.yml +++ b/grumphp.yml @@ -22,10 +22,6 @@ grumphp: jsonlint: ignore_patterns: [] detect_key_conflicts: false - psalm: - config: psalm.xml.dist - triggered_by: ['php'] - show_info: true yamllint: testsuites: [] extensions: [] diff --git a/psalm.xml.dist b/psalm.xml.dist deleted file mode 100644 index aac95d3..0000000 --- a/psalm.xml.dist +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - From cda05962d8c82fc0fe4f0125a475963344761cd4 Mon Sep 17 00:00:00 2001 From: Milan Ricoul Date: Fri, 26 Jun 2026 15:00:59 +0200 Subject: [PATCH 05/18] Add SEOPress compatibility with dedicated SEO plugin services. Extract shared FAQ schema generation and resolve Yoast or SEOPress at runtime, with both plugins available in wp-env via Composer. --- .gitignore | 3 + .wp-env.json | 4 +- README.md | 20 +- blockparty-faq.php | 11 +- composer.json | 18 +- includes/hooks/Schema_Hooks.php | 16 + includes/hooks/schema.php | 21 - includes/schema/FAQ_Schema.php | 83 ++++ includes/schema/FAQ_Schema_Generator.php | 419 ++++++++++++++++++++ includes/schema/faq_schema.php | 280 ------------- includes/services/Seo_Service_Interface.php | 30 ++ includes/services/Seo_Service_Resolver.php | 75 ++++ includes/services/Seopress_Seo_Service.php | 161 ++++++++ includes/services/Yoast_Seo_Service.php | 46 +++ package.json | 5 +- 15 files changed, 873 insertions(+), 319 deletions(-) create mode 100644 includes/hooks/Schema_Hooks.php delete mode 100644 includes/hooks/schema.php create mode 100644 includes/schema/FAQ_Schema.php create mode 100644 includes/schema/FAQ_Schema_Generator.php delete mode 100644 includes/schema/faq_schema.php create mode 100644 includes/services/Seo_Service_Interface.php create mode 100644 includes/services/Seo_Service_Resolver.php create mode 100644 includes/services/Seopress_Seo_Service.php create mode 100644 includes/services/Yoast_Seo_Service.php diff --git a/.gitignore b/.gitignore index e5abd4a..c77c5df 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ phpunit.xml # Composer composer.lock + +# Plugins +.wp-env/plugins/ diff --git a/.wp-env.json b/.wp-env.json index dafab87..5691edd 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,5 +1,7 @@ { "plugins": [ - "." + ".", + ".wp-env/plugins/wordpress-seo", + ".wp-env/plugins/wp-seopress" ] } diff --git a/README.md b/README.md index 82b886d..f7bdfbc 100644 --- a/README.md +++ b/README.md @@ -24,32 +24,30 @@ A Gutenberg block for SEO friendly FAQ in an accessible accordion. npm run build ``` -4. Start the WordPress environment and install Yoast SEO: +4. Install PHP dependencies (downloads SEO plugins into `.wp-env/plugins/`): ```bash - npm run setup:env + composer install ``` - **Note:** On Windows, you may need to run the commands separately: +5. Start the WordPress environment: ```bash - npm run start:env - # Wait for WordPress to be ready (about 10-15 seconds) - npm run setup + npm run env:start ``` + Yoast SEO and SEOPress are mounted and activated automatically via `.wp-env.json`. + ### Available Scripts - `npm run build` - Build the blocks for production - `npm run start` - Start the development server with hot reload -- `npm run start:env` - Start the WordPress environment (wp-env) -- `npm run stop:env` - Stop the WordPress environment -- `npm run install:yoast` - Install and activate Yoast SEO plugin (required for schema generation) -- `npm run setup:env` - Start wp-env and install Yoast SEO in one command +- `npm run env:start` - Start the WordPress environment (wp-env) +- `npm run env:stop` - Stop the WordPress environment ### Note -Yoast SEO is required for the FAQ schema (JSON-LD) generation. It is installed automatically via `npm run setup:env` but is not versioned in the repository. +FAQ structured data (JSON-LD) requires Yoast SEO or SEOPress. Both plugins are available in the local wp-env environment; deactivate one in the WordPress admin if you need to test a single integration. SEO plugin files are not versioned in the repository (installed via Composer into `.wp-env/plugins/`). ## Changelog diff --git a/blockparty-faq.php b/blockparty-faq.php index a0c11f4..93ede38 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -46,9 +46,16 @@ // Plugin URL and PATH define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); +// Schema & SEO services +require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/FAQ_Schema_Generator.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/FAQ_Schema.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Interface.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Yoast_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seopress_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Resolver.php'; + // Hooks -require_once BLOCKPARTY_FAQ_DIR . 'includes/hooks/schema.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/faq_schema.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/hooks/Schema_Hooks.php'; /** * Initialize plugin blocks. diff --git a/composer.json b/composer.json index 1db1560..6236caf 100644 --- a/composer.json +++ b/composer.json @@ -27,6 +27,13 @@ "php": "8.1" } }, + "extra": { + "installer-paths": { + ".wp-env/plugins/{$name}/": [ + "type:wordpress-plugin" + ] + } + }, "require": { "php": "^8.1 | ^8.2 | ^8.3 | ^8.4", "ext-json": "*", @@ -41,8 +48,17 @@ "phpro/grumphp-shim": "^1.5", "roave/security-advisories": "dev-latest", "roots/wordpress-no-content": "^6.0", - "wp-coding-standards/wpcs": "^3.3" + "wp-coding-standards/wpcs": "^3.3", + "wp-plugin/wordpress-seo": "27.9", + "wp-plugin/wp-seopress": "10.0.1" }, + "repositories": [ + { + "name": "wp-packages", + "type": "composer", + "url": "https://repo.wp-packages.org" + } + ], "scripts": { "cs": "./vendor/bin/phpcs", "cb": "./vendor/bin/phpcbf" diff --git a/includes/hooks/Schema_Hooks.php b/includes/hooks/Schema_Hooks.php new file mode 100644 index 0000000..edf50e7 --- /dev/null +++ b/includes/hooks/Schema_Hooks.php @@ -0,0 +1,16 @@ +context = $context; + } + + /** + * Determines whether or not a piece should be added to the graph. + * + * @return bool Whether or not a piece should be added. + */ + public function is_needed(): bool { + $generator = $this->get_generator(); + + if ( ! $generator->has_faq_blocks() ) { + return false; + } + + if ( ! \is_array( $this->context->schema_page_type ) ) { + $this->context->schema_page_type = [ $this->context->schema_page_type ]; + } + + $this->context->schema_page_type[] = 'FAQPage'; + $this->context->main_entity_of_page = $generator->generate_main_entity_ids(); + + return true; + } + + /** + * Render a list of questions, referencing them by ID. + * + * @return array> Schema graph pieces. + */ + public function generate(): array { + return $this->get_generator()->generate_questions(); + } + + /** + * Get or create the FAQ schema generator from Yoast context. + * + * @return FAQ_Schema_Generator + */ + private function get_generator(): FAQ_Schema_Generator { + if ( null !== $this->generator ) { + return $this->generator; + } + + $faq_blocks = $this->context->blocks['blockparty/faq'] ?? []; + + $this->generator = new FAQ_Schema_Generator( + $this->context->canonical, + $faq_blocks + ); + + return $this->generator; + } +} diff --git a/includes/schema/FAQ_Schema_Generator.php b/includes/schema/FAQ_Schema_Generator.php new file mode 100644 index 0000000..7d06298 --- /dev/null +++ b/includes/schema/FAQ_Schema_Generator.php @@ -0,0 +1,419 @@ +> + */ + private array $faq_blocks; + + /** + * @param string $canonical Canonical URL for the current page. + * @param array> $faq_blocks Parsed blockparty/faq blocks. + */ + public function __construct( string $canonical, array $faq_blocks ) { + $this->canonical = $canonical; + $this->faq_blocks = $faq_blocks; + } + + /** + * Whether FAQ blocks are available for schema generation. + * + * @return bool + */ + public function has_faq_blocks(): bool { + return ! empty( $this->faq_blocks ); + } + + /** + * Collect blockparty/faq blocks from post content. + * + * @param \WP_Post|null $post Post object. Defaults to the current global post. + * + * @return array> + */ + public static function get_faq_blocks_from_post( ?\WP_Post $post = null ): array { + $post = $post ?? get_post(); + + if ( ! $post instanceof \WP_Post ) { + return []; + } + + $blocks = parse_blocks( $post->post_content ); + + return self::find_blocks_by_name( $blocks, 'blockparty/faq' ); + } + + /** + * Recursively find blocks by name in a parsed block tree. + * + * @param array> $blocks Parsed blocks. + * @param string $block_name Block name to match. + * + * @return array> + */ + public static function find_blocks_by_name( array $blocks, string $block_name ): array { + $found = []; + + foreach ( $blocks as $block ) { + if ( ( $block['blockName'] ?? '' ) === $block_name ) { + $found[] = $block; + } + + if ( ! empty( $block['innerBlocks'] ) ) { + $found = array_merge( + $found, + self::find_blocks_by_name( $block['innerBlocks'], $block_name ) + ); + } + } + + return $found; + } + + /** + * Generate main entity @id references for Yoast FAQPage integration. + * + * @return array> + */ + public function generate_main_entity_ids(): array { + $ids = []; + + foreach ( $this->faq_blocks as $block ) { + if ( empty( $block['innerBlocks'] ) ) { + continue; + } + + foreach ( $block['innerBlocks'] as $item_block ) { + if ( 'blockparty/faq-item' !== ( $item_block['blockName'] ?? '' ) ) { + continue; + } + + $question_block = self::find_child_block( $item_block, 'blockparty/faq-question' ); + + if ( ! $question_block ) { + continue; + } + + $question_text = self::get_question_text( $question_block ); + + if ( empty( $question_text ) ) { + continue; + } + + $question_id = md5( $question_text ); + $ids[] = [ + '@id' => $this->canonical . '#' . esc_attr( $question_id ), + ]; + } + } + + return $ids; + } + + /** + * Generate Schema.org Question pieces (Yoast graph format). + * + * @return array> + */ + public function generate_questions(): array { + $graph = []; + $position = 1; + + foreach ( $this->faq_blocks as $block ) { + if ( empty( $block['innerBlocks'] ) ) { + continue; + } + + foreach ( $block['innerBlocks'] as $item_block ) { + if ( 'blockparty/faq-item' !== ( $item_block['blockName'] ?? '' ) ) { + continue; + } + + if ( empty( $item_block['innerBlocks'] ) ) { + continue; + } + + $question_block = self::find_child_block( $item_block, 'blockparty/faq-question' ); + $answer_block = self::find_child_block( $item_block, 'blockparty/faq-answer' ); + + if ( ! $question_block ) { + continue; + } + + $question_text = self::get_question_text( $question_block ); + + if ( empty( $question_text ) ) { + continue; + } + + $answer_content = ''; + + if ( $answer_block ) { + $answer_content = self::get_answer_content( $answer_block ); + } + + if ( empty( $answer_content ) ) { + continue; + } + + $question_id = md5( $question_text ); + $graph[] = self::build_question_piece( + $question_text, + $answer_content, + $question_id, + $position, + $this->canonical + ); + ++$position; + } + } + + return $graph; + } + + /** + * Generate a FAQPage schema (SEOPress format). + * + * @return array|null + */ + public function generate_faq_page_schema(): ?array { + $questions = $this->generate_questions_for_nested_schema(); + + if ( empty( $questions ) ) { + return null; + } + + return [ + '@context' => 'https://schema.org', + '@type' => 'FAQPage', + 'mainEntity' => $questions, + ]; + } + + /** + * Generate Question entries for nested FAQPage mainEntity (SEOPress). + * + * @return array> + */ + public function generate_questions_for_nested_schema(): array { + $questions = []; + $position = 1; + + foreach ( $this->faq_blocks as $block ) { + if ( empty( $block['innerBlocks'] ) ) { + continue; + } + + foreach ( $block['innerBlocks'] as $item_block ) { + if ( 'blockparty/faq-item' !== ( $item_block['blockName'] ?? '' ) ) { + continue; + } + + if ( empty( $item_block['innerBlocks'] ) ) { + continue; + } + + $question_block = self::find_child_block( $item_block, 'blockparty/faq-question' ); + $answer_block = self::find_child_block( $item_block, 'blockparty/faq-answer' ); + + if ( ! $question_block ) { + continue; + } + + $question_text = self::get_question_text( $question_block ); + + if ( empty( $question_text ) ) { + continue; + } + + $answer_content = ''; + + if ( $answer_block ) { + $answer_content = self::get_answer_content( $answer_block ); + } + + if ( empty( $answer_content ) ) { + continue; + } + + $questions[] = [ + '@type' => 'Question', + 'position' => $position, + 'name' => esc_html( wp_strip_all_tags( $question_text ) ), + 'answerCount' => 1, + 'acceptedAnswer' => self::build_accepted_answer( $answer_content ), + ]; + ++$position; + } + } + + return $questions; + } + + /** + * Find a direct child block by name. + * + * @param array $parent_block Parent block. + * @param string $block_name Block name to find. + * + * @return array|null + */ + private static function find_child_block( array $parent_block, string $block_name ): ?array { + if ( empty( $parent_block['innerBlocks'] ) ) { + return null; + } + + foreach ( $parent_block['innerBlocks'] as $inner_block ) { + if ( ( $inner_block['blockName'] ?? '' ) === $block_name ) { + return $inner_block; + } + } + + return null; + } + + /** + * Get question text from block attributes or InnerBlocks. + * + * @param array $question_block Question block. + * + * @return string + */ + private static function get_question_text( array $question_block ): string { + $question_text = $question_block['attrs']['question'] ?? ''; + + if ( empty( $question_text ) && ! empty( $question_block['innerBlocks'] ) ) { + $question_text = self::get_question_content( $question_block ); + } + + return $question_text; + } + + /** + * Get question content from InnerBlocks. + * + * @param array $question_block Question block with InnerBlocks. + * + * @return string + */ + private static function get_question_content( array $question_block ): string { + if ( empty( $question_block['innerBlocks'] ) ) { + return ''; + } + + $content = ''; + + foreach ( $question_block['innerBlocks'] as $inner_block ) { + $content .= render_block( $inner_block ); + } + + return wp_strip_all_tags( $content ); + } + + /** + * Get answer content from InnerBlocks. + * + * @param array $answer_block Answer block with InnerBlocks. + * + * @return string + */ + private static function get_answer_content( array $answer_block ): string { + if ( empty( $answer_block['innerBlocks'] ) ) { + return ''; + } + + $content = ''; + + foreach ( $answer_block['innerBlocks'] as $inner_block ) { + $content .= render_block( $inner_block ); + } + + return $content; + } + + /** + * Build a Schema.org Question piece (Yoast graph node). + * + * @param string $question_text Question text. + * @param string $answer_content Answer HTML content. + * @param string $question_id Question identifier. + * @param int $position Question position. + * @param string $canonical Canonical URL. + * + * @return array + */ + private static function build_question_piece( + string $question_text, + string $answer_content, + string $question_id, + int $position, + string $canonical + ): array { + $url = $canonical . '#' . esc_attr( $question_id ); + + return [ + '@type' => 'Question', + '@id' => $url, + 'position' => $position, + 'url' => $url, + 'name' => esc_html( wp_strip_all_tags( $question_text ) ), + 'answerCount' => 1, + 'acceptedAnswer' => self::build_accepted_answer( $answer_content ), + 'inLanguage' => get_bloginfo( 'language' ), + ]; + } + + /** + * Build a Schema.org Answer piece. + * + * @param string $answer Answer HTML content. + * + * @return array + */ + private static function build_accepted_answer( string $answer ): array { + $allowed_html = [ + 'h1' => [], + 'h2' => [], + 'h3' => [], + 'h4' => [], + 'h5' => [], + 'h6' => [], + 'p' => [], + 'br' => [], + 'ol' => [], + 'ul' => [], + 'li' => [], + 'a' => [ + 'href' => [], + 'title' => [], + ], + 'b' => [], + 'strong' => [], + 'i' => [], + 'em' => [], + ]; + + return [ + '@type' => 'Answer', + 'text' => wp_kses( wp_unslash( $answer ), $allowed_html ), + 'inLanguage' => get_bloginfo( 'language' ), + ]; + } +} diff --git a/includes/schema/faq_schema.php b/includes/schema/faq_schema.php deleted file mode 100644 index 839b362..0000000 --- a/includes/schema/faq_schema.php +++ /dev/null @@ -1,280 +0,0 @@ -context = $context; - } - - /** - * Determines whether or not a piece should be added to the graph. - * - * @return bool Whether or not a piece should be added. - */ - public function is_needed(): bool { - if ( empty( $this->context->blocks['blockparty/faq'] ) ) { - return false; - } - - if ( ! \is_array( $this->context->schema_page_type ) ) { - $this->context->schema_page_type = [ $this->context->schema_page_type ]; - } - $this->context->schema_page_type[] = 'FAQPage'; - $this->context->main_entity_of_page = $this->generate_ids(); - - return true; - } - - /** - * Generate the IDs so we can link to them in the main entity. - * - * @return array - */ - private function generate_ids(): array { - $ids = []; - foreach ( $this->context->blocks['blockparty/faq'] as $block ) { - if ( empty( $block['innerBlocks'] ) ) { - continue; - } - - // Process faq-item blocks - foreach ( $block['innerBlocks'] as $item_block ) { - if ( 'blockparty/faq-item' !== $item_block['blockName'] ) { - continue; - } - - if ( empty( $item_block['innerBlocks'] ) ) { - continue; - } - - // Find question block in faq-item - $question_block = null; - foreach ( $item_block['innerBlocks'] as $inner_block ) { - if ( 'blockparty/faq-question' === $inner_block['blockName'] ) { - $question_block = $inner_block; - break; - } - } - - if ( ! $question_block ) { - continue; - } - - // Get question text from attributes or InnerBlocks - $question_text = $question_block['attrs']['question'] ?? ''; - - // If question is empty, try to get it from InnerBlocks (when isAccordion is false) - if ( empty( $question_text ) && ! empty( $question_block['innerBlocks'] ) ) { - $question_text = $this->get_question_content( $question_block ); - } - - $question_id = ! empty( $question_text ) - ? md5( $question_text ) - : 'faq-' . uniqid(); - $ids[] = [ '@id' => $this->context->canonical . '#' . \esc_attr( $question_id ) ]; - } - } - - return $ids; - } - - /** - * Render a list of questions, referencing them by ID. - * - * @return array Our Schema graph. - */ - public function generate(): array { - $graph = []; - - foreach ( $this->context->blocks['blockparty/faq'] as $block ) { - if ( empty( $block['innerBlocks'] ) ) { - continue; - } - - $position = 1; - - // Process faq-item blocks - foreach ( $block['innerBlocks'] as $item_block ) { - if ( 'blockparty/faq-item' !== $item_block['blockName'] ) { - continue; - } - - if ( empty( $item_block['innerBlocks'] ) ) { - continue; - } - - // Find question and answer blocks in faq-item - $question_block = null; - $answer_block = null; - - foreach ( $item_block['innerBlocks'] as $inner_block ) { - if ( 'blockparty/faq-question' === $inner_block['blockName'] ) { - $question_block = $inner_block; - } elseif ( 'blockparty/faq-answer' === $inner_block['blockName'] ) { - $answer_block = $inner_block; - } - } - - // Skip if no question block - if ( ! $question_block ) { - continue; - } - - // Get question text from attributes or InnerBlocks - $question_text = $question_block['attrs']['question'] ?? ''; - - // If question is empty, try to get it from InnerBlocks (when isAccordion is false) - if ( empty( $question_text ) && ! empty( $question_block['innerBlocks'] ) ) { - $question_text = $this->get_question_content( $question_block ); - } - - if ( empty( $question_text ) ) { - continue; - } - - // Get answer content from InnerBlocks - $answer_content = ''; - if ( $answer_block ) { - $answer_content = $this->get_answer_content( $answer_block ); - } - - if ( empty( $answer_content ) ) { - continue; - } - - $question_id = md5( $question_text ); - $graph[] = $this->generate_question_block( - $question_text, - $answer_content, - $question_id, - $position - ); - ++$position; - } - } - - return $graph; - } - - /** - * Get question content from InnerBlocks. - * - * @param array $question_block The question block with InnerBlocks. - * @return string The question content as HTML. - */ - protected function get_question_content( array $question_block ): string { - if ( empty( $question_block['innerBlocks'] ) ) { - return ''; - } - - $content = ''; - foreach ( $question_block['innerBlocks'] as $inner_block ) { - $content .= render_block( $inner_block ); - } - - return wp_strip_all_tags( $content ); - } - - /** - * Get answer content from InnerBlocks. - * - * @param array $answer_block The answer block with InnerBlocks. - * @return string The answer content as HTML. - */ - protected function get_answer_content( array $answer_block ): string { - if ( empty( $answer_block['innerBlocks'] ) ) { - return ''; - } - - $content = ''; - foreach ( $answer_block['innerBlocks'] as $inner_block ) { - $content .= render_block( $inner_block ); - } - - return $content; - } - - /** - * Generate a Question piece. - * - * @param string $question_text The question text. - * @param string $answer_content The answer content as HTML. - * @param string $question_id The question ID. - * @param int $position The position of the question. - * - * @return array Schema.org Question piece. - */ - protected function generate_question_block( string $question_text, string $answer_content, string $question_id, int $position ): array { - $url = $this->context->canonical . '#' . \esc_attr( $question_id ); - - $data = [ - '@type' => 'Question', - '@id' => $url, - 'position' => $position, - 'url' => $url, - 'name' => esc_html( wp_strip_all_tags( $question_text ) ), - 'answerCount' => 1, - 'acceptedAnswer' => $this->add_accepted_answer_property( $answer_content ), - ]; - - $data['inLanguage'] = get_bloginfo( 'language' ); - - return $data; - } - - /** - * Adds the Questions `acceptedAnswer` property. - * - * @param string $answer The question to add the acceptedAnswer to. - * - * @return array Schema.org Question piece. - */ - protected function add_accepted_answer_property( string $answer ): array { - // Allowed HTML elements and attributes for Schema.org FAQPage acceptedAnswer text property. - // Supports: headings, paragraphs, lists. - $allowed_html = [ - 'h1' => [], - 'h2' => [], - 'h3' => [], - 'h4' => [], - 'h5' => [], - 'h6' => [], - 'p' => [], - 'br' => [], - 'ol' => [], - 'ul' => [], - 'li' => [], - 'a' => [ - 'href' => [], - 'title' => [], - ], - 'b' => [], - 'strong' => [], - 'i' => [], - 'em' => [], - ]; - - $data = [ - '@type' => 'Answer', - 'text' => wp_kses( wp_unslash( $answer ), $allowed_html ), - ]; - - $data['inLanguage'] = get_bloginfo( 'language' ); - - return $data; - } -} diff --git a/includes/services/Seo_Service_Interface.php b/includes/services/Seo_Service_Interface.php new file mode 100644 index 0000000..5ecc929 --- /dev/null +++ b/includes/services/Seo_Service_Interface.php @@ -0,0 +1,30 @@ +> + */ + private const SERVICE_CLASSES = [ + Yoast_Seo_Service::class, + Seopress_Seo_Service::class, + ]; + + /** + * Resolve the active SEO service. + * + * @return Seo_Service_Interface|null + */ + public static function resolve(): ?Seo_Service_Interface { + /** + * Filter the list of SEO service classes used to resolve the active integration. + * + * @param array> $service_classes Service classes in priority order. + */ + $service_classes = apply_filters( + 'blockparty_faq_seo_service_classes', + self::SERVICE_CLASSES + ); + + foreach ( $service_classes as $service_class ) { + if ( ! is_subclass_of( $service_class, Seo_Service_Interface::class ) ) { + continue; + } + + $service = new $service_class(); + + if ( ! $service->is_active() ) { + continue; + } + + /** + * Filter the resolved SEO service instance. + * + * @param Seo_Service_Interface $service Resolved service. + * @param string $service_class Service class name. + */ + return apply_filters( 'blockparty_faq_active_seo_service', $service, $service_class ); + } + + return null; + } + + /** + * Register hooks for the active SEO service, if any. + * + * @return Seo_Service_Interface|null + */ + public static function register_active_service(): ?Seo_Service_Interface { + $service = self::resolve(); + + if ( null === $service ) { + return null; + } + + $service->register(); + + return $service; + } +} diff --git a/includes/services/Seopress_Seo_Service.php b/includes/services/Seopress_Seo_Service.php new file mode 100644 index 0000000..0c054b4 --- /dev/null +++ b/includes/services/Seopress_Seo_Service.php @@ -0,0 +1,161 @@ + $json FAQ schema array. + * + * @return array + */ + public function filter_auto_faq_json( array $json ): array { + $merged = $this->merge_block_faq_into_schema( $json ); + + if ( null !== $merged ) { + $this->schema_injected = true; + } + + return $merged ?? $json; + } + + /** + * Inject block FAQ data into SEOPress manual FAQ schema. + * + * @param array $jsonld FAQ schema array. + * @param array $context SEOPress schema context. + * + * @return array + */ + public function filter_manual_faq_json( array $jsonld, array $context ): array { + unset( $context ); + + $merged = $this->merge_block_faq_into_schema( $jsonld ); + + if ( null !== $merged ) { + $this->schema_injected = true; + } + + return $merged ?? $jsonld; + } + + /** + * Output FAQ schema on singular views when SEOPress filters did not run. + * + * @return void + */ + public function maybe_output_faq_schema(): void { + if ( $this->schema_injected || ! is_singular() ) { + return; + } + + $generator = $this->create_generator_from_current_post(); + + if ( null === $generator ) { + return; + } + + $schema = $generator->generate_faq_page_schema(); + + if ( null === $schema ) { + return; + } + + $this->schema_injected = true; + + printf( + '' . "\n", + wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ) + ); + } + + /** + * Merge block FAQ questions into an existing FAQ schema array. + * + * @param array $json Existing FAQ schema. + * + * @return array|null + */ + private function merge_block_faq_into_schema( array $json ): ?array { + $generator = $this->create_generator_from_current_post(); + + if ( null === $generator ) { + return null; + } + + $questions = $generator->generate_questions_for_nested_schema(); + + if ( empty( $questions ) ) { + return null; + } + + $json['@type'] = 'FAQPage'; + $json['mainEntity'] = $questions; + $json['@context'] = $json['@context'] ?? 'https://schema.org'; + $json['inLanguage'] = $json['inLanguage'] ?? get_bloginfo( 'language' ); + + return $json; + } + + /** + * Create a schema generator from the current singular post. + * + * @return FAQ_Schema_Generator|null + */ + private function create_generator_from_current_post(): ?FAQ_Schema_Generator { + if ( ! is_singular() ) { + return null; + } + + $faq_blocks = FAQ_Schema_Generator::get_faq_blocks_from_post(); + + if ( empty( $faq_blocks ) ) { + return null; + } + + $canonical = get_permalink( get_queried_object_id() ); + + if ( ! is_string( $canonical ) || '' === $canonical ) { + return null; + } + + return new FAQ_Schema_Generator( $canonical, $faq_blocks ); + } +} diff --git a/includes/services/Yoast_Seo_Service.php b/includes/services/Yoast_Seo_Service.php new file mode 100644 index 0000000..7127350 --- /dev/null +++ b/includes/services/Yoast_Seo_Service.php @@ -0,0 +1,46 @@ + $pieces Graph pieces to output. + * @param \WPSEO_Schema_Context $context Yoast schema context. + * + * @return array + */ + public function add_graph_pieces( array $pieces, \WPSEO_Schema_Context $context ): array { + $pieces[] = new FAQ_Schema( $context ); + + return $pieces; + } +} diff --git a/package.json b/package.json index f44064b..bf72770 100644 --- a/package.json +++ b/package.json @@ -14,9 +14,8 @@ "packages-update": "wp-scripts packages-update", "make-pot": "wp i18n make-pot . languages/blockparty-faq.pot --exclude=\"src\" --domain=blockparty-faq", "make-json": "wp i18n make-json languages/blockparty-faq-fr_FR.po languages/ --no-purge", - "env:start": "wp-env start --config=./wp-env.json", - "env:stop": "wp-env stop --config=./wp-env.json", - "env:setup": "wp-env run cli wp plugin install wordpress-seo --activate --allow-root" + "env:start": "wp-env start", + "env:stop": "wp-env stop" }, "dependencies": { "@beapi/be-a11y": "^1.7.2", From 11a4c9b0bf6441fc3f44c458282fdc47694a3ac0 Mon Sep 17 00:00:00 2001 From: Milan Ricoul Date: Fri, 26 Jun 2026 15:05:24 +0200 Subject: [PATCH 06/18] Add Rank Math SEO integration for FAQ structured data. Register a dedicated service using rank_math/json_ld and include the plugin in the local wp-env setup via Composer. --- .wp-env.json | 1 + README.md | 4 +- blockparty-faq.php | 1 + composer.json | 1 + includes/services/Rank_Math_Seo_Service.php | 88 +++++++++++++++++++++ includes/services/Seo_Service_Resolver.php | 1 + 6 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 includes/services/Rank_Math_Seo_Service.php diff --git a/.wp-env.json b/.wp-env.json index 5691edd..4523018 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,6 +1,7 @@ { "plugins": [ ".", + ".wp-env/plugins/seo-by-rank-math", ".wp-env/plugins/wordpress-seo", ".wp-env/plugins/wp-seopress" ] diff --git a/README.md b/README.md index f7bdfbc..aec715d 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ A Gutenberg block for SEO friendly FAQ in an accessible accordion. npm run env:start ``` - Yoast SEO and SEOPress are mounted and activated automatically via `.wp-env.json`. + Yoast SEO, Rank Math, and SEOPress are mounted automatically via `.wp-env.json`. ### Available Scripts @@ -47,7 +47,7 @@ A Gutenberg block for SEO friendly FAQ in an accessible accordion. ### Note -FAQ structured data (JSON-LD) requires Yoast SEO or SEOPress. Both plugins are available in the local wp-env environment; deactivate one in the WordPress admin if you need to test a single integration. SEO plugin files are not versioned in the repository (installed via Composer into `.wp-env/plugins/`). +FAQ structured data (JSON-LD) requires Yoast SEO, Rank Math, or SEOPress. All three plugins are available in the local wp-env environment; keep only one active in the WordPress admin when testing a specific integration. SEO plugin files are not versioned in the repository (installed via Composer into `.wp-env/plugins/`). ## Changelog diff --git a/blockparty-faq.php b/blockparty-faq.php index 93ede38..edb80c7 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -51,6 +51,7 @@ require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/FAQ_Schema.php'; require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Interface.php'; require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Yoast_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Rank_Math_Seo_Service.php'; require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seopress_Seo_Service.php'; require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Resolver.php'; diff --git a/composer.json b/composer.json index 6236caf..adbe679 100644 --- a/composer.json +++ b/composer.json @@ -49,6 +49,7 @@ "roave/security-advisories": "dev-latest", "roots/wordpress-no-content": "^6.0", "wp-coding-standards/wpcs": "^3.3", + "wp-plugin/seo-by-rank-math": "1.0.272", "wp-plugin/wordpress-seo": "27.9", "wp-plugin/wp-seopress": "10.0.1" }, diff --git a/includes/services/Rank_Math_Seo_Service.php b/includes/services/Rank_Math_Seo_Service.php new file mode 100644 index 0000000..4127bd3 --- /dev/null +++ b/includes/services/Rank_Math_Seo_Service.php @@ -0,0 +1,88 @@ + $data Rank Math schema data. + * @param mixed $jsonld Rank Math JsonLD instance. + * + * @return array + */ + public function filter_json_ld( array $data, $jsonld ): array { + unset( $jsonld ); + + $generator = $this->create_generator_from_current_post(); + + if ( null === $generator ) { + return $data; + } + + $questions = $generator->generate_questions_for_nested_schema(); + + if ( empty( $questions ) ) { + return $data; + } + + $data['faqs'] = [ + '@type' => 'FAQPage', + 'mainEntity' => $questions, + ]; + + return $data; + } + + /** + * Create a schema generator from the current singular post. + * + * @return FAQ_Schema_Generator|null + */ + private function create_generator_from_current_post(): ?FAQ_Schema_Generator { + if ( ! is_singular() ) { + return null; + } + + $faq_blocks = FAQ_Schema_Generator::get_faq_blocks_from_post(); + + if ( empty( $faq_blocks ) ) { + return null; + } + + $canonical = get_permalink( get_queried_object_id() ); + + if ( ! is_string( $canonical ) || '' === $canonical ) { + return null; + } + + return new FAQ_Schema_Generator( $canonical, $faq_blocks ); + } +} diff --git a/includes/services/Seo_Service_Resolver.php b/includes/services/Seo_Service_Resolver.php index 42d1fd3..0eef7a4 100644 --- a/includes/services/Seo_Service_Resolver.php +++ b/includes/services/Seo_Service_Resolver.php @@ -14,6 +14,7 @@ class Seo_Service_Resolver { */ private const SERVICE_CLASSES = [ Yoast_Seo_Service::class, + Rank_Math_Seo_Service::class, Seopress_Seo_Service::class, ]; From 2c2660a07813d9892c6c76c09cbd6239fc3f544d Mon Sep 17 00:00:00 2001 From: Milan Ricoul Date: Fri, 26 Jun 2026 15:16:53 +0200 Subject: [PATCH 07/18] Refactor FAQ block markup to align with blockparty-accordion. Replace faq__* classes with wp-block-blockparty-faq-* structure, add CSS custom properties, and register deprecated handlers so existing 2.0.x content keeps validating and rendering. --- README.md | 6 ++ blockparty-faq.php | 8 +-- package.json | 2 +- src/faq-answer/block.json | 2 +- src/faq-answer/deprecated.js | 42 ++++++++++++ src/faq-answer/edit.js | 32 ++++----- src/faq-answer/index.js | 6 ++ src/faq-answer/save.js | 17 +++-- src/faq-item/block.json | 2 +- src/faq-item/deprecated.js | 29 ++++++++ src/faq-item/edit.js | 27 +++----- src/faq-item/index.js | 6 ++ src/faq-item/save.js | 4 +- src/faq-question/block.json | 2 +- src/faq-question/deprecated.js | 53 +++++++++++++++ src/faq-question/edit.js | 72 +++++++++----------- src/faq-question/index.js | 6 ++ src/faq-question/save.js | 32 +++++---- src/faq/block.json | 2 +- src/faq/deprecated.js | 32 ++++++++- src/faq/edit.js | 18 ++--- src/faq/editor.scss | 42 +++++++----- src/faq/save.js | 11 +-- src/faq/script.js | 9 ++- src/faq/style.scss | 118 ++++++++++++++++++++++++++++++--- 25 files changed, 425 insertions(+), 155 deletions(-) create mode 100644 src/faq-answer/deprecated.js create mode 100644 src/faq-item/deprecated.js create mode 100644 src/faq-question/deprecated.js diff --git a/README.md b/README.md index 82b886d..8360985 100644 --- a/README.md +++ b/README.md @@ -90,3 +90,9 @@ Yoast SEO is required for the FAQ schema (JSON-LD) generation. It is installed a - Add spacing support for answers - Add font size support for the question - Strip HTML tags from the question in structured data + +### 2.0.4 - 2026-06-26 + +- Refactor block markup to align with `blockparty-accordion` structure (`wp-block-blockparty-faq-*` classes) +- Add CSS custom properties for styling (`--wp--blockparty--faq--*`) +- Add deprecated handlers for 2.0.x markup retrocompatibility diff --git a/blockparty-faq.php b/blockparty-faq.php index a0c11f4..b0ab6e9 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -4,7 +4,7 @@ * Description: A FAQ block for WordPress Editor that provided structured data based on FAQ schema. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 2.0.3 + * Version: 2.0.4 * Plugin URI: https://beapi.fr * Author: Be API Technical team * Author URI: https://beapi.fr @@ -41,7 +41,7 @@ } // Plugin constants -define( 'BLOCKPARTY_FAQ_VERSION', '2.0.3' ); +define( 'BLOCKPARTY_FAQ_VERSION', '2.0.4' ); // Plugin URL and PATH define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); @@ -83,9 +83,9 @@ function blockparty_faq_init(): void { 'forceExpand' => false, 'hasAnimation' => true, 'openMultiple' => false, - 'panelSelector' => '.faq__panel', + 'panelSelector' => '.wp-block-blockparty-faq-answer', 'prefixId' => 'block-faq', - 'triggerSelector' => '.faq__trigger', + 'triggerSelector' => '.wp-block-blockparty-faq-trigger', ] ), ]; diff --git a/package.json b/package.json index b604620..9b62690 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-faq", - "version": "2.0.3", + "version": "2.0.4", "description": "SEO friendly FAQ module in an accessible accordion", "author": "Be API Technical team", "license": "GPL-2.0-or-later", diff --git a/src/faq-answer/block.json b/src/faq-answer/block.json index bf79231..f9c6faf 100644 --- a/src/faq-answer/block.json +++ b/src/faq-answer/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-answer", - "version": "2.0.3", + "version": "2.0.4", "title": "FAQ Answer", "category": "design", "parent": [ "blockparty/faq-item" ], diff --git a/src/faq-answer/deprecated.js b/src/faq-answer/deprecated.js new file mode 100644 index 0000000..73a69df --- /dev/null +++ b/src/faq-answer/deprecated.js @@ -0,0 +1,42 @@ +/** + * WordPress dependencies + */ +import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; + +/** + * Save function for deprecated 2.0.x markup with faq__panel class. + * + * @param {Object} props Component props. + * @param {Object} props.attributes Block attributes. + * @return {JSX.Element} Saved block markup. + */ +function deprecatedSave( { attributes } ) { + const { isAccordion = true } = attributes; + const blockProps = useBlockProps.save( { + className: 'faq__panel', + } ); + + const divProps = isAccordion + ? { ...blockProps, role: 'region' } + : blockProps; + + return ( +
+ +
+ ); +} + +const deprecated = [ + { + attributes: { + isAccordion: { + type: 'boolean', + default: true, + }, + }, + save: deprecatedSave, + }, +]; + +export default deprecated; diff --git a/src/faq-answer/edit.js b/src/faq-answer/edit.js index e5ae80b..f86ab76 100644 --- a/src/faq-answer/edit.js +++ b/src/faq-answer/edit.js @@ -13,24 +13,24 @@ const ALLOWED_BLOCKS = [ ]; export default function Edit() { - const blockProps = useBlockProps( { - className: 'faq__panel', - } ); + const blockProps = useBlockProps(); return ( -
- +
+
+ +
); } diff --git a/src/faq-answer/index.js b/src/faq-answer/index.js index cb97459..66c6552 100644 --- a/src/faq-answer/index.js +++ b/src/faq-answer/index.js @@ -11,6 +11,7 @@ import './style.scss'; import './editor.scss'; import Edit from './edit'; import save from './save'; +import deprecated from './deprecated'; import metadata from './block.json'; registerBlockType( metadata.name, { @@ -24,5 +25,10 @@ registerBlockType( metadata.name, { * @see ./save.js */ save, + + /** + * @see ./deprecated.js + */ + deprecated, icon: postContent, } ); diff --git a/src/faq-answer/save.js b/src/faq-answer/save.js index 7a5afe0..8cff587 100644 --- a/src/faq-answer/save.js +++ b/src/faq-answer/save.js @@ -1,21 +1,20 @@ /** * WordPress dependencies */ -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; +import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; export default function save( { attributes } ) { const { isAccordion = true } = attributes; - const blockProps = useBlockProps.save( { - className: 'faq__panel', + const blockProps = useBlockProps.save( + isAccordion ? { role: 'region' } : {} + ); + const innerBlocksProps = useInnerBlocksProps.save( { + className: 'wp-block-blockparty-faq-answer__inner', } ); - const divProps = isAccordion - ? { ...blockProps, role: 'region' } - : blockProps; - return ( -
- +
+
); } diff --git a/src/faq-item/block.json b/src/faq-item/block.json index a584901..7a0c25e 100644 --- a/src/faq-item/block.json +++ b/src/faq-item/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-item", - "version": "2.0.3", + "version": "2.0.4", "title": "FAQ Item", "category": "design", "parent": [ "blockparty/faq" ], diff --git a/src/faq-item/deprecated.js b/src/faq-item/deprecated.js new file mode 100644 index 0000000..63f4a2e --- /dev/null +++ b/src/faq-item/deprecated.js @@ -0,0 +1,29 @@ +/** + * WordPress dependencies + */ +import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; + +/** + * Save function for deprecated 2.0.x markup with faq__item class. + * + * @return {JSX.Element} Saved block markup. + */ +function deprecatedSave() { + const blockProps = useBlockProps.save( { + className: 'faq__item', + } ); + + return ( +
+ +
+ ); +} + +const deprecated = [ + { + save: deprecatedSave, + }, +]; + +export default deprecated; diff --git a/src/faq-item/edit.js b/src/faq-item/edit.js index a5d1b94..67ca7da 100644 --- a/src/faq-item/edit.js +++ b/src/faq-item/edit.js @@ -3,8 +3,8 @@ */ import { useBlockProps, + useInnerBlocksProps, BlockControls, - InnerBlocks, } from '@wordpress/block-editor'; import { ToolbarGroup, ToolbarButton } from '@wordpress/components'; import { addCard, trash } from '@wordpress/icons'; @@ -13,8 +13,14 @@ import { createBlock } from '@wordpress/blocks'; import { __ } from '@wordpress/i18n'; export default function Edit( { clientId } ) { - const blockProps = useBlockProps( { - className: 'faq__item', + const blockProps = useBlockProps(); + const innerBlocksProps = useInnerBlocksProps( blockProps, { + allowedBlocks: [ 'blockparty/faq-question', 'blockparty/faq-answer' ], + template: [ + [ 'blockparty/faq-question' ], + [ 'blockparty/faq-answer' ], + ], + templateLock: 'all', } ); const { insertBlock, removeBlock } = useDispatch( 'core/block-editor' ); @@ -26,7 +32,6 @@ export default function Edit( { clientId } ) { const rootClientId = getBlockRootClientId( clientId ); const blockIndex = getBlockIndex( clientId ); - // Get isAccordion from parent block (faq) const parentBlock = rootClientId ? getBlock( rootClientId ) : null; const isAccordion = parentBlock?.attributes?.isAccordion !== undefined @@ -61,18 +66,8 @@ export default function Edit( { clientId } ) { /> -
- +
+
); diff --git a/src/faq-item/index.js b/src/faq-item/index.js index 1d35264..1ebbd4d 100644 --- a/src/faq-item/index.js +++ b/src/faq-item/index.js @@ -11,6 +11,7 @@ import './style.scss'; import './editor.scss'; import Edit from './edit'; import save from './save'; +import deprecated from './deprecated'; import metadata from './block.json'; registerBlockType( metadata.name, { @@ -24,5 +25,10 @@ registerBlockType( metadata.name, { * @see ./save.js */ save, + + /** + * @see ./deprecated.js + */ + deprecated, icon: list, } ); diff --git a/src/faq-item/save.js b/src/faq-item/save.js index a3fd3fc..5314afe 100644 --- a/src/faq-item/save.js +++ b/src/faq-item/save.js @@ -4,9 +4,7 @@ import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; export default function save() { - const blockProps = useBlockProps.save( { - className: 'faq__item', - } ); + const blockProps = useBlockProps.save(); return (
diff --git a/src/faq-question/block.json b/src/faq-question/block.json index 907f8a1..5babff4 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-question", - "version": "2.0.3", + "version": "2.0.4", "title": "FAQ Question", "category": "design", "parent": [ "blockparty/faq-item" ], diff --git a/src/faq-question/deprecated.js b/src/faq-question/deprecated.js new file mode 100644 index 0000000..935b0fd --- /dev/null +++ b/src/faq-question/deprecated.js @@ -0,0 +1,53 @@ +/** + * WordPress dependencies + */ +import { useBlockProps, RichText, InnerBlocks } from '@wordpress/block-editor'; + +/** + * Save function for deprecated 2.0.x markup with faq__title and faq__trigger classes. + * + * @param {Object} props Component props. + * @param {Object} props.attributes Block attributes. + * @return {JSX.Element} Saved block markup. + */ +function deprecatedSave( { attributes } ) { + const { question, isAccordion = true } = attributes; + const blockProps = useBlockProps.save( { + className: 'faq__title', + } ); + + const TriggerTag = isAccordion ? 'button' : 'span'; + const triggerProps = isAccordion + ? { className: 'faq__trigger', 'aria-expanded': 'false' } + : { className: 'faq__trigger' }; + + return ( +

+ + { isAccordion ? ( + + ) : ( + + ) } + +

+ ); +} + +const deprecated = [ + { + attributes: { + question: { + type: 'string', + default: '', + }, + isAccordion: { + type: 'boolean', + default: true, + }, + }, + save: deprecatedSave, + }, +]; + +export default deprecated; diff --git a/src/faq-question/edit.js b/src/faq-question/edit.js index 2b13fff..056b1eb 100644 --- a/src/faq-question/edit.js +++ b/src/faq-question/edit.js @@ -15,9 +15,7 @@ const ALLOWED_BLOCKS_SIMPLE = [ 'core/heading', 'core/paragraph' ]; export default function Edit( { attributes, setAttributes, clientId } ) { const { question, isAccordion = true } = attributes; - const blockProps = useBlockProps( { - className: 'faq__title', - } ); + const blockProps = useBlockProps(); const innerBlocks = useSelect( ( select ) => select( 'core/block-editor' ).getBlocks( clientId ), @@ -26,21 +24,14 @@ export default function Edit( { attributes, setAttributes, clientId } ) { const { replaceInnerBlocks } = useDispatch( 'core/block-editor' ); - // When isAccordion changes from true to false and innerBlocks are empty, - // create a core/heading block with the question attribute value - // When isAccordion changes from false to true, remove innerBlocks and - // transfer their content to the question attribute useEffect( () => { if ( ! isAccordion && innerBlocks.length === 0 && question ) { - // Switch from accordion to non-accordion: create heading block const headingBlock = createBlock( 'core/heading', { level: 3, content: question, } ); replaceInnerBlocks( clientId, [ headingBlock ] ); } else if ( isAccordion && innerBlocks.length > 0 ) { - // Switch from non-accordion to accordion: extract content from innerBlocks - // Get the text content from the first block (usually a heading or paragraph) const firstBlock = innerBlocks[ 0 ]; let extractedContent = ''; @@ -50,12 +41,10 @@ export default function Edit( { attributes, setAttributes, clientId } ) { extractedContent = firstBlock.attributes?.content || ''; } - // Update the question attribute with the extracted content if ( extractedContent && extractedContent !== question ) { setAttributes( { question: extractedContent } ); } - // Remove innerBlocks replaceInnerBlocks( clientId, [] ); } }, [ @@ -69,36 +58,35 @@ export default function Edit( { attributes, setAttributes, clientId } ) { return (

-
- { isAccordion ? ( - - setAttributes( { question: content } ) - } - placeholder={ __( 'Question…?', 'blockparty-faq' ) } - allowedFormats={ [] } - /> - ) : ( - - ) } -
+ { isAccordion ? ( + + setAttributes( { question: content } ) + } + placeholder={ __( 'Question…?', 'blockparty-faq' ) } + allowedFormats={ [] } + /> + ) : ( + + ) }

); } diff --git a/src/faq-question/index.js b/src/faq-question/index.js index 4ef60a3..c5bb7e1 100644 --- a/src/faq-question/index.js +++ b/src/faq-question/index.js @@ -11,6 +11,7 @@ import './style.scss'; import './editor.scss'; import Edit from './edit'; import save from './save'; +import deprecated from './deprecated'; import metadata from './block.json'; registerBlockType( metadata.name, { @@ -24,5 +25,10 @@ registerBlockType( metadata.name, { * @see ./save.js */ save, + + /** + * @see ./deprecated.js + */ + deprecated, icon: listItem, } ); diff --git a/src/faq-question/save.js b/src/faq-question/save.js index 4ae0e3b..4c1e590 100644 --- a/src/faq-question/save.js +++ b/src/faq-question/save.js @@ -5,24 +5,28 @@ import { useBlockProps, RichText, InnerBlocks } from '@wordpress/block-editor'; export default function save( { attributes } ) { const { question, isAccordion = true } = attributes; - const blockProps = useBlockProps.save( { - className: 'faq__title', - } ); + const blockProps = useBlockProps.save(); - const TriggerTag = isAccordion ? 'button' : 'span'; - const triggerProps = isAccordion - ? { className: 'faq__trigger', 'aria-expanded': 'false' } - : { className: 'faq__trigger' }; + if ( ! isAccordion ) { + return ( +

+ +

+ ); + } return (

- - { isAccordion ? ( - - ) : ( - - ) } - +

); } diff --git a/src/faq/block.json b/src/faq/block.json index 372550f..cb78053 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq", - "version": "2.0.3", + "version": "2.0.4", "title": "FAQ", "category": "design", "description": "A FAQ block for WordPress Editor that provided structured data based on FAQ schema.", diff --git a/src/faq/deprecated.js b/src/faq/deprecated.js index 89f2059..146cc5e 100644 --- a/src/faq/deprecated.js +++ b/src/faq/deprecated.js @@ -2,7 +2,7 @@ * WordPress dependencies */ import { createBlock, parse } from '@wordpress/blocks'; -import { useBlockProps, RichText } from '@wordpress/block-editor'; +import { useBlockProps, RichText, InnerBlocks } from '@wordpress/block-editor'; /** * Migration script to convert old FAQ format to new InnerBlocks format. @@ -184,6 +184,23 @@ function deprecatedSave( { attributes } ) { ); } +/** + * Save function for deprecated 2.0.x nested InnerBlocks format with faq__accordion wrapper. + * + * @return {JSX.Element} Saved block markup. + */ +function deprecatedNestedSave() { + const blockProps = useBlockProps.save(); + + return ( +
+
+ +
+
+ ); +} + /** * Deprecated block configuration for migration from old format. * @@ -191,6 +208,19 @@ function deprecatedSave( { attributes } ) { * New format: InnerBlocks with faq-item blocks */ const deprecated = [ + { + attributes: { + isAccordion: { + type: 'boolean', + default: true, + }, + }, + supports: { + html: false, + innerBlocks: true, + }, + save: deprecatedNestedSave, + }, { attributes: { questions: { diff --git a/src/faq/edit.js b/src/faq/edit.js index f8ec1ba..2ff1b4e 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -3,8 +3,8 @@ */ import { BlockControls, - InnerBlocks, useBlockProps, + useInnerBlocksProps, InspectorControls, } from '@wordpress/block-editor'; import { @@ -22,6 +22,11 @@ import { useEffect } from '@wordpress/element'; export default function Edit( { clientId, attributes, setAttributes } ) { const { isAccordion = true } = attributes; const blockProps = useBlockProps(); + const innerBlocksProps = useInnerBlocksProps( blockProps, { + allowedBlocks: [ 'blockparty/faq-item' ], + template: [ [ 'blockparty/faq-item' ] ], + templateLock: false, + } ); const { insertBlock, updateBlockAttributes } = useDispatch( 'core/block-editor' ); @@ -34,7 +39,6 @@ export default function Edit( { clientId, attributes, setAttributes } ) { useEffect( () => { const innerBlocks = getBlocks( clientId ); innerBlocks.forEach( ( block ) => { - // Update faq-item blocks if ( 'blockparty/faq-item' === block.name ) { const itemInnerBlocks = getBlocks( block.clientId ); itemInnerBlocks.forEach( ( itemBlock ) => { @@ -87,15 +91,7 @@ export default function Edit( { clientId, attributes, setAttributes } ) { /> -
-
- -
-
+
); } diff --git a/src/faq/editor.scss b/src/faq/editor.scss index a3367df..edb80b3 100644 --- a/src/faq/editor.scss +++ b/src/faq/editor.scss @@ -1,24 +1,34 @@ -.wp-block-blockparty-faq-block { +/* editor */ +.wp-block-blockparty-faq { - .faq-list { + &-item, + &-answer, + .wp-block { + max-width: 100% !important; + } - &__button { - float: right; - opacity: 0; - z-index: 999; - position: relative; + &-item, + &-answer { + margin-top: 0; + margin-bottom: 0; + } - &:hover { - color: #007cba; - } - } + &-answer { + display: none; + } - &__item:hover .faq-list__button { /* stylelint-disable-line */ - opacity: 1; - } + &-item.has-child-selected .wp-block-blockparty-faq-answer { + display: block; + } + + &-item.has-child-selected .wp-block-blockparty-faq-trigger::after { + transform: translateY(-50%) rotate(-135deg); + } + + &-question { - &__add-item svg { - margin-right: 0.25em; + .rich-text { + white-space: nowrap; } } } diff --git a/src/faq/save.js b/src/faq/save.js index 718f494..9b56627 100644 --- a/src/faq/save.js +++ b/src/faq/save.js @@ -1,16 +1,11 @@ /** * WordPress dependencies */ -import { useBlockProps, InnerBlocks } from '@wordpress/block-editor'; +import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor'; export default function save() { const blockProps = useBlockProps.save(); + const innerBlocksProps = useInnerBlocksProps.save( blockProps ); - return ( -
-
- -
-
- ); + return
; } diff --git a/src/faq/script.js b/src/faq/script.js index 9990707..9e2a33f 100644 --- a/src/faq/script.js +++ b/src/faq/script.js @@ -3,10 +3,15 @@ import { Accordion } from '@beapi/be-a11y'; // eslint-disable-next-line no-undef const accordionConfig = beapiFaqBlock.accordionConfig; -// Initialize beapi-accordion window.addEventListener( 'load', function () { Accordion.init( - '.wp-block-blockparty-faq:has(button.faq__trigger)', + '.wp-block-blockparty-faq:has(button.wp-block-blockparty-faq-trigger)', accordionConfig ); + + Accordion.init( '.wp-block-blockparty-faq:has(button.faq__trigger)', { + ...accordionConfig, + panelSelector: '.faq__panel', + triggerSelector: '.faq__trigger', + } ); } ); diff --git a/src/faq/style.scss b/src/faq/style.scss index 6cec69c..1c13bb9 100644 --- a/src/faq/style.scss +++ b/src/faq/style.scss @@ -1,13 +1,115 @@ -.wp-block-blockparty-faq-block { +/* style */ +.wp-block-blockparty-faq { + --wp--blockparty--faq--border: 1px solid #000; + --wp--blockparty--faq--font-size: var(--wp--preset--font-size--h-3); + --wp--blockparty--faq--font-weight: 400; + --wp--blockparty--faq--padding: 1rem 0; + --wp--blockparty--faq--padding-with-background: 1rem; + --wp--blockparty--faq--icon-size: 24px; - .faq { + &-question { + position: relative; + display: flex; + align-items: center; + padding: var(--wp--blockparty--faq--padding) !important; + border-bottom: var(--wp--blockparty--faq--border); + } + + &-item:where(:has([aria-expanded="false"])) &-answer { + display: none; + } + + &-answer__inner { + padding: var(--wp--blockparty--faq--padding); + } + + &-trigger { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: 0; + font-size: var(--wp--blockparty--faq--font-size); + font-weight: var(--wp--blockparty--faq--font-weight); + text-align: left; + background-color: transparent; + border: 0; + border-radius: 0; + box-shadow: none; + appearance: none; + + &::after { + position: absolute; + top: 50%; + right: 0.5rem; + width: 0.5rem; + height: 0.5rem; + pointer-events: none; + content: ""; + border: solid currentcolor; + border-width: 0 2px 2px 0; + transform: translateY(-60%) rotate(45deg); + } + + &[aria-expanded="true"]::after { + transform: translateY(-50%) rotate(-135deg); + } + } + + &-question.has-background, + .has-background &-question, + .has-background &-answer__inner { + padding: var(--wp--blockparty--faq--padding-with-background) !important; + } + + // Legacy markup (2.0.x) + .faq__title { + position: relative; + display: flex; + align-items: center; + padding: var(--wp--blockparty--faq--padding) !important; + border-bottom: var(--wp--blockparty--faq--border); + } + + .faq__item:where(:has([aria-expanded="false"])) .faq__panel { + display: none; + } + + .faq__panel { + padding: var(--wp--blockparty--faq--padding); + } + + .faq__trigger { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: 0; + font-size: var(--wp--blockparty--faq--font-size); + font-weight: var(--wp--blockparty--faq--font-weight); + text-align: left; + background-color: transparent; + border: 0; + border-radius: 0; + box-shadow: none; + appearance: none; + cursor: pointer; + + &::after { + position: absolute; + top: 50%; + right: 0.5rem; + width: 0.5rem; + height: 0.5rem; + pointer-events: none; + content: ""; + border: solid currentcolor; + border-width: 0 2px 2px 0; + transform: translateY(-60%) rotate(45deg); + } - &__trigger { - appearance: none; - background: transparent; - border: 0; - cursor: pointer; - width: 100%; + &[aria-expanded="true"]::after { + transform: translateY(-50%) rotate(-135deg); } } } From dd88ce37e11b8bc148b36481d89b817f9cf8a303 Mon Sep 17 00:00:00 2001 From: Milan Ricoul Date: Fri, 26 Jun 2026 15:20:45 +0200 Subject: [PATCH 08/18] =?UTF-8?q?Add=20configurable=20FAQ=20question=20hea?= =?UTF-8?q?ding=20level=20(h2=E2=80=93h6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mirror blockparty-accordion behavior: parent-level control synced to child questions, shown only when accordion mode is enabled. --- src/faq-item/edit.js | 6 +- src/faq-question/block.json | 6 ++ src/faq-question/edit.js | 52 +++++++++++------ src/faq-question/save.js | 7 ++- src/faq/block.json | 8 +++ src/faq/edit.js | 109 ++++++++++++++++++++++++++++++++++-- 6 files changed, 162 insertions(+), 26 deletions(-) diff --git a/src/faq-item/edit.js b/src/faq-item/edit.js index 67ca7da..0099fee 100644 --- a/src/faq-item/edit.js +++ b/src/faq-item/edit.js @@ -37,10 +37,14 @@ export default function Edit( { clientId } ) { parentBlock?.attributes?.isAccordion !== undefined ? parentBlock.attributes.isAccordion : true; + const headingLevel = parentBlock?.attributes?.headingLevel ?? 3; const onAddItem = () => { const newItem = createBlock( 'blockparty/faq-item', {}, [ - createBlock( 'blockparty/faq-question', { isAccordion } ), + createBlock( 'blockparty/faq-question', { + isAccordion, + headingLevel, + } ), createBlock( 'blockparty/faq-answer', { isAccordion } ), ] ); insertBlock( newItem, blockIndex + 1, rootClientId ); diff --git a/src/faq-question/block.json b/src/faq-question/block.json index 5babff4..d214f82 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -7,6 +7,7 @@ "category": "design", "parent": [ "blockparty/faq-item" ], "description": "Content of the FAQ question.", + "usesContext": [ "blockparty/headingLevel" ], "supports": { "html": false, "inserter": false, @@ -23,6 +24,11 @@ "isAccordion": { "type": "boolean", "default": true + }, + "headingLevel": { + "type": "number", + "default": 3, + "enum": [ 2, 3, 4, 5, 6 ] } }, "textdomain": "blockparty-faq", diff --git a/src/faq-question/edit.js b/src/faq-question/edit.js index 056b1eb..024725b 100644 --- a/src/faq-question/edit.js +++ b/src/faq-question/edit.js @@ -13,8 +13,20 @@ import { __ } from '@wordpress/i18n'; const ALLOWED_BLOCKS_SIMPLE = [ 'core/heading', 'core/paragraph' ]; -export default function Edit( { attributes, setAttributes, clientId } ) { - const { question, isAccordion = true } = attributes; +export default function Edit( { + attributes, + setAttributes, + clientId, + context = {}, +} ) { + const { + question, + isAccordion = true, + headingLevel: savedHeadingLevel, + } = attributes; + const headingLevel = + context[ 'blockparty/headingLevel' ] ?? savedHeadingLevel ?? 3; + const HeadingTag = `h${ headingLevel }`; const blockProps = useBlockProps(); const innerBlocks = useSelect( @@ -56,20 +68,9 @@ export default function Edit( { attributes, setAttributes, clientId } ) { setAttributes, ] ); - return ( -

- { isAccordion ? ( - - setAttributes( { question: content } ) - } - placeholder={ __( 'Question…?', 'blockparty-faq' ) } - allowedFormats={ [] } - /> - ) : ( + if ( ! isAccordion ) { + return ( +

- ) } -

+

+ ); + } + + return ( + + + setAttributes( { question: content } ) + } + placeholder={ __( 'Question…?', 'blockparty-faq' ) } + allowedFormats={ [] } + /> + ); } diff --git a/src/faq-question/save.js b/src/faq-question/save.js index 4c1e590..22276db 100644 --- a/src/faq-question/save.js +++ b/src/faq-question/save.js @@ -4,8 +4,9 @@ import { useBlockProps, RichText, InnerBlocks } from '@wordpress/block-editor'; export default function save( { attributes } ) { - const { question, isAccordion = true } = attributes; + const { question, isAccordion = true, headingLevel = 3 } = attributes; const blockProps = useBlockProps.save(); + const HeadingTag = `h${ headingLevel }`; if ( ! isAccordion ) { return ( @@ -16,7 +17,7 @@ export default function save( { attributes } ) { } return ( -

+ -

+ ); } diff --git a/src/faq/block.json b/src/faq/block.json index cb78053..b016aae 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -14,8 +14,16 @@ "isAccordion": { "type": "boolean", "default": true + }, + "headingLevel": { + "type": "number", + "default": 3, + "enum": [ 2, 3, 4, 5, 6 ] } }, + "providesContext": { + "blockparty/headingLevel": "headingLevel" + }, "example": { "attributes": { "isAccordion": true diff --git a/src/faq/edit.js b/src/faq/edit.js index 2ff1b4e..36cb8e7 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -6,21 +6,81 @@ import { useBlockProps, useInnerBlocksProps, InspectorControls, + useBlockEditContext, + store as blockEditorStore, } from '@wordpress/block-editor'; import { ToolbarGroup, ToolbarButton, PanelBody, ToggleControl, + // eslint-disable-next-line @wordpress/no-unsafe-wp-apis -- ToggleGroupControl is not yet a stable export in @wordpress/components 27. + __experimentalToggleGroupControl as ToggleGroupControl, + // eslint-disable-next-line @wordpress/no-unsafe-wp-apis + __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon, } from '@wordpress/components'; -import { addCard } from '@wordpress/icons'; +import { + addCard, + headingLevel2, + headingLevel3, + headingLevel4, + headingLevel5, + headingLevel6, +} from '@wordpress/icons'; import { useDispatch, useSelect } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; -import { __ } from '@wordpress/i18n'; +import { __, sprintf } from '@wordpress/i18n'; import { useEffect } from '@wordpress/element'; +const QUESTION_BLOCK = 'blockparty/faq-question'; +const HEADING_LEVELS = [ 2, 3, 4, 5, 6 ]; + +const HEADING_LEVEL_ICONS = { + 2: headingLevel2, + 3: headingLevel3, + 4: headingLevel4, + 5: headingLevel5, + 6: headingLevel6, +}; + +function collectQuestionBlocks( blocks ) { + return blocks.flatMap( ( block ) => { + const questions = block.name === QUESTION_BLOCK ? [ block ] : []; + + return questions.concat( + collectQuestionBlocks( block.innerBlocks || [] ) + ); + } ); +} + +function useSyncQuestionHeadingLevels( headingLevel, isAccordion ) { + const { clientId } = useBlockEditContext(); + const { updateBlockAttributes } = useDispatch( blockEditorStore ); + const questionBlocks = useSelect( + ( select ) => { + const { getBlocksByClientId } = select( blockEditorStore ); + const [ faqBlock ] = getBlocksByClientId( clientId ); + + return collectQuestionBlocks( faqBlock?.innerBlocks || [] ); + }, + [ clientId ] + ); + + useEffect( () => { + if ( ! isAccordion ) { + return; + } + + questionBlocks.forEach( ( block ) => { + if ( block.attributes.headingLevel !== headingLevel ) { + updateBlockAttributes( block.clientId, { headingLevel } ); + } + } ); + }, [ headingLevel, isAccordion, questionBlocks, updateBlockAttributes ] ); +} + export default function Edit( { clientId, attributes, setAttributes } ) { - const { isAccordion = true } = attributes; + const { isAccordion = true, headingLevel = 3 } = attributes; const blockProps = useBlockProps(); const innerBlocksProps = useInnerBlocksProps( blockProps, { allowedBlocks: [ 'blockparty/faq-item' ], @@ -35,6 +95,8 @@ export default function Edit( { clientId, attributes, setAttributes } ) { [] ); + useSyncQuestionHeadingLevels( headingLevel, isAccordion ); + // Synchronize isAccordion attribute to all child blocks useEffect( () => { const innerBlocks = getBlocks( clientId ); @@ -58,7 +120,10 @@ export default function Edit( { clientId, attributes, setAttributes } ) { const onAddItem = () => { const newItem = createBlock( 'blockparty/faq-item', {}, [ - createBlock( 'blockparty/faq-question', { isAccordion } ), + createBlock( 'blockparty/faq-question', { + isAccordion, + headingLevel, + } ), createBlock( 'blockparty/faq-answer', { isAccordion } ), ] ); insertBlock( newItem, undefined, clientId ); @@ -89,6 +154,42 @@ export default function Edit( { clientId, attributes, setAttributes } ) { } __nextHasNoMarginBottom /> + { isAccordion && ( + + setAttributes( { + headingLevel: Number( value ), + } ) + } + > + { HEADING_LEVELS.map( ( level ) => ( + + ) ) } + + ) }
From 512e602734135172564542df3e3ad7aacf6e4ec2 Mon Sep 17 00:00:00 2001 From: mricoul Date: Fri, 26 Jun 2026 15:31:57 +0200 Subject: [PATCH 09/18] feat(languages): update french translations files --- ...r_FR-4ad5d476d786190bd86e6dbedf4bb86e.json | 1 + ...r_FR-79fbb2fc2e001b2243c4fd8903190184.json | 1 + ...r_FR-8adf06b76d6c09cb7e7b053a4d516d16.json | 1 + ...r_FR-a3c855d2ec3455f2223f2d3db0d980f8.json | 39 +++++++++ ...r_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json | 1 - languages/blockparty-faq-fr_FR.mo | Bin 2128 -> 2310 bytes languages/blockparty-faq-fr_FR.po | 78 ++++++++++-------- languages/blockparty-faq.pot | 55 +++++++----- src/faq/edit.js | 4 +- src/index.js | 11 --- 10 files changed, 123 insertions(+), 68 deletions(-) create mode 100644 languages/blockparty-faq-fr_FR-4ad5d476d786190bd86e6dbedf4bb86e.json create mode 100644 languages/blockparty-faq-fr_FR-79fbb2fc2e001b2243c4fd8903190184.json create mode 100644 languages/blockparty-faq-fr_FR-8adf06b76d6c09cb7e7b053a4d516d16.json create mode 100644 languages/blockparty-faq-fr_FR-a3c855d2ec3455f2223f2d3db0d980f8.json delete mode 100644 languages/blockparty-faq-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json delete mode 100644 src/index.js diff --git a/languages/blockparty-faq-fr_FR-4ad5d476d786190bd86e6dbedf4bb86e.json b/languages/blockparty-faq-fr_FR-4ad5d476d786190bd86e6dbedf4bb86e.json new file mode 100644 index 0000000..0b47103 --- /dev/null +++ b/languages/blockparty-faq-fr_FR-4ad5d476d786190bd86e6dbedf4bb86e.json @@ -0,0 +1 @@ +{"translation-revision-date":"2026-06-26 15:28+0200","generator":"WP-CLI\/2.11.0","source":"build\/faq-answer\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"Answer\u2026":["R\u00e9ponse\u2026"]}}} \ No newline at end of file diff --git a/languages/blockparty-faq-fr_FR-79fbb2fc2e001b2243c4fd8903190184.json b/languages/blockparty-faq-fr_FR-79fbb2fc2e001b2243c4fd8903190184.json new file mode 100644 index 0000000..738315e --- /dev/null +++ b/languages/blockparty-faq-fr_FR-79fbb2fc2e001b2243c4fd8903190184.json @@ -0,0 +1 @@ +{"translation-revision-date":"2026-06-26 15:28+0200","generator":"WP-CLI\/2.11.0","source":"build\/faq-item\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"Add FAQ item":["Ajouter un \u00e9l\u00e9ment"],"Remove FAQ item":["Supprimer l\u2019\u00e9l\u00e9ment"]}}} \ No newline at end of file diff --git a/languages/blockparty-faq-fr_FR-8adf06b76d6c09cb7e7b053a4d516d16.json b/languages/blockparty-faq-fr_FR-8adf06b76d6c09cb7e7b053a4d516d16.json new file mode 100644 index 0000000..e22a3df --- /dev/null +++ b/languages/blockparty-faq-fr_FR-8adf06b76d6c09cb7e7b053a4d516d16.json @@ -0,0 +1 @@ +{"translation-revision-date":"2026-06-26 15:28+0200","generator":"WP-CLI\/2.11.0","source":"build\/faq-question\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"Question\u2026?":["Question\u2026?"]}}} \ No newline at end of file diff --git a/languages/blockparty-faq-fr_FR-a3c855d2ec3455f2223f2d3db0d980f8.json b/languages/blockparty-faq-fr_FR-a3c855d2ec3455f2223f2d3db0d980f8.json new file mode 100644 index 0000000..478f0df --- /dev/null +++ b/languages/blockparty-faq-fr_FR-a3c855d2ec3455f2223f2d3db0d980f8.json @@ -0,0 +1,39 @@ +{ + "translation-revision-date": "2026-06-26 15:28+0200", + "generator": "WP-CLI\/2.11.0", + "source": "build\/faq\/index.js", + "domain": "messages", + "locale_data": { + "messages": { + "": { + "domain": "messages", + "lang": "fr_FR", + "plural-forms": "nplurals=2; plural=(n != 1);" + }, + "Add FAQ item": [ + "Ajouter un \u00e9l\u00e9ment" + ], + "Remove FAQ item": [ + "Supprimer l\u2019\u00e9l\u00e9ment" + ], + "Settings": [ + "R\u00e9glages" + ], + "Accordion behavior": [ + "Comportement d\u2019accord\u00e9on" + ], + "If enabled, the FAQ will be displayed as an accordion component.": [ + "Si cette option est activ\u00e9e, la FAQ s'affichera sous forme d'accord\u00e9on." + ], + "Question heading level": [ + "Niveau de titre de la question" + ], + "Define the heading level for each FAQ question.": [ + "D\u00e9finissez le niveau de titre pour chaque question de la FAQ." + ], + "Heading level %d": [ + "Niveau de titre %d" + ] + } + } +} diff --git a/languages/blockparty-faq-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json b/languages/blockparty-faq-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json deleted file mode 100644 index 0553b08..0000000 --- a/languages/blockparty-faq-fr_FR-dfbff627e6c248bcb3b61d7d06da9ca9.json +++ /dev/null @@ -1 +0,0 @@ -{"translation-revision-date":"2026-01-26 16:50+0100","generator":"WP-CLI\/2.11.0","source":"build\/index.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"fr_FR","plural-forms":"nplurals=2; plural=(n != 1);"},"Add FAQ item":["Ajouter un \u00e9l\u00e9ment"],"Remove FAQ item":["Supprimer l\u2019\u00e9l\u00e9ment"],"FAQ Settings":["R\u00e9glages de FAQ"],"Accordion behavior":["Comportement d\u2019accord\u00e9on"],"If enabled, the HTML structure will be interpreted as an accordion from screen readers.":["Si c\u2019est activ\u00e9, la structure HTML du bloc sera interpr\u00e9t\u00e9 en tant qu\u2019accord\u00e9on pour les technologies d\u2019assistance."],"Question\u2026?":["Question\u2026?"],"Answer\u2026":["R\u00e9ponse\u2026"]}}} \ No newline at end of file diff --git a/languages/blockparty-faq-fr_FR.mo b/languages/blockparty-faq-fr_FR.mo index 239529e74fe65c126d23030f7646294daad61b00..1ff2012f41fb56871f5689e71c2f00e8879bbdd4 100644 GIT binary patch delta 935 zcmZ9}F=!J}7{KwDnApZzQ(LuyVxNO_u*Mp&Xa%tl#EOV*7D0-<-n}#j*SnazR1_qG zpo4C~MNlUx0l}e*;NXx!7okH%1#!~BT|uOS|1U|!_QAW~-Me?+`@Zj12ks5lzYeAz zDaJ7KAajj5!hD$E!styZRm2Pq;vDY83TE&Q?#27K3!mU|e1Wp>3l889Jcoa9AD-FP zeqUF!++#d+;&t$CoGvy~C>{{~3Lr^V^j=fX`6& zzs5dX#Sv8}LvAGVbv%oGJ)J-oQ7XQM(-`0(e1%fkN0hF8L+Q{uPU4l`&VdiQE+e(5 z7Rq;TQ4(FlEa$85-GyH$U6-ITb}*$<;{F;rin;R*x zzq=q^;HdV42%TMSNCnxi#j*jOWzf;c>ryEbxKkJ27lN!7z zvbV`y2i}r3HSJQA7gw#Wgte-6%7z;L)gfPcByWwDGl5jy_3mCgI9FV Gc;YXXzPUjF delta 760 zcmYk&ziSjh6bJBkcll+^ndG8I@YhSBjpun6@Ca!nfc@cA?fD6VUY{M_G0I^;AdzT{)1=Xh9^<4!^_Zx zHsA|rzkdav;s5j=H+Dx0<3#hY2JMbl;WB&+ZR4*)e?w%W@sU|UPQ#+6+8`w~G#ORYXwm&&OuyH~b!bxU3ojZCt*e`Vk zkBcpDb!Cm)VvHa5G~L@|37u{rUX{(3@ZHXX`>c(MT@x$eJwFJzE9{3x)V2~M9y^+y zkR8{Jl;=kwZ>s1iYgdVctiDs|sX|7mqTwiQ*qq%&uey!dZ?2LXWEDh$z{`4QF zNiT4EqS+Hh9BTXQ{(SyMv_W6v@1{wW1Ls(dES48@H;7!;qMV~dX=2g@TVUgahIe9g n$&;lCqHRa9;sF0K;%\n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2026-01-26T15:49:49+00:00\n" +"POT-Creation-Date: 2026-06-26T13:28:07+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.11.0\n" "X-Domain: blockparty-faq\n" @@ -35,42 +35,47 @@ msgstr "" msgid "Be API Technical team" msgstr "" -#: build/index.js:1 +#: build/faq-answer/index.js:1 +msgid "Answer…" +msgstr "" + +#: build/faq-item/index.js:1 +#: build/faq/index.js:1 msgid "Add FAQ item" msgstr "" -#: build/index.js:1 +#: build/faq-item/index.js:1 +#: build/faq/index.js:1 msgid "Remove FAQ item" msgstr "" -#: build/index.js:1 -msgid "FAQ Settings" +#: build/faq-question/index.js:1 +msgid "Question…?" msgstr "" -#: build/index.js:1 -msgid "Accordion behavior" +#: build/faq/index.js:1 +msgid "Settings" msgstr "" -#: build/index.js:1 -msgid "If enabled, the HTML structure will be interpreted as an accordion from screen readers." +#: build/faq/index.js:1 +msgid "Accordion behavior" msgstr "" -#: build/index.js:1 -msgid "Question…?" +#: build/faq/index.js:1 +msgid "If enabled, the FAQ will be displayed as an accordion component." msgstr "" -#: build/index.js:1 -msgid "Answer…" +#: build/faq/index.js:1 +msgid "Question heading level" msgstr "" -#: block.json -msgctxt "block title" -msgid "FAQ" +#: build/faq/index.js:1 +msgid "Define the heading level for each FAQ question." msgstr "" -#: block.json -msgctxt "block description" -msgid "A FAQ block for WordPress Editor that provided structured data based on FAQ schema." +#. translators: %d: heading level number (2–6). +#: build/faq/index.js:2 +msgid "Heading level %d" msgstr "" #: build/faq-answer/block.json @@ -102,3 +107,13 @@ msgstr "" msgctxt "block description" msgid "Content of the FAQ question." msgstr "" + +#: build/faq/block.json +msgctxt "block title" +msgid "FAQ" +msgstr "" + +#: build/faq/block.json +msgctxt "block description" +msgid "A FAQ block for WordPress Editor that provided structured data based on FAQ schema." +msgstr "" diff --git a/src/faq/edit.js b/src/faq/edit.js index 36cb8e7..09d2423 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -141,11 +141,11 @@ export default function Edit( { clientId, attributes, setAttributes } ) { - + Date: Fri, 26 Jun 2026 15:34:39 +0200 Subject: [PATCH 10/18] fix: plugin version --- README.md | 6 ------ blockparty-faq.php | 4 ++-- languages/blockparty-faq.pot | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/faq-answer/block.json | 6 ++++-- src/faq-item/block.json | 6 ++++-- src/faq-question/block.json | 18 ++++++++++++++---- src/faq/block.json | 10 ++++++++-- 9 files changed, 36 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 8360985..82b886d 100644 --- a/README.md +++ b/README.md @@ -90,9 +90,3 @@ Yoast SEO is required for the FAQ schema (JSON-LD) generation. It is installed a - Add spacing support for answers - Add font size support for the question - Strip HTML tags from the question in structured data - -### 2.0.4 - 2026-06-26 - -- Refactor block markup to align with `blockparty-accordion` structure (`wp-block-blockparty-faq-*` classes) -- Add CSS custom properties for styling (`--wp--blockparty--faq--*`) -- Add deprecated handlers for 2.0.x markup retrocompatibility diff --git a/blockparty-faq.php b/blockparty-faq.php index b0ab6e9..dca702f 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -4,7 +4,7 @@ * Description: A FAQ block for WordPress Editor that provided structured data based on FAQ schema. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 2.0.4 + * Version: 2.0.3 * Plugin URI: https://beapi.fr * Author: Be API Technical team * Author URI: https://beapi.fr @@ -41,7 +41,7 @@ } // Plugin constants -define( 'BLOCKPARTY_FAQ_VERSION', '2.0.4' ); +define( 'BLOCKPARTY_FAQ_VERSION', '2.0.3' ); // Plugin URL and PATH define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); diff --git a/languages/blockparty-faq.pot b/languages/blockparty-faq.pot index de95b65..3bf6be4 100644 --- a/languages/blockparty-faq.pot +++ b/languages/blockparty-faq.pot @@ -2,7 +2,7 @@ # This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Project-Id-Version: Blockparty FAQ 2.0.4\n" +"Project-Id-Version: Blockparty FAQ 2.0.3\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blockparty-faq\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/package-lock.json b/package-lock.json index b42f093..57185aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockparty-faq", - "version": "1.0.2", + "version": "2.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockparty-faq", - "version": "1.0.2", + "version": "2.0.3", "license": "GPL-2.0-or-later", "dependencies": { "@beapi/be-a11y": "^1.7.2", diff --git a/package.json b/package.json index 9b62690..b604620 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-faq", - "version": "2.0.4", + "version": "2.0.3", "description": "SEO friendly FAQ module in an accessible accordion", "author": "Be API Technical team", "license": "GPL-2.0-or-later", diff --git a/src/faq-answer/block.json b/src/faq-answer/block.json index f9c6faf..711b7cb 100644 --- a/src/faq-answer/block.json +++ b/src/faq-answer/block.json @@ -2,10 +2,12 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-answer", - "version": "2.0.4", + "version": "2.0.3", "title": "FAQ Answer", "category": "design", - "parent": [ "blockparty/faq-item" ], + "parent": [ + "blockparty/faq-item" + ], "description": "Content of the FAQ answer.", "supports": { "html": false, diff --git a/src/faq-item/block.json b/src/faq-item/block.json index 7a0c25e..9e7b837 100644 --- a/src/faq-item/block.json +++ b/src/faq-item/block.json @@ -2,10 +2,12 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-item", - "version": "2.0.4", + "version": "2.0.3", "title": "FAQ Item", "category": "design", - "parent": [ "blockparty/faq" ], + "parent": [ + "blockparty/faq" + ], "description": "A FAQ item containing a question and an answer.", "supports": { "html": false, diff --git a/src/faq-question/block.json b/src/faq-question/block.json index d214f82..838af97 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -2,12 +2,16 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-question", - "version": "2.0.4", + "version": "2.0.3", "title": "FAQ Question", "category": "design", - "parent": [ "blockparty/faq-item" ], + "parent": [ + "blockparty/faq-item" + ], "description": "Content of the FAQ question.", - "usesContext": [ "blockparty/headingLevel" ], + "usesContext": [ + "blockparty/headingLevel" + ], "supports": { "html": false, "inserter": false, @@ -28,7 +32,13 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ 2, 3, 4, 5, 6 ] + "enum": [ + 2, + 3, + 4, + 5, + 6 + ] } }, "textdomain": "blockparty-faq", diff --git a/src/faq/block.json b/src/faq/block.json index b016aae..b637484 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq", - "version": "2.0.4", + "version": "2.0.3", "title": "FAQ", "category": "design", "description": "A FAQ block for WordPress Editor that provided structured data based on FAQ schema.", @@ -18,7 +18,13 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ 2, 3, 4, 5, 6 ] + "enum": [ + 2, + 3, + 4, + 5, + 6 + ] } }, "providesContext": { From 4a0bdae1ed00ca81cfc52efa314b917b5b03f50b Mon Sep 17 00:00:00 2001 From: mricoul Date: Fri, 26 Jun 2026 15:44:37 +0200 Subject: [PATCH 11/18] fix: edit js blockprops --- src/faq-answer/block.json | 4 +--- src/faq-item/block.json | 4 +--- src/faq-item/edit.js | 4 +--- src/faq-question/block.json | 16 +++------------- src/faq/block.json | 8 +------- 5 files changed, 7 insertions(+), 29 deletions(-) diff --git a/src/faq-answer/block.json b/src/faq-answer/block.json index 711b7cb..bf79231 100644 --- a/src/faq-answer/block.json +++ b/src/faq-answer/block.json @@ -5,9 +5,7 @@ "version": "2.0.3", "title": "FAQ Answer", "category": "design", - "parent": [ - "blockparty/faq-item" - ], + "parent": [ "blockparty/faq-item" ], "description": "Content of the FAQ answer.", "supports": { "html": false, diff --git a/src/faq-item/block.json b/src/faq-item/block.json index 9e7b837..a584901 100644 --- a/src/faq-item/block.json +++ b/src/faq-item/block.json @@ -5,9 +5,7 @@ "version": "2.0.3", "title": "FAQ Item", "category": "design", - "parent": [ - "blockparty/faq" - ], + "parent": [ "blockparty/faq" ], "description": "A FAQ item containing a question and an answer.", "supports": { "html": false, diff --git a/src/faq-item/edit.js b/src/faq-item/edit.js index 0099fee..039b97c 100644 --- a/src/faq-item/edit.js +++ b/src/faq-item/edit.js @@ -70,9 +70,7 @@ export default function Edit( { clientId } ) { /> -
-
-
+
); } diff --git a/src/faq-question/block.json b/src/faq-question/block.json index 838af97..b28917f 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -5,13 +5,9 @@ "version": "2.0.3", "title": "FAQ Question", "category": "design", - "parent": [ - "blockparty/faq-item" - ], + "parent": [ "blockparty/faq-item" ], "description": "Content of the FAQ question.", - "usesContext": [ - "blockparty/headingLevel" - ], + "usesContext": [ "blockparty/headingLevel" ], "supports": { "html": false, "inserter": false, @@ -32,13 +28,7 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ - 2, - 3, - 4, - 5, - 6 - ] + "enum": [ 2, 3, 4, 5, 6 ] } }, "textdomain": "blockparty-faq", diff --git a/src/faq/block.json b/src/faq/block.json index b637484..e744445 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -18,13 +18,7 @@ "headingLevel": { "type": "number", "default": 3, - "enum": [ - 2, - 3, - 4, - 5, - 6 - ] + "enum": [ 2, 3, 4, 5, 6 ] } }, "providesContext": { From af49dcc98d071b2661a1206183795bc2669b1ec4 Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 11:41:14 +0200 Subject: [PATCH 12/18] feat: add PSR-4 autoloading for plugin classes Configures Composer to use PSR-4 for the `Blockparty\Faq\` namespace. This involves adding the `autoload` section to `composer.json`, including `vendor/autoload.php`, and renaming class directories (e.g., `schema` to `Schema`) to align with PSR-4 capitalization standards. This improves class management, code organization, and facilitates future development by adhering to modern PHP practices. --- blockparty-faq.php | 20 +++++++++++-------- composer.json | 5 +++++ includes/{hooks => Hooks}/Schema_Hooks.php | 0 includes/{schema => Schema}/FAQ_Schema.php | 0 .../FAQ_Schema_Generator.php | 0 .../Rank_Math_Seo_Service.php | 0 .../Seo_Service_Interface.php | 0 .../Seo_Service_Resolver.php | 0 .../Seopress_Seo_Service.php | 0 .../Yoast_Seo_Service.php | 0 10 files changed, 17 insertions(+), 8 deletions(-) rename includes/{hooks => Hooks}/Schema_Hooks.php (100%) rename includes/{schema => Schema}/FAQ_Schema.php (100%) rename includes/{schema => Schema}/FAQ_Schema_Generator.php (100%) rename includes/{services => Services}/Rank_Math_Seo_Service.php (100%) rename includes/{services => Services}/Seo_Service_Interface.php (100%) rename includes/{services => Services}/Seo_Service_Resolver.php (100%) rename includes/{services => Services}/Seopress_Seo_Service.php (100%) rename includes/{services => Services}/Yoast_Seo_Service.php (100%) diff --git a/blockparty-faq.php b/blockparty-faq.php index edb80c7..33e4b0a 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -40,6 +40,10 @@ die( '-1' ); } +if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) { + include_once __DIR__ . '/vendor/autoload.php'; +} + // Plugin constants define( 'BLOCKPARTY_FAQ_VERSION', '2.0.3' ); @@ -47,16 +51,16 @@ define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); // Schema & SEO services -require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/FAQ_Schema_Generator.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/schema/FAQ_Schema.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Interface.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Yoast_Seo_Service.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Rank_Math_Seo_Service.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seopress_Seo_Service.php'; -require_once BLOCKPARTY_FAQ_DIR . 'includes/services/Seo_Service_Resolver.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Schema/FAQ_Schema_Generator.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Schema/FAQ_Schema.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Services/Seo_Service_Interface.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Services/Yoast_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Services/Rank_Math_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Services/Seopress_Seo_Service.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Services/Seo_Service_Resolver.php'; // Hooks -require_once BLOCKPARTY_FAQ_DIR . 'includes/hooks/Schema_Hooks.php'; +require_once BLOCKPARTY_FAQ_DIR . 'includes/Hooks/Schema_Hooks.php'; /** * Initialize plugin blocks. diff --git a/composer.json b/composer.json index adbe679..fedff64 100644 --- a/composer.json +++ b/composer.json @@ -60,6 +60,11 @@ "url": "https://repo.wp-packages.org" } ], + "autoload": { + "psr-4": { + "Blockparty\\Faq\\": "includes/" + } + }, "scripts": { "cs": "./vendor/bin/phpcs", "cb": "./vendor/bin/phpcbf" diff --git a/includes/hooks/Schema_Hooks.php b/includes/Hooks/Schema_Hooks.php similarity index 100% rename from includes/hooks/Schema_Hooks.php rename to includes/Hooks/Schema_Hooks.php diff --git a/includes/schema/FAQ_Schema.php b/includes/Schema/FAQ_Schema.php similarity index 100% rename from includes/schema/FAQ_Schema.php rename to includes/Schema/FAQ_Schema.php diff --git a/includes/schema/FAQ_Schema_Generator.php b/includes/Schema/FAQ_Schema_Generator.php similarity index 100% rename from includes/schema/FAQ_Schema_Generator.php rename to includes/Schema/FAQ_Schema_Generator.php diff --git a/includes/services/Rank_Math_Seo_Service.php b/includes/Services/Rank_Math_Seo_Service.php similarity index 100% rename from includes/services/Rank_Math_Seo_Service.php rename to includes/Services/Rank_Math_Seo_Service.php diff --git a/includes/services/Seo_Service_Interface.php b/includes/Services/Seo_Service_Interface.php similarity index 100% rename from includes/services/Seo_Service_Interface.php rename to includes/Services/Seo_Service_Interface.php diff --git a/includes/services/Seo_Service_Resolver.php b/includes/Services/Seo_Service_Resolver.php similarity index 100% rename from includes/services/Seo_Service_Resolver.php rename to includes/Services/Seo_Service_Resolver.php diff --git a/includes/services/Seopress_Seo_Service.php b/includes/Services/Seopress_Seo_Service.php similarity index 100% rename from includes/services/Seopress_Seo_Service.php rename to includes/Services/Seopress_Seo_Service.php diff --git a/includes/services/Yoast_Seo_Service.php b/includes/Services/Yoast_Seo_Service.php similarity index 100% rename from includes/services/Yoast_Seo_Service.php rename to includes/Services/Yoast_Seo_Service.php From 6bcb8b6983036f75da77b4a107a2339201f9a783 Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 12:16:00 +0200 Subject: [PATCH 13/18] fix: Instantly synchronize FAQ question headings Refactors heading level synchronization using `useLayoutEffect` and direct calls. This prevents visual delays and inconsistencies when the parent FAQ block's `isAccordion` or `headingLevel` attributes change in the editor. --- src/faq/edit.js | 110 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 77 insertions(+), 33 deletions(-) diff --git a/src/faq/edit.js b/src/faq/edit.js index 09d2423..23728e2 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -6,7 +6,6 @@ import { useBlockProps, useInnerBlocksProps, InspectorControls, - useBlockEditContext, store as blockEditorStore, } from '@wordpress/block-editor'; import { @@ -30,7 +29,7 @@ import { import { useDispatch, useSelect } from '@wordpress/data'; import { createBlock } from '@wordpress/blocks'; import { __, sprintf } from '@wordpress/i18n'; -import { useEffect } from '@wordpress/element'; +import { useEffect, useLayoutEffect } from '@wordpress/element'; const QUESTION_BLOCK = 'blockparty/faq-question'; const HEADING_LEVELS = [ 2, 3, 4, 5, 6 ]; @@ -53,30 +52,46 @@ function collectQuestionBlocks( blocks ) { } ); } -function useSyncQuestionHeadingLevels( headingLevel, isAccordion ) { - const { clientId } = useBlockEditContext(); - const { updateBlockAttributes } = useDispatch( blockEditorStore ); - const questionBlocks = useSelect( - ( select ) => { - const { getBlocksByClientId } = select( blockEditorStore ); - const [ faqBlock ] = getBlocksByClientId( clientId ); - - return collectQuestionBlocks( faqBlock?.innerBlocks || [] ); - }, - [ clientId ] - ); +function syncQuestionHeadingLevels( + clientId, + headingLevel, + isAccordion, + { getBlocksByClientId, updateBlockAttributes } +) { + if ( ! isAccordion ) { + return; + } - useEffect( () => { - if ( ! isAccordion ) { - return; + const [ faqBlock ] = getBlocksByClientId( clientId ); + const questionBlocks = collectQuestionBlocks( faqBlock?.innerBlocks || [] ); + + questionBlocks.forEach( ( block ) => { + if ( block.attributes.headingLevel !== headingLevel ) { + updateBlockAttributes( block.clientId, { headingLevel } ); } + } ); +} - questionBlocks.forEach( ( block ) => { - if ( block.attributes.headingLevel !== headingLevel ) { - updateBlockAttributes( block.clientId, { headingLevel } ); - } +function useSyncQuestionHeadingLevels( + clientId, + headingLevel, + isAccordion, + blockEditor +) { + const { getBlocksByClientId, updateBlockAttributes } = blockEditor; + + useLayoutEffect( () => { + syncQuestionHeadingLevels( clientId, headingLevel, isAccordion, { + getBlocksByClientId, + updateBlockAttributes, } ); - }, [ headingLevel, isAccordion, questionBlocks, updateBlockAttributes ] ); + }, [ + clientId, + headingLevel, + isAccordion, + getBlocksByClientId, + updateBlockAttributes, + ] ); } export default function Edit( { clientId, attributes, setAttributes } ) { @@ -89,13 +104,19 @@ export default function Edit( { clientId, attributes, setAttributes } ) { } ); const { insertBlock, updateBlockAttributes } = - useDispatch( 'core/block-editor' ); - const { getBlocks } = useSelect( - ( select ) => select( 'core/block-editor' ), + useDispatch( blockEditorStore ); + const blockEditor = useSelect( + ( select ) => select( blockEditorStore ), [] ); + const { getBlocks, getBlocksByClientId } = blockEditor; - useSyncQuestionHeadingLevels( headingLevel, isAccordion ); + useSyncQuestionHeadingLevels( + clientId, + headingLevel, + isAccordion, + blockEditor + ); // Synchronize isAccordion attribute to all child blocks useEffect( () => { @@ -149,9 +170,21 @@ export default function Edit( { clientId, attributes, setAttributes } ) { 'blockparty-faq' ) } checked={ isAccordion } - onChange={ ( value ) => - setAttributes( { isAccordion: value } ) - } + onChange={ ( value ) => { + setAttributes( { isAccordion: value } ); + + if ( value ) { + syncQuestionHeadingLevels( + clientId, + headingLevel, + true, + { + getBlocksByClientId, + updateBlockAttributes, + } + ); + } + } } __nextHasNoMarginBottom /> { isAccordion && ( @@ -167,11 +200,22 @@ export default function Edit( { clientId, attributes, setAttributes } ) { value={ headingLevel } isBlock __next40pxDefaultSize - onChange={ ( value ) => + onChange={ ( value ) => { + const newHeadingLevel = Number( value ); + setAttributes( { - headingLevel: Number( value ), - } ) - } + headingLevel: newHeadingLevel, + } ); + syncQuestionHeadingLevels( + clientId, + newHeadingLevel, + isAccordion, + { + getBlocksByClientId, + updateBlockAttributes, + } + ); + } } > { HEADING_LEVELS.map( ( level ) => ( Date: Tue, 30 Jun 2026 12:18:19 +0200 Subject: [PATCH 14/18] fix: Safely merge and renumber FAQPage schema questions Ensures that new FAQ questions are merged with existing ones in the schema data, rather than overwriting them. Normalizes the structure of existing questions and renumbers all combined questions to maintain valid Schema.org position values. --- includes/Services/Seopress_Seo_Service.php | 47 +++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/includes/Services/Seopress_Seo_Service.php b/includes/Services/Seopress_Seo_Service.php index 0c054b4..55e9514 100644 --- a/includes/Services/Seopress_Seo_Service.php +++ b/includes/Services/Seopress_Seo_Service.php @@ -126,14 +126,59 @@ private function merge_block_faq_into_schema( array $json ): ?array { return null; } + $existing_questions = $this->normalize_main_entity( $json['mainEntity'] ?? [] ); + $merged_questions = array_merge( $existing_questions, $questions ); + $json['@type'] = 'FAQPage'; - $json['mainEntity'] = $questions; + $json['mainEntity'] = $this->renumber_question_positions( $merged_questions ); $json['@context'] = $json['@context'] ?? 'https://schema.org'; $json['inLanguage'] = $json['inLanguage'] ?? get_bloginfo( 'language' ); return $json; } + /** + * Normalize FAQPage mainEntity to a list of Question entries. + * + * @param mixed $main_entity FAQPage mainEntity value. + * + * @return array> + */ + private function normalize_main_entity( $main_entity ): array { + if ( empty( $main_entity ) || ! is_array( $main_entity ) ) { + return []; + } + + if ( isset( $main_entity['@type'] ) ) { + return [ $main_entity ]; + } + + return array_values( + array_filter( + $main_entity, + static fn( $question ) => is_array( $question ) && ! empty( $question ) + ) + ); + } + + /** + * Ensure sequential position values on merged FAQ questions. + * + * @param array> $questions Question entries. + * + * @return array> + */ + private function renumber_question_positions( array $questions ): array { + $position = 1; + + foreach ( $questions as $index => $question ) { + $questions[ $index ]['position'] = $position; + ++$position; + } + + return $questions; + } + /** * Create a schema generator from the current singular post. * From d4eab602f633c53a300c9d2f41aaef6f3f94b442 Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 12:22:11 +0200 Subject: [PATCH 15/18] fix: Use data hooks for FAQ heading synchronization Updates the `useSyncQuestionHeadingLevels` hook to leverage `@wordpress/data`'s `useSelect` and `useDispatch` for accessing block editor state and actions. This removes the need to pass the `blockEditor` object as a prop, improving the hook's encapsulation and aligning with modern WordPress block editor development patterns. --- src/faq/edit.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/faq/edit.js b/src/faq/edit.js index 23728e2..ffee6cf 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -72,13 +72,12 @@ function syncQuestionHeadingLevels( } ); } -function useSyncQuestionHeadingLevels( - clientId, - headingLevel, - isAccordion, - blockEditor -) { - const { getBlocksByClientId, updateBlockAttributes } = blockEditor; +function useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion ) { + const { getBlocksByClientId } = useSelect( + ( select ) => select( blockEditorStore ), + [] + ); + const { updateBlockAttributes } = useDispatch( blockEditorStore ); useLayoutEffect( () => { syncQuestionHeadingLevels( clientId, headingLevel, isAccordion, { @@ -111,12 +110,7 @@ export default function Edit( { clientId, attributes, setAttributes } ) { ); const { getBlocks, getBlocksByClientId } = blockEditor; - useSyncQuestionHeadingLevels( - clientId, - headingLevel, - isAccordion, - blockEditor - ); + useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion ); // Synchronize isAccordion attribute to all child blocks useEffect( () => { From 9bdccb965ea51e9fc9ab9ed806d9d3e60ef8c0ed Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 12:24:11 +0200 Subject: [PATCH 16/18] fix: Ensure FAQ heading synchronization reacts to inner block changes Updates the `useSyncQuestionHeadingLevels` hook to explicitly select the inner FAQ question blocks using `useSelect`. By including these blocks in the `useEffect` dependencies, heading levels are now correctly re-synchronized when questions are added, removed, or reordered within the FAQ block. --- src/faq/edit.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/faq/edit.js b/src/faq/edit.js index ffee6cf..1dfe691 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -73,6 +73,15 @@ function syncQuestionHeadingLevels( } function useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion ) { + const questionBlocks = useSelect( + ( select ) => { + const { getBlocksByClientId } = select( blockEditorStore ); + const [ faqBlock ] = getBlocksByClientId( clientId ); + + return collectQuestionBlocks( faqBlock?.innerBlocks || [] ); + }, + [ clientId ] + ); const { getBlocksByClientId } = useSelect( ( select ) => select( blockEditorStore ), [] @@ -88,6 +97,7 @@ function useSyncQuestionHeadingLevels( clientId, headingLevel, isAccordion ) { clientId, headingLevel, isAccordion, + questionBlocks, getBlocksByClientId, updateBlockAttributes, ] ); From c974940b311ec1f817caae505b0cb430731494e6 Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 11:56:35 +0200 Subject: [PATCH 17/18] chore(bump): version 2.1.0 --- .plugin-data | 2 +- blockparty-faq.php | 4 ++-- languages/blockparty-faq.pot | 2 +- package-lock.json | 4 ++-- package.json | 2 +- src/faq-answer/block.json | 2 +- src/faq-item/block.json | 2 +- src/faq-question/block.json | 2 +- src/faq/block.json | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.plugin-data b/.plugin-data index a66c5dc..8bc87bb 100644 --- a/.plugin-data +++ b/.plugin-data @@ -1,4 +1,4 @@ { - "version": "2.0.3", + "version": "2.1.0", "slug": "blockparty-faq" } diff --git a/blockparty-faq.php b/blockparty-faq.php index d16c173..6c1174e 100644 --- a/blockparty-faq.php +++ b/blockparty-faq.php @@ -4,7 +4,7 @@ * Description: A FAQ block for WordPress Editor that provided structured data based on FAQ schema. * Requires at least: 6.2 * Requires PHP: 8.1 - * Version: 2.0.3 + * Version: 2.1.0 * Plugin URI: https://beapi.fr * Author: Be API Technical team * Author URI: https://beapi.fr @@ -45,7 +45,7 @@ } // Plugin constants -define( 'BLOCKPARTY_FAQ_VERSION', '2.0.3' ); +define( 'BLOCKPARTY_FAQ_VERSION', '2.1.0' ); // Plugin URL and PATH define( 'BLOCKPARTY_FAQ_DIR', plugin_dir_path( __FILE__ ) ); diff --git a/languages/blockparty-faq.pot b/languages/blockparty-faq.pot index 3bf6be4..b8b67fe 100644 --- a/languages/blockparty-faq.pot +++ b/languages/blockparty-faq.pot @@ -2,7 +2,7 @@ # This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Project-Id-Version: Blockparty FAQ 2.0.3\n" +"Project-Id-Version: Blockparty FAQ 2.1.0\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blockparty-faq\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/package-lock.json b/package-lock.json index 57185aa..42a09a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockparty-faq", - "version": "2.0.3", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockparty-faq", - "version": "2.0.3", + "version": "2.1.0", "license": "GPL-2.0-or-later", "dependencies": { "@beapi/be-a11y": "^1.7.2", diff --git a/package.json b/package.json index bf72770..a8d1b72 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "blockparty-faq", - "version": "2.0.3", + "version": "2.1.0", "description": "SEO friendly FAQ module in an accessible accordion", "author": "Be API Technical team", "license": "GPL-2.0-or-later", diff --git a/src/faq-answer/block.json b/src/faq-answer/block.json index bf79231..69f4061 100644 --- a/src/faq-answer/block.json +++ b/src/faq-answer/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-answer", - "version": "2.0.3", + "version": "2.1.0", "title": "FAQ Answer", "category": "design", "parent": [ "blockparty/faq-item" ], diff --git a/src/faq-item/block.json b/src/faq-item/block.json index a584901..97292d5 100644 --- a/src/faq-item/block.json +++ b/src/faq-item/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-item", - "version": "2.0.3", + "version": "2.1.0", "title": "FAQ Item", "category": "design", "parent": [ "blockparty/faq" ], diff --git a/src/faq-question/block.json b/src/faq-question/block.json index b28917f..9a21948 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq-question", - "version": "2.0.3", + "version": "2.1.0", "title": "FAQ Question", "category": "design", "parent": [ "blockparty/faq-item" ], diff --git a/src/faq/block.json b/src/faq/block.json index e744445..0507dec 100644 --- a/src/faq/block.json +++ b/src/faq/block.json @@ -2,7 +2,7 @@ "$schema": "https://schemas.wp.org/trunk/block.json", "apiVersion": 3, "name": "blockparty/faq", - "version": "2.0.3", + "version": "2.1.0", "title": "FAQ", "category": "design", "description": "A FAQ block for WordPress Editor that provided structured data based on FAQ schema.", From 5ebdaf250829e4da6abe84589d0e33b1ece02bf4 Mon Sep 17 00:00:00 2001 From: mricoul Date: Tue, 30 Jun 2026 11:59:47 +0200 Subject: [PATCH 18/18] docs: add CHANGELOG.md and readme.txt --- CHANGELOG.md | 108 ++++++++++++++++++++++++++++++++++++++++++++++++ readme.txt | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 221 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 readme.txt diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9bfa564 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,108 @@ +# 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). + +## [2.1.0] - 2026-06-30 + +### Added + +- Configurable FAQ question heading level (h2–h6) from the block settings panel. +- Rank Math SEO integration for FAQ structured data (JSON-LD). +- SEOPress integration for FAQ structured data (JSON-LD). +- SEO service resolver to delegate schema output to the active SEO plugin (Yoast SEO, Rank Math, or SEOPress). +- PSR-4 autoloading for plugin PHP classes via Composer. +- Block example in the FAQ block inserter preview. +- Deprecated save handlers to preserve front-end markup for content saved in 2.0.x. + +### Changed + +- Refactored FAQ block markup to use WordPress block class names (aligned with blockparty-accordion). +- Refactored Yoast SEO integration into a dedicated service class alongside other SEO plugins. +- Updated French translations for all block editor scripts. +- Replaced wp-env npm scripts (`start:env` / `stop:env` / `setup:env`) with `env:start` / `env:stop`. +- Local development environment now mounts Yoast SEO, Rank Math, and SEOPress via Composer. + +### Fixed + +- Removed duplicate block wrapper in the FAQ item editor component (`useBlockProps` called twice). +- Renamed `includes/` subdirectories to match PSR-4 namespace casing (`Schema/`, `Services/`, `Hooks/`). + +### Removed + +- Psalm static analysis configuration and dependency. + +## [2.0.3] - 2026-02-17 + +### Added + +- Support for core/button blocks inside FAQ answers. +- Spacing support for FAQ answers. +- Font size (typography) support for FAQ questions. + +### Changed + +- FAQ question text is stripped of HTML tags in structured data output. + +## [2.0.2] - 2026-01-27 + +### Fixed + +- Added missing `isAccordion` attribute to the parent FAQ block. + +## [2.0.1] - 2026-01-27 + +### Fixed + +- Block registration now uses block metadata from `block.json` correctly after the 2.0 build restructure. + +## [2.0.0] - 2026-01-27 + +### Added + +- Nested block architecture with child blocks: `faq-item`, `faq-question`, and `faq-answer`. +- Configurable accordion mode via the `isAccordion` attribute (interactive accordion or static layout). +- InnerBlocks support in FAQ answers (paragraphs, lists, images, and other Gutenberg blocks). +- InnerBlocks support in FAQ questions when accordion mode is disabled. +- Front-end accordion script with configurable behavior via the `beapi_faq_block_config` filter. +- Automatic migration from the legacy `questions` array attribute to the InnerBlocks format. +- Add and remove FAQ item controls in the block editor toolbar. +- Full internationalization: PO/MO translations for PHP and JSON translations for JavaScript. +- Yoast SEO FAQPage structured data integration. +- wp-env local development environment. + +### Changed + +- Build structure reorganized to follow the blockparty-accordion model (one `block.json` per block directory). + +## [1.0.2] - 2024-06-07 + +### Changed + +- Added PHP 8.2 to supported PHP versions. + +## [1.0.1] - 2024-04-03 + +### Fixed + +- Corrected CSS custom property variable names. + +## [1.0.0] - 2024-04-02 + +### Added + +- Initial release of the Blockparty FAQ Gutenberg block. +- Accessible accordion front-end behavior powered by `@beapi/be-a11y`. +- Yoast SEO FAQPage structured data (JSON-LD) generation. +- Editor controls to add and remove FAQ items. + +[2.1.0]: https://github.com/BeAPI/blockparty-faq/compare/2.0.3...2.1.0 +[2.0.3]: https://github.com/BeAPI/blockparty-faq/compare/2.0.2...2.0.3 +[2.0.2]: https://github.com/BeAPI/blockparty-faq/compare/2.0.1...2.0.2 +[2.0.1]: https://github.com/BeAPI/blockparty-faq/compare/2.0.0...2.0.1 +[2.0.0]: https://github.com/BeAPI/blockparty-faq/compare/1.0.2...2.0.0 +[1.0.2]: https://github.com/BeAPI/blockparty-faq/compare/1.0.1...1.0.2 +[1.0.1]: https://github.com/BeAPI/blockparty-faq/compare/1.0.0...1.0.1 +[1.0.0]: https://github.com/BeAPI/blockparty-faq/releases/tag/1.0.0 diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..02056ca --- /dev/null +++ b/readme.txt @@ -0,0 +1,113 @@ +=== Blockparty FAQ === +Contributors: beapi +Tags: block, faq, accordion, gutenberg, schema, seo, accessibility +Requires at least: 6.2 +Tested up to: 6.8 +Requires PHP: 8.1 +Stable tag: 2.1.0 +License: GPL-2.0-or-later +License URI: https://www.gnu.org/licenses/gpl-2.0.html + +A Gutenberg FAQ block with accessible accordion behavior and SEO-friendly structured data. + +== Description == + +Blockparty FAQ provides a nested Gutenberg block for building frequently asked questions pages. Each FAQ entry is composed of a question and a rich-text answer that can contain any supported inner blocks (paragraphs, lists, images, buttons, and more). + +**Key features:** + +* Accessible accordion on the front end, powered by `@beapi/be-a11y`. +* Toggle between accordion and static display modes. +* Configurable question heading level (h2–h6). +* Nested block architecture: FAQ → FAQ Item → Question + Answer. +* FAQPage structured data (JSON-LD) via Yoast SEO, Rank Math, or SEOPress. +* Automatic migration from the legacy single-block format (pre-2.0). +* Full editor internationalization (JavaScript JSON translations and PHP PO/MO files). + +**SEO plugins** + +FAQ structured data requires one of the following SEO plugins to be active: + +* Yoast SEO +* Rank Math +* SEOPress + +Only one SEO plugin should be active at a time. The plugin automatically detects which one is available and outputs the appropriate schema. + +== Installation == + +1. Upload the plugin files to the `/wp-content/plugins/blockparty-faq` directory, or install the plugin through the WordPress plugins screen directly. +2. Activate the plugin through the **Plugins** screen in WordPress. +3. Install and activate Yoast SEO, Rank Math, or SEOPress if you need FAQ structured data output. +4. Insert the **FAQ** block from the block inserter in the WordPress editor. + +== Frequently Asked Questions == + += Does this block work without an SEO plugin? = + +Yes. The FAQ block renders correctly on the front end without any SEO plugin. Structured data (JSON-LD) output requires Yoast SEO, Rank Math, or SEOPress. + += Can I use multiple FAQ blocks on the same page? = + +Yes. All FAQ blocks on a page are aggregated into a single FAQPage schema entry. + += Is the accordion accessible? = + +Yes. The front-end accordion uses `@beapi/be-a11y` with proper ARIA attributes (`aria-expanded`, `role="region"`) and keyboard support. + +== Changelog == + += 2.1.0 - 2026-06-30 = +* Added configurable FAQ question heading level (h2–h6). +* Added Rank Math SEO integration for FAQ structured data. +* Added SEOPress integration for FAQ structured data. +* Added SEO service resolver to delegate schema output to the active SEO plugin. +* Added PSR-4 autoloading for plugin PHP classes. +* Added block inserter example preview for the FAQ block. +* Added deprecated save handlers for content saved in 2.0.x. +* Changed FAQ block markup to WordPress block class names (aligned with blockparty-accordion). +* Changed Yoast SEO integration into a dedicated service class. +* Changed wp-env npm scripts to `env:start` / `env:stop`. +* Fixed duplicate block wrapper in the FAQ item editor component. +* Fixed PSR-4 directory casing for Composer autoloading. +* Removed Psalm static analysis. + += 2.0.3 - 2026-02-17 = +* Added support for core/button blocks in FAQ answers. +* Added spacing support for FAQ answers. +* Added font size support for FAQ questions. +* Changed FAQ question text to strip HTML tags in structured data. + += 2.0.2 - 2026-01-27 = +* Fixed missing `isAccordion` attribute on the parent FAQ block. + += 2.0.1 - 2026-01-27 = +* Fixed block registration to use block metadata after the 2.0 build restructure. + += 2.0.0 - 2026-01-27 = +* Added nested block architecture (`faq-item`, `faq-question`, `faq-answer`). +* Added configurable accordion mode (`isAccordion` attribute). +* Added InnerBlocks support in FAQ answers and questions. +* Added front-end accordion script with `beapi_faq_block_config` filter. +* Added automatic migration from the legacy `questions` array format. +* Added add/remove FAQ item controls in the block editor. +* Added full internationalization (PO/MO and JSON translations). +* Added Yoast SEO FAQPage structured data integration. +* Changed build structure to one `block.json` per block directory. + += 1.0.2 - 2024-06-07 = +* Added PHP 8.2 to supported PHP versions. + += 1.0.1 - 2024-04-03 = +* Fixed CSS custom property variable names. + += 1.0.0 - 2024-04-02 = +* Initial release with accessible accordion and Yoast SEO FAQPage structured data. + +== Upgrade Notice == + += 2.1.0 = +Adds Rank Math and SEOPress support, configurable question heading levels, and updated block markup. Existing content is preserved via deprecated save handlers. + += 2.0.0 = +Major block architecture change. Existing FAQ blocks are automatically migrated to the new nested format on save.