diff --git a/.gitignore b/.gitignore index 839a99e..c77c5df 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,9 @@ Thumbs.db .wp-env.override.json phpcs.xml phpunit.xml + +# Composer +composer.lock + +# Plugins +.wp-env/plugins/ 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/.wp-env.json b/.wp-env.json index dafab87..4523018 100644 --- a/.wp-env.json +++ b/.wp-env.json @@ -1,5 +1,8 @@ { "plugins": [ - "." + ".", + ".wp-env/plugins/seo-by-rank-math", + ".wp-env/plugins/wordpress-seo", + ".wp-env/plugins/wp-seopress" ] } 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.md b/README.md index 82b886d..aec715d 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, Rank Math, and SEOPress are mounted 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, 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 a0c11f4..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 @@ -40,15 +40,27 @@ die( '-1' ); } +if ( is_readable( __DIR__ . '/vendor/autoload.php' ) ) { + include_once __DIR__ . '/vendor/autoload.php'; +} + // 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__ ) ); +// 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'; + // 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. @@ -83,9 +95,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/composer.json b/composer.json index 894b89e..fedff64 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": "*", @@ -34,7 +41,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 +48,29 @@ "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", + "wp-plugin/seo-by-rank-math": "1.0.272", + "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" + } + ], + "autoload": { + "psr-4": { + "Blockparty\\Faq\\": "includes/" + } }, "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/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" -} 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/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/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_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, + Rank_Math_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..55e9514 --- /dev/null +++ b/includes/Services/Seopress_Seo_Service.php @@ -0,0 +1,206 @@ + $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; + } + + $existing_questions = $this->normalize_main_entity( $json['mainEntity'] ?? [] ); + $merged_questions = array_merge( $existing_questions, $questions ); + + $json['@type'] = 'FAQPage'; + $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. + * + * @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/includes/hooks/schema.php b/includes/hooks/schema.php deleted file mode 100644 index 83cf17a..0000000 --- a/includes/hooks/schema.php +++ /dev/null @@ -1,21 +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/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 239529e..1ff2012 100644 Binary files a/languages/blockparty-faq-fr_FR.mo and b/languages/blockparty-faq-fr_FR.mo differ diff --git a/languages/blockparty-faq-fr_FR.po b/languages/blockparty-faq-fr_FR.po index 7d38da3..273bf5b 100644 --- a/languages/blockparty-faq-fr_FR.po +++ b/languages/blockparty-faq-fr_FR.po @@ -4,15 +4,15 @@ msgid "" msgstr "" "Project-Id-Version: Blockparty Faq 1.0.2\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/blockparty-faq\n" -"POT-Creation-Date: 2026-01-26T15:49:49+00:00\n" -"PO-Revision-Date: 2026-01-26 16:50+0100\n" +"POT-Creation-Date: 2026-06-26T13:28:07+00:00\n" +"PO-Revision-Date: 2026-06-26 15:28+0200\n" "Last-Translator: \n" "Language-Team: \n" "Language: fr_FR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 3.8\n" +"X-Generator: Poedit 3.9\n" "X-Domain: blockparty-faq\n" #. Plugin Name of the plugin @@ -40,51 +40,47 @@ msgstr "" msgid "Be API Technical team" msgstr "L’équipe technique de Be API" -#: build/index.js:1 +#: build/faq-answer/index.js:1 +msgid "Answer…" +msgstr "Réponse…" + +#: build/faq-item/index.js:1 build/faq/index.js:1 msgid "Add FAQ item" msgstr "Ajouter un élément" -#: build/index.js:1 +#: build/faq-item/index.js:1 build/faq/index.js:1 msgid "Remove FAQ item" msgstr "Supprimer l’élément" -#: build/index.js:1 -msgid "FAQ Settings" -msgstr "Réglages de FAQ" +#: build/faq-question/index.js:1 +msgid "Question…?" +msgstr "Question…?" -#: build/index.js:1 +#: build/faq/index.js:1 +msgid "Settings" +msgstr "Réglages" + +#: build/faq/index.js:1 msgid "Accordion behavior" msgstr "Comportement d’accordéon" -#: 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 "If enabled, the FAQ will be displayed as an accordion component." msgstr "" -"Si c’est activé, la structure HTML du bloc sera interprété en tant " -"qu’accordéon pour les technologies d’assistance." +"Si cette option est activée, la FAQ s'affichera sous forme d'accordéon." -#: build/index.js:1 -msgid "Question…?" -msgstr "Question…?" +#: build/faq/index.js:1 +msgid "Question heading level" +msgstr "Niveau de titre de la question" -#: build/index.js:1 -msgid "Answer…" -msgstr "Réponse…" - -#: block.json -msgctxt "block title" -msgid "FAQ" -msgstr "FAQ" +#: build/faq/index.js:1 +msgid "Define the heading level for each FAQ question." +msgstr "Définissez le niveau de titre pour chaque question de la FAQ." -#: block.json -msgctxt "block description" -msgid "" -"A FAQ block for WordPress Editor that provided structured data based on FAQ " -"schema." -msgstr "" -"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 "Niveau de titre %d" #: build/faq-answer/block.json msgctxt "block title" @@ -115,3 +111,17 @@ msgstr "Question de FAQ" msgctxt "block description" msgid "Content of the FAQ question." msgstr "Contenu de la question FAQ." + +#: build/faq/block.json +msgctxt "block title" +msgid "FAQ" +msgstr "FAQ" + +#: build/faq/block.json +msgctxt "block description" +msgid "" +"A FAQ block for WordPress Editor that provided structured data based on FAQ " +"schema." +msgstr "" +"A FAQ block for WordPress Editor that provided structured data based on FAQ " +"schema." diff --git a/languages/blockparty-faq.pot b/languages/blockparty-faq.pot index 9d514cd..b8b67fe 100644 --- a/languages/blockparty-faq.pot +++ b/languages/blockparty-faq.pot @@ -2,14 +2,14 @@ # This file is distributed under the GPL-2.0-or-later. msgid "" msgstr "" -"Project-Id-Version: Blockparty FAQ 1.0.2\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" "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/package-lock.json b/package-lock.json index b42f093..42a09a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "blockparty-faq", - "version": "1.0.2", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "blockparty-faq", - "version": "1.0.2", + "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 b604620..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", @@ -12,11 +12,10 @@ "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", + "env:stop": "wp-env stop" }, "dependencies": { "@beapi/be-a11y": "^1.7.2", 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 @@ - - - - - - - - - - - - - - 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. 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-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..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-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..039b97c 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,16 +32,19 @@ 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 ? 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 ); @@ -61,19 +70,7 @@ 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..9a21948 100644 --- a/src/faq-question/block.json +++ b/src/faq-question/block.json @@ -2,11 +2,12 @@ "$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" ], "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/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..024725b 100644 --- a/src/faq-question/edit.js +++ b/src/faq-question/edit.js @@ -13,11 +13,21 @@ import { __ } from '@wordpress/i18n'; 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', - } ); +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( ( select ) => select( 'core/block-editor' ).getBlocks( clientId ), @@ -26,21 +36,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 +53,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, [] ); } }, [ @@ -67,38 +68,41 @@ export default function Edit( { attributes, setAttributes, clientId } ) { setAttributes, ] ); + if ( ! isAccordion ) { + return ( +

+ +

+ ); + } + return ( -

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

+ + + 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..22276db 100644 --- a/src/faq-question/save.js +++ b/src/faq-question/save.js @@ -4,25 +4,30 @@ 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 { question, isAccordion = true, headingLevel = 3 } = attributes; + const blockProps = useBlockProps.save(); + const HeadingTag = `h${ headingLevel }`; - 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 024a625..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.", @@ -14,8 +14,40 @@ "isAccordion": { "type": "boolean", "default": true + }, + "headingLevel": { + "type": "number", + "default": 3, + "enum": [ 2, 3, 4, 5, 6 ] } }, + "providesContext": { + "blockparty/headingLevel": "headingLevel" + }, + "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", 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..1dfe691 100644 --- a/src/faq/edit.js +++ b/src/faq/edit.js @@ -3,38 +3,129 @@ */ import { BlockControls, - InnerBlocks, useBlockProps, + useInnerBlocksProps, InspectorControls, + 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 { useEffect } from '@wordpress/element'; +import { __, sprintf } from '@wordpress/i18n'; +import { useEffect, useLayoutEffect } 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 syncQuestionHeadingLevels( + clientId, + headingLevel, + isAccordion, + { getBlocksByClientId, updateBlockAttributes } +) { + if ( ! isAccordion ) { + return; + } + + const [ faqBlock ] = getBlocksByClientId( clientId ); + const questionBlocks = collectQuestionBlocks( faqBlock?.innerBlocks || [] ); + + questionBlocks.forEach( ( block ) => { + if ( block.attributes.headingLevel !== headingLevel ) { + updateBlockAttributes( block.clientId, { headingLevel } ); + } + } ); +} + +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 ), + [] + ); + const { updateBlockAttributes } = useDispatch( blockEditorStore ); + + useLayoutEffect( () => { + syncQuestionHeadingLevels( clientId, headingLevel, isAccordion, { + getBlocksByClientId, + updateBlockAttributes, + } ); + }, [ + clientId, + headingLevel, + isAccordion, + questionBlocks, + getBlocksByClientId, + 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' ], + template: [ [ 'blockparty/faq-item' ] ], + templateLock: false, + } ); 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( clientId, headingLevel, isAccordion ); // Synchronize isAccordion attribute to all child blocks 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 ) => { @@ -54,7 +145,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 ); @@ -72,30 +166,81 @@ export default function Edit( { clientId, attributes, setAttributes } ) { - + - setAttributes( { isAccordion: value } ) - } + onChange={ ( value ) => { + setAttributes( { isAccordion: value } ); + + if ( value ) { + syncQuestionHeadingLevels( + clientId, + headingLevel, + true, + { + getBlocksByClientId, + updateBlockAttributes, + } + ); + } + } } __nextHasNoMarginBottom /> + { isAccordion && ( + { + const newHeadingLevel = Number( value ); + + setAttributes( { + headingLevel: newHeadingLevel, + } ); + syncQuestionHeadingLevels( + clientId, + newHeadingLevel, + isAccordion, + { + getBlocksByClientId, + updateBlockAttributes, + } + ); + } } + > + { HEADING_LEVELS.map( ( level ) => ( + + ) ) } + + ) } -
-
- -
-
+
); } 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); } } } diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 78bd1c0..0000000 --- a/src/index.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * WordPress dependencies - */ - -/** - * Internal dependencies - */ -import './faq'; -import './faq-item'; -import './faq-question'; -import './faq-answer';