diff --git a/.gitignore b/.gitignore index d66edda..2579aca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .idea .DS_Store vendor +wordpress diff --git a/CHANGELONG.md b/CHANGELONG.md index b33e147..9913129 100755 --- a/CHANGELONG.md +++ b/CHANGELONG.md @@ -4,6 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## 2.0.0 - 2023-11-15 +- Bump min PHP version to 8.0. + ## 1.4.0 - 2019-01-03 ### Updated - `thefrosty/wp-utilties` to v^1.3.1. diff --git a/README.md b/README.md index adb0937..4a65c8e 100755 --- a/README.md +++ b/README.md @@ -1,14 +1,22 @@ -# Dwnload EDD Software License Manager [![Build Status](https://travis-ci.org/dwnload/EddSoftwareLicenseManager.svg?branch=master)](https://travis-ci.org/dwnload/EddSoftwareLicenseManager) +# EDD Software License Manager + +[![PHP from Packagist](https://img.shields.io/packagist/php-v/dwnload/edd-software-license-manager.svg)]() +[![Latest Stable Version](https://img.shields.io/packagist/v/dwnload/edd-software-license-manager.svg)](https://packagist.org/packages/dwnload/edd-software-license-manager) +[![Total Downloads](https://img.shields.io/packagist/dt/dwnload/edd-software-license-manager.svg)](https://packagist.org/packages/dwnload/edd-software-license-manager) +[![License](https://img.shields.io/packagist/l/dwnload/edd-software-license-manager.svg)](https://packagist.org/packages/dwnload/edd-software-license-manager) +![Build Status](https://github.com/dwnload/WpSettingsApi/actions/workflows/main.yml/badge.svg) +[![codecov](https://codecov.io/gh/dwnload/WpSettingsApi//branch/develop/graph/badge.svg)](https://codecov.io/gh/dwnload/WpSettingsApi/) + A PHP class abstraction for managing WordPress plugin licenses and auto-updates that are sold on an Easy Digital Downloads store. ## Package Installation (via Composer) To install this package, edit your `composer.json` file: -```js +```json { "require": { - "dwnload/edd-software-license-manager": "^1.3.0" + "dwnload/edd-software-license-manager": "^2.0" } } ``` @@ -20,31 +28,16 @@ Now run: ### How to use this package ```php -use Dwnload\EddSoftwareLicenseManager\Edd; - -// In the root of your plugin -$args = [ - 'api_url' => trailingslashit( https://plugingarden.dwnload.io ), - 'plugin_file' => __FILE__, - 'api_data' => [ - 'version' => (string) $version, // current version number - 'license' => (string) $license_key, // license key (used get_option above to retrieve from DB) - 'item_name' => 'Super Cool Plugin', // name of this plugin (matching your EDD Download title) - 'item_id' => (int) 10, - 'author' => 'Austin Passy', // author of this plugin - 'beta' => (bool) isset( $use_beta ), - ], - 'item_id' => (int) 10, - 'name' => plugin_basename( __FILE__ ), - 'slug' => basename( __FILE__, '.php' ), - 'version' => (string) $version, - 'wp_override' => false, - 'beta' => (bool) isset( $use_beta ), +$license = \get_option(\Dwnload\EddSoftwareLicenseManager\Edd\AbstractLicenceManager::LICENSE_SETTING, []); +$data = [ + 'license' => $license[$plugin_id]['license'] ?? '', + 'item_name' => 'Custom Login Style Pack #1', // Name of this plugin (matching your EDD Download title). + 'author' => 'Frosty Media', + 'item_id' => (int), + 'version' => '1.0.0', ]; - -if ( is_admin() ) { - ( new Init() ) - ->add( new PluginUpdater( $args ) - ->initialize(); -} +\TheFrosty\WpUtilities\Plugin\Plugin $plugin + ->add(new Edd\LicenseManager($plugin, $data)) + ->add(new Edd\PluginUpdater('https://frosty.media/', __FILE__, $data)) +->initialize(); ``` \ No newline at end of file diff --git a/assets/css/licensemanager.css b/assets/css/licensemanager.css index 2788fb9..8f2e0ef 100644 --- a/assets/css/licensemanager.css +++ b/assets/css/licensemanager.css @@ -1,28 +1,24 @@ -h2 span.license-status { - background-color: whitesmoke; - border: 1px solid; - font-size: 90%; - padding: 4px 6px; - border-radius: 2px; +div.EddSoftwareLicenseManager .license-status { } -h2 span.license-status.active { - background-color: #f6fef9; - border-color: #23d160; - color: #0e301a; +div.EddSoftwareLicenseManager .license-status.active { + color: #066226; + text-shadow: 1px 1px 1px rgba(20, 255, 0, 0.5); } -h2 span.license-status.inactive { - background-color: #fffdf5; - border-color: #ffdd57; - color: #3b3108; +div.EddSoftwareLicenseManager .license-status.inactive { + color: #886d03; + text-shadow: 1px 1px 1px rgba(255, 215, 0, 0.5); } -h2 span.license-status.expired, -h2 span.license-status.invalid { - background-color: #fff5f7; - border-color: #ff3860; - color: #cd0930; +div.EddSoftwareLicenseManager .license-status.expired, +div.EddSoftwareLicenseManager .license-status.invalid { + color: #990422; + text-shadow: 1px 1px 1px rgba(255, 37, 37, 0.5); +} + +div.EddSoftwareLicenseManager hr { + visibility: hidden; } img.EddLicenseLoader { diff --git a/assets/js/licensemanager.js b/assets/js/licensemanager.js index 7f7089a..dc0dddd 100644 --- a/assets/js/licensemanager.js +++ b/assets/js/licensemanager.js @@ -1,37 +1,42 @@ /* global jQuery, ajaxurl, EddLicenseManager */ (function ($) { - "use strict"; + 'use strict' - $(document).ready(function () { - $('input#EddSoftwareLicenseManagerButton').on('click', function (e) { - e.preventDefault(); - var $this = $(this), - img = 'EddLicenseLoader'; + $(document).ready(function () { + $('a[id^="EddSoftwareLicenseManagerButton"]:not(:disabled)').on('click', function (e) { + e.preventDefault() + const $this = $(this) + const $element = $('input[name$="[' + $this.data('plugin_id') + ']"]') - $.ajax({ - method: "POST", - url: ajaxurl, - data: { - action: EddLicenseManager.action, - license_key: $('input[name="'+ EddLicenseManager.license_attr +'"]').val(), - nonce: EddLicenseManager.nonce, - plugin_action: $this.prop('name') - }, - beforeSend: function () { - $this.attr('disabled', true); - $('').insertAfter($this); - }, - success: function (response) { - if (typeof response.success !== 'undefined' && response.success) { - location.reload(true); - } - $this.attr('disabled', false); - $('img[class="'+ img +'"]').remove(); - }, - fail: function () { - window.alert('Unknown Error'); - } - }); - }); - }); -}(jQuery)); \ No newline at end of file + if ($this.attr('disabled') === 'disabled' || $element.val().length === 0) { + return + } + + $.ajax({ + method: 'POST', + url: ajaxurl, + data: { + action: EddLicenseManager.action, + license_key: $element.val(), + nonce: EddLicenseManager.nonce, + plugin_action: $this.data('action'), + plugin_id: $this.data('plugin_id') + }, + beforeSend: function () { + $this.attr('disabled', true) + $('').insertAfter($this) + }, + success: function (response) { + if (typeof response.success !== 'undefined' && response.success) { + $this.closest('form').submit() + } + $('img[class="EddLicenseLoader"]').remove() + }, + fail: function (response) { + $this.attr('disabled', false) + window.alert(response) + } + }) + }) + }) +}(jQuery)) \ No newline at end of file diff --git a/composer.json b/composer.json index a6b43be..ce90f36 100755 --- a/composer.json +++ b/composer.json @@ -1,7 +1,6 @@ { "name": "dwnload/edd-software-license-manager", "description": "A PHP class abstraction for managing WordPress plugin licenses and auto-updates that are sold on an Easy Digital Downloads store.", - "version": "1.4.0", "license": "MIT", "authors": [ { @@ -11,15 +10,36 @@ "role": "Developer" } ], + "config": { + "allow-plugins": { + "composer/installers": true, + "dealerdirect/phpcodesniffer-composer-installer": true, + "roots/wordpress-core-installer": true + }, + "optimize-autoloader": true, + "platform": { + "php": "8.0" + }, + "preferred-install": "dist", + "sort-packages": true + }, "require": { - "composer/installers": "~1.0", - "dwnload/wp-settings-api": "^2.6.0", - "thefrosty/wp-utilities": "^1.3.1", - "php": ">=7.1" + "php": "^8.0", + "composer/installers": "~2.0", + "dwnload/wp-settings-api": "^3.9", + "thefrosty/wp-utilities": "^3.2" }, "require-dev": { - "10up/wp_mock": "dev-dev", - "wp-coding-standards/wpcs": "^0.9.0" + "ext-simplexml": "*", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/php-code-coverage": "^9", + "phpunit/phpunit": "^9", + "roots/wordpress": "^6.4", + "squizlabs/php_codesniffer": "^3.2", + "symfony/var-dumper": "^5.4 || ^6.2", + "wp-phpunit/wp-phpunit": "^6.3", + "yoast/phpunit-polyfills": "^2.0" }, "autoload": { "psr-4": { diff --git a/composer.lock b/composer.lock index 4b6fee6..980beb0 100644 --- a/composer.lock +++ b/composer.lock @@ -1,42 +1,44 @@ { "_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#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "a867798a244b5ba5a13507e6a23387f5", + "content-hash": "0c50383bc0b1bcebc9af9f7b7186d7ca", "packages": [ { "name": "composer/installers", - "version": "v1.6.0", + "version": "v2.2.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b" + "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/cfcca6b1b60bc4974324efb5783c13dca6932b5b", - "reference": "cfcca6b1b60bc4974324efb5783c13dca6932b5b", + "url": "https://api.github.com/repos/composer/installers/zipball/c29dc4b93137acb82734f672c37e029dfbd95b35", + "reference": "c29dc4b93137acb82734f672c37e029dfbd95b35", "shasum": "" }, "require": { - "composer-plugin-api": "^1.0" - }, - "replace": { - "roundcube/plugin-installer": "*", - "shama/baton": "*" + "composer-plugin-api": "^1.0 || ^2.0", + "php": "^7.2 || ^8.0" }, "require-dev": { - "composer/composer": "1.0.*@dev", - "phpunit/phpunit": "^4.8.36" + "composer/composer": "1.6.* || ^2.0", + "composer/semver": "^1 || ^3", + "phpstan/phpstan": "^0.12.55", + "phpstan/phpstan-phpunit": "^0.12.16", + "symfony/phpunit-bridge": "^5.3", + "symfony/process": "^5" }, "type": "composer-plugin", "extra": { "class": "Composer\\Installers\\Plugin", "branch-alias": { - "dev-master": "1.0-dev" - } + "dev-main": "2.x-dev" + }, + "plugin-modifies-install-path": true }, "autoload": { "psr-4": { @@ -57,7 +59,6 @@ "description": "A multi-framework Composer library installer", "homepage": "https://composer.github.io/installers/", "keywords": [ - "Craft", "Dolibarr", "Eliasis", "Hurad", @@ -65,6 +66,7 @@ "Kanboard", "Lan Management System", "MODX Evo", + "MantisBT", "Mautic", "Maya", "OXID", @@ -72,10 +74,11 @@ "Porto", "RadPHP", "SMF", + "Starbug", "Thelia", + "Whmcs", "WolfCMS", "agl", - "aimeos", "annotatecms", "attogram", "bitrix", @@ -94,7 +97,7 @@ "grav", "installer", "itop", - "joomla", + "known", "kohana", "laravel", "lavalite", @@ -102,14 +105,18 @@ "magento", "majima", "mako", + "matomo", "mediawiki", + "miaoxing", "modulework", "modx", "moodle", "osclass", + "pantheon", "phpbb", "piwik", "ppi", + "processwire", "puppet", "pxcms", "reindex", @@ -117,40 +124,68 @@ "shopware", "silverstripe", "sydes", - "symfony", - "typo3", + "sylius", + "tastyigniter", "wordpress", "yawik", "zend", "zikula" ], - "time": "2018-08-27T06:10:37+00:00" + "support": { + "issues": "https://github.com/composer/installers/issues", + "source": "https://github.com/composer/installers/tree/v2.2.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": "2022-08-20T06:45:11+00:00" }, { "name": "dwnload/wp-settings-api", - "version": "2.6.0", + "version": "v3.10.0", "source": { "type": "git", "url": "https://github.com/dwnload/WpSettingsApi.git", - "reference": "639d0b8d2713a001f670bb6811a6100d40a45867" + "reference": "a38cd495aa3ef7c5c819ab6af28c069935c68071" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dwnload/WpSettingsApi/zipball/639d0b8d2713a001f670bb6811a6100d40a45867", - "reference": "639d0b8d2713a001f670bb6811a6100d40a45867", + "url": "https://api.github.com/repos/dwnload/WpSettingsApi/zipball/a38cd495aa3ef7c5c819ab6af28c069935c68071", + "reference": "a38cd495aa3ef7c5c819ab6af28c069935c68071", "shasum": "" }, "require": { - "composer/installers": "~1.0", - "php": ">=7.0.4", - "thefrosty/wp-utilities": "^1.2" + "ext-json": "*", + "php": "^8.0", + "thefrosty/wp-utilities": "^3.0" }, "require-dev": { - "10up/wp_mock": "dev-dev", - "inpsyde/php-coding-standards": "^0.13.3", - "phpmd/phpmd": "^2.6", - "phpunit/phpunit": "6.*", - "wp-phpunit/wp-phpunit": "4.9.*" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "ext-simplexml": "*", + "inpsyde/php-coding-standards": "^1.0", + "phpcompatibility/php-compatibility": "*", + "phpunit/php-code-coverage": "^9", + "phpunit/phpunit": "^9", + "roave/security-advisories": "dev-master", + "roots/wordpress": "~6.2", + "slevomat/coding-standard": "~8.12", + "squizlabs/php_codesniffer": "^3.2", + "wp-phpunit/wp-phpunit": "~6.2", + "yoast/phpunit-polyfills": "^1.0.2 || ^2.0" + }, + "suggest": { + "frontpack/composer-assets-plugin": "Composer plugin for copying of frontend assets into public directory." }, "type": "library", "autoload": { @@ -171,173 +206,284 @@ } ], "description": "A PHP class abstraction that removes all the headaches of the WordPress settings API under the hood and builds a nice options panel on the fly.", - "time": "2018-11-21T21:13:22+00:00" + "support": { + "issues": "https://github.com/dwnload/WpSettingsApi/issues", + "source": "https://github.com/dwnload/WpSettingsApi/tree/v3.10.0" + }, + "time": "2023-11-10T23:23:07+00:00" }, { - "name": "thefrosty/wp-utilities", - "version": "1.3.1", + "name": "johnbillion/args", + "version": "1.9.0", "source": { "type": "git", - "url": "https://github.com/thefrosty/wp-utilities.git", - "reference": "cd619f8d1f7fd7bf998b0ba97a892dc0384a7c0f" + "url": "https://github.com/johnbillion/args.git", + "reference": "78dd8408f61960784982fb55efd8b1bc88d4584c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thefrosty/wp-utilities/zipball/cd619f8d1f7fd7bf998b0ba97a892dc0384a7c0f", - "reference": "cd619f8d1f7fd7bf998b0ba97a892dc0384a7c0f", + "url": "https://api.github.com/repos/johnbillion/args/zipball/78dd8408f61960784982fb55efd8b1bc88d4584c", + "reference": "78dd8408f61960784982fb55efd8b1bc88d4584c", "shasum": "" }, "require": { - "php": ">=7.0" + "php": ">=7.4" }, "require-dev": { - "phpmd/phpmd": "^2.6", - "phpunit/phpunit": "^6.5", - "squizlabs/php_codesniffer": "^3.2" - }, - "suggest": { - "pimple/pimple": "", - "symfony/http-foundation": "" + "ergebnis/json-printer": "^3.2", + "ergebnis/phpstan-rules": "^1.0", + "humanmade/coding-standards": "^1.1", + "johnbillion/falsey-assertequals-detector": "^3", + "phpdocumentor/reflection": "~4.0 || ~5.0", + "phpstan/phpstan": "^1.0", + "phpstan/phpstan-phpunit": "^1.0", + "phpstan/phpstan-strict-rules": "^1.1", + "phpunit/phpunit": "^9.0", + "roots/wordpress-core-installer": "^1.0.0", + "roots/wordpress-full": "~6.4.0" }, "type": "library", + "extra": { + "args-shapes": [ + "--function=\"\\get_categories()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category.php", + "--function=\"\\get_comments()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/comment.php", + "--function=\"\\get_posts()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\get_tags()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category.php", + "--function=\"\\get_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\get_users()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/user.php", + "--function=\"\\paginate_links()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/general-template.php", + "--function=\"\\register_block_type()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/blocks.php", + "--function=\"\\register_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/meta.php", + "--function=\"\\register_post_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\register_post_status()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\register_post_type()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\register_rest_field()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/rest-api.php", + "--function=\"\\register_taxonomy()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\register_term_meta()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\wp_count_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\wp_die()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/functions.php", + "--function=\"\\wp_dropdown_categories()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category-template.php", + "--function=\"\\wp_dropdown_languages()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/l10n.php", + "--function=\"\\wp_generate_tag_cloud()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/category-template.php", + "--function=\"\\wp_get_nav_menus()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/nav-menu.php", + "--function=\"\\wp_get_object_terms()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\wp_insert_post()\" --param=postarr --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\wp_insert_term()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\wp_insert_user()\" --param=userdata --file=vendor/wordpress/wordpress/wp-includes/user.php", + "--function=\"\\wp_nav_menu()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/nav-menu-template.php", + "--function=\"\\wp_remote_get()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_remote_head()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_remote_post()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_remote_request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_safe_remote_get()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_safe_remote_head()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_safe_remote_post()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_safe_remote_request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/http.php", + "--function=\"\\wp_update_post()\" --param=postarr --file=vendor/wordpress/wordpress/wp-includes/post.php", + "--function=\"\\wp_update_term()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/taxonomy.php", + "--function=\"\\wp_update_user()\" --param=userdata --file=vendor/wordpress/wordpress/wp-includes/user.php", + "--method=\"\\WP_Block_Type::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-block-type.php", + "--method=\"\\WP_Comment_Query::__construct()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-comment-query.php", + "--method=\"\\WP_Customize_Control::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-control.php", + "--method=\"\\WP_Customize_Manager::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-manager.php", + "--method=\"\\WP_Customize_Panel::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-panel.php", + "--method=\"\\WP_Customize_Section::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-section.php", + "--method=\"\\WP_Customize_Setting::__construct()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-customize-setting.php", + "--method=\"\\WP_Http::request()\" --param=args --file=vendor/wordpress/wordpress/wp-includes/class-wp-http.php", + "--method=\"\\WP_Query::parse_query()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-query.php", + "--method=\"\\WP_Term_Query::__construct()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-term-query.php", + "--method=\"\\WP_User_Query::prepare_query()\" --param=query --file=vendor/wordpress/wordpress/wp-includes/class-wp-user-query.php" + ], + "wordpress-install-dir": "vendor/wordpress/wordpress" + }, "autoload": { "psr-4": { - "TheFrosty\\WpUtilities\\": "src/" + "Args\\": "src/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "GPL-2.0-or-later" ], "authors": [ { - "name": "Austin Passy", - "email": "thefrosty@users.noreply.github.com", - "homepage": "https://austin.passy.co", - "role": "Developer" + "name": "John Blackbourn", + "homepage": "https://johnblackbourn.com/" } ], - "description": "A library containing my standard development resources", - "time": "2019-01-07T21:23:39+00:00" - } - ], - "packages-dev": [ + "description": "I don't want to get into an argument about this.", + "support": { + "issues": "https://github.com/johnbillion/args/issues", + "source": "https://github.com/johnbillion/args/tree/1.9.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/johnbillion", + "type": "github" + } + ], + "time": "2023-11-07T23:51:42+00:00" + }, { - "name": "10up/wp_mock", - "version": "dev-dev", + "name": "psr/container", + "version": "2.0.2", "source": { "type": "git", - "url": "https://github.com/10up/wp_mock.git", - "reference": "0354413d63cbae920ffc0676443c6d9dd330ce40" + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/10up/wp_mock/zipball/0354413d63cbae920ffc0676443c6d9dd330ce40", - "reference": "0354413d63cbae920ffc0676443c6d9dd330ce40", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", "shasum": "" }, "require": { - "antecedent/patchwork": "^2.1", - "mockery/mockery": "^1.0", - "php": ">=7.0", - "phpunit/phpunit": ">=6.0" - }, - "require-dev": { - "behat/behat": "^3.0", - "satooshi/php-coveralls": "^1.0", - "sebastian/comparator": ">=1.2.3" + "php": ">=7.4.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, "autoload": { "psr-4": { - "WP_Mock\\": "./php/WP_Mock" - }, - "classmap": [ - "php/WP_Mock.php" - ] + "Psr\\Container\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "GPL-2.0+" + "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" ], - "description": "A mocking library to take the pain out of unit testing for WordPress", - "time": "2017-12-03T19:27:57+00:00" + "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": "antecedent/patchwork", - "version": "2.1.8", + "name": "symfony/deprecation-contracts", + "version": "v2.5.2", "source": { "type": "git", - "url": "https://github.com/antecedent/patchwork.git", - "reference": "3bb81ace3914c220aa273d1c0603d5e1b454c0d7" + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/antecedent/patchwork/zipball/3bb81ace3914c220aa273d1c0603d5e1b454c0d7", - "reference": "3bb81ace3914c220aa273d1c0603d5e1b454c0d7", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/e8b495ea28c1d97b5e0c121748d6f9b53d075c66", + "reference": "e8b495ea28c1d97b5e0c121748d6f9b53d075c66", "shasum": "" }, "require": { - "php": ">=5.4.0" + "php": ">=7.1" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.5-dev" + }, + "thanks": { + "name": "symfony/contracts", + "url": "https://github.com/symfony/contracts" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], "authors": [ { - "name": "Ignas Rudaitis", - "email": "ignas.rudaitis@gmail.com" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Method redefinition (monkey-patching) functionality for PHP.", - "homepage": "http://patchwork2.org/", - "keywords": [ - "aop", - "aspect", - "interception", - "monkeypatching", - "redefinition", - "runkit", - "testing" + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v2.5.2" + }, + "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": "2018-02-19T18:52:50+00:00" + "time": "2022-01-02T09:53:40+00:00" }, { - "name": "doctrine/instantiator", - "version": "1.1.0", + "name": "symfony/http-foundation", + "version": "v5.4.31", "source": { "type": "git", - "url": "https://github.com/doctrine/instantiator.git", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda" + "url": "https://github.com/symfony/http-foundation.git", + "reference": "f84fd4fd8311a541ceb2ae3f257841d002450a90" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/instantiator/zipball/185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", - "reference": "185b8868aa9bf7159f5f953ed5afb2d7fcdc3bda", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/f84fd4fd8311a541ceb2ae3f257841d002450a90", + "reference": "f84fd4fd8311a541ceb2ae3f257841d002450a90", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.2.5", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "athletic/athletic": "~0.1.8", - "ext-pdo": "*", - "ext-phar": "*", - "phpunit/phpunit": "^6.2.3", - "squizlabs/php_codesniffer": "^3.0.2" + "predis/predis": "~1.0", + "symfony/cache": "^4.4|^5.0|^6.0", + "symfony/dependency-injection": "^5.4|^6.0", + "symfony/expression-language": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", + "symfony/mime": "^4.4|^5.0|^6.0", + "symfony/rate-limiter": "^5.2|^6.0" }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.2.x-dev" - } + "suggest": { + "symfony/mime": "To use the file extension guesser" }, + "type": "library", "autoload": { "psr-4": { - "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" - } + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -345,533 +491,748 @@ ], "authors": [ { - "name": "Marco Pivetta", - "email": "ocramius@gmail.com", - "homepage": "http://ocramius.github.com/" + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", - "homepage": "https://github.com/doctrine/instantiator", - "keywords": [ - "constructor", - "instantiate" + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v5.4.31" + }, + "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": "2017-07-22T11:58:36+00:00" + "time": "2023-11-06T22:05:57+00:00" }, { - "name": "hamcrest/hamcrest-php", - "version": "v2.0.0", + "name": "symfony/polyfill-mbstring", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/hamcrest/hamcrest-php.git", - "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad" + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "42292d99c55abe617799667f454222c54c60e229" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/776503d3a8e85d4f9a1148614f95b7a608b046ad", - "reference": "776503d3a8e85d4f9a1148614f95b7a608b046ad", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229", + "reference": "42292d99c55abe617799667f454222c54c60e229", "shasum": "" }, "require": { - "php": "^5.3|^7.0" + "php": ">=7.1" }, - "replace": { - "cordoval/hamcrest-php": "*", - "davedevelopment/hamcrest-php": "*", - "kodova/hamcrest-php": "*" + "provide": { + "ext-mbstring": "*" }, - "require-dev": { - "phpunit/php-file-iterator": "1.3.3", - "phpunit/phpunit": "~4.0", - "satooshi/php-coveralls": "^1.0" + "suggest": { + "ext-mbstring": "For best performance" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { - "classmap": [ - "hamcrest" - ] + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD" + "MIT" ], - "description": "This is the PHP port of Hamcrest Matchers", + "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": [ - "test" + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.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": "2016-01-20T08:20:44+00:00" + "time": "2023-07-28T09:04:16+00:00" }, { - "name": "mockery/mockery", - "version": "1.2.0", + "name": "symfony/polyfill-php80", + "version": "v1.28.0", "source": { "type": "git", - "url": "https://github.com/mockery/mockery.git", - "reference": "100633629bf76d57430b86b7098cd6beb996a35a" + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mockery/mockery/zipball/100633629bf76d57430b86b7098cd6beb996a35a", - "reference": "100633629bf76d57430b86b7098cd6beb996a35a", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/6caa57379c4aec19c0a12a38b59b26487dcfe4b5", + "reference": "6caa57379c4aec19c0a12a38b59b26487dcfe4b5", "shasum": "" }, "require": { - "hamcrest/hamcrest-php": "~2.0", - "lib-pcre": ">=7.0", - "php": ">=5.6.0" - }, - "require-dev": { - "phpunit/phpunit": "~5.7.10|~6.5|~7.0" + "php": ">=7.1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-main": "1.28-dev" + }, + "thanks": { + "name": "symfony/polyfill", + "url": "https://github.com/symfony/polyfill" } }, "autoload": { - "psr-0": { - "Mockery": "library/" - } + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Pádraic Brady", - "email": "padraic.brady@gmail.com", - "homepage": "http://blog.astrumfutura.com" + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" }, { - "name": "Dave Marshall", - "email": "dave.marshall@atstsolutions.co.uk", - "homepage": "http://davedevelopment.co.uk" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Mockery is a simple yet flexible PHP mock object framework", - "homepage": "https://github.com/mockery/mockery", + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", "keywords": [ - "BDD", - "TDD", - "library", - "mock", - "mock objects", - "mockery", - "stub", - "test", - "test double", - "testing" + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.28.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": "2018-10-02T21:52:37+00:00" + "time": "2023-01-26T09:26:14+00:00" }, { - "name": "myclabs/deep-copy", - "version": "1.8.1", + "name": "thefrosty/wp-utilities", + "version": "v3.2.5", "source": { "type": "git", - "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8" + "url": "https://github.com/thefrosty/wp-utilities.git", + "reference": "9c740dbe4563abbffc27511fa0f135e81cc94609" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", - "reference": "3e01bdad3e18354c3dce54466b7fbe33a9f9f7f8", + "url": "https://api.github.com/repos/thefrosty/wp-utilities/zipball/9c740dbe4563abbffc27511fa0f135e81cc94609", + "reference": "9c740dbe4563abbffc27511fa0f135e81cc94609", "shasum": "" }, "require": { - "php": "^7.1" - }, - "replace": { - "myclabs/deep-copy": "self.version" + "ext-json": "*", + "ext-openssl": "*", + "johnbillion/args": "^1.1", + "php": "^8.0 || ^8.1 || ^8.2", + "psr/container": "^1.0 || ^2.0", + "symfony/http-foundation": "^5.2 || ~6.0" }, "require-dev": { - "doctrine/collections": "^1.0", - "doctrine/common": "^2.6", - "phpunit/phpunit": "^7.1" + "dealerdirect/phpcodesniffer-composer-installer": "^1.0.0", + "ext-simplexml": "*", + "phpcompatibility/php-compatibility": "^9.3", + "phpmd/phpmd": "^2.13", + "phpunit/php-code-coverage": "^9.2", + "phpunit/phpunit": "^9", + "pimple/pimple": "^3.5", + "roots/wordpress": "^6.2", + "slevomat/coding-standard": "^8.8", + "squizlabs/php_codesniffer": "^3.7", + "szepeviktor/phpstan-wordpress": "^1.0", + "wp-coding-standards/wpcs": "dev-develop", + "wp-phpunit/wp-phpunit": "^6.2", + "yoast/phpunit-polyfills": "^1.0.5 || ^2.0" + }, + "suggest": { + "jjgrainger/posttypes": "Simple WordPress custom post types." }, "type": "library", "autoload": { - "psr-4": { - "DeepCopy\\": "src/DeepCopy/" - }, "files": [ - "src/DeepCopy/deep_copy.php" - ] + "src/functions.php" + ], + "psr-4": { + "TheFrosty\\WpUtilities\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "description": "Create deep copies (clones) of your objects", - "keywords": [ - "clone", - "copy", - "duplicate", - "object", - "object graph" + "authors": [ + { + "name": "Austin Passy", + "email": "thefrosty@users.noreply.github.com", + "homepage": "https://austin.passy.co", + "role": "Developer" + } ], - "time": "2018-06-11T23:09:50+00:00" - }, + "description": "A library containing my standard development resources", + "support": { + "issues": "https://github.com/thefrosty/wp-utilities/issues", + "source": "https://github.com/thefrosty/wp-utilities/tree/v3.2.5" + }, + "time": "2023-11-01T21:30:28+00:00" + } + ], + "packages-dev": [ { - "name": "phar-io/manifest", - "version": "1.0.3", + "name": "dealerdirect/phpcodesniffer-composer-installer", + "version": "v1.0.0", "source": { "type": "git", - "url": "https://github.com/phar-io/manifest.git", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4" + "url": "https://github.com/PHPCSStandards/composer-installer.git", + "reference": "4be43904336affa5c2f70744a348312336afd0da" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/manifest/zipball/7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", - "reference": "7761fcacf03b4d4f16e7ccb606d4879ca431fcf4", + "url": "https://api.github.com/repos/PHPCSStandards/composer-installer/zipball/4be43904336affa5c2f70744a348312336afd0da", + "reference": "4be43904336affa5c2f70744a348312336afd0da", "shasum": "" }, "require": { - "ext-dom": "*", - "ext-phar": "*", - "phar-io/version": "^2.0", - "php": "^5.6 || ^7.0" + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^2.0 || ^3.1.0 || ^4.0" }, - "type": "library", + "require-dev": { + "composer/composer": "*", + "ext-json": "*", + "ext-zip": "*", + "php-parallel-lint/php-parallel-lint": "^1.3.1", + "phpcompatibility/php-compatibility": "^9.0", + "yoast/phpunit-polyfills": "^1.0" + }, + "type": "composer-plugin", "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } + "class": "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin" }, "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "PHPCSStandards\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\": "src/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" - }, - { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "name": "Franck Nijhof", + "email": "franck.nijhof@dealerdirect.com", + "homepage": "http://www.frenck.nl", + "role": "Developer / IT Manager" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/composer-installer/graphs/contributors" } ], - "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", - "time": "2018-07-08T19:23:20+00:00" + "description": "PHP_CodeSniffer Standards Composer Installer Plugin", + "homepage": "http://www.dealerdirect.com", + "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", + "source": "https://github.com/PHPCSStandards/composer-installer" + }, + "time": "2023-01-05T11:28:13+00:00" }, { - "name": "phar-io/version", - "version": "2.0.1", + "name": "doctrine/instantiator", + "version": "1.5.0", "source": { "type": "git", - "url": "https://github.com/phar-io/version.git", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6" + "url": "https://github.com/doctrine/instantiator.git", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phar-io/version/zipball/45a2ec53a73c70ce41d55cedef9063630abaf1b6", - "reference": "45a2ec53a73c70ce41d55cedef9063630abaf1b6", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/0a0fa9780f5d4e507415a065172d26a98d02047b", + "reference": "0a0fa9780f5d4e507415a065172d26a98d02047b", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^9 || ^11", + "ext-pdo": "*", + "ext-phar": "*", + "phpbench/phpbench": "^0.16 || ^1", + "phpstan/phpstan": "^1.4", + "phpstan/phpstan-phpunit": "^1", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5", + "vimeo/psalm": "^4.30 || ^5.4" }, "type": "library", "autoload": { - "classmap": [ - "src/" - ] + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "BSD-3-Clause" + "MIT" ], "authors": [ { - "name": "Arne Blankerts", - "email": "arne@blankerts.de", - "role": "Developer" + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "https://ocramius.github.io/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://www.doctrine-project.org/projects/instantiator.html", + "keywords": [ + "constructor", + "instantiate" + ], + "support": { + "issues": "https://github.com/doctrine/instantiator/issues", + "source": "https://github.com/doctrine/instantiator/tree/1.5.0" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" }, { - "name": "Sebastian Heuer", - "email": "sebastian@phpeople.de", - "role": "Developer" + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" }, { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de", - "role": "Developer" + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finstantiator", + "type": "tidelift" } ], - "description": "Library for handling version information and constraints", - "time": "2018-07-08T19:19:57+00:00" + "time": "2022-12-30T00:15:36+00:00" }, { - "name": "phpdocumentor/reflection-common", - "version": "1.0.1", + "name": "myclabs/deep-copy", + "version": "1.11.1", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionCommon.git", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6" + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", - "reference": "21bdeb5f65d7ebf9f43b1b25d404f87deab5bfb6", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", + "reference": "7284c22080590fb39f2ffa3e9057f10a4ddd0e0c", "shasum": "" }, "require": { - "php": ">=5.5" + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3,<3.2.2" }, "require-dev": { - "phpunit/phpunit": "^4.6" + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.0.x-dev" - } - }, "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src" - ] + "DeepCopy\\": "src/DeepCopy/" } }, "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], - "authors": [ + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.11.1" + }, + "funding": [ { - "name": "Jaap van Otterdijk", - "email": "opensource@ijaap.nl" + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" } ], - "description": "Common reflection classes used by phpdocumentor to reflect the code structure", - "homepage": "http://www.phpdoc.org", - "keywords": [ - "FQSEN", - "phpDocumentor", - "phpdoc", - "reflection", - "static analysis" - ], - "time": "2017-09-11T18:02:19+00:00" + "time": "2023-03-08T13:26:56+00:00" }, { - "name": "phpdocumentor/reflection-docblock", - "version": "4.3.0", + "name": "nikic/php-parser", + "version": "v4.17.1", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08" + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94fd0001232e47129dd3504189fa1c7225010d08", - "reference": "94fd0001232e47129dd3504189fa1c7225010d08", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", + "reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d", "shasum": "" }, "require": { - "php": "^7.0", - "phpdocumentor/reflection-common": "^1.0.0", - "phpdocumentor/type-resolver": "^0.4.0", - "webmozart/assert": "^1.0" + "ext-tokenizer": "*", + "php": ">=7.0" }, "require-dev": { - "doctrine/instantiator": "~1.0.5", - "mockery/mockery": "^1.0", - "phpunit/phpunit": "^6.4" + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^6.5 || ^7.0 || ^8.0 || ^9.0" }, + "bin": [ + "bin/php-parse" + ], "type": "library", "extra": { "branch-alias": { - "dev-master": "4.x-dev" + "dev-master": "4.9-dev" } }, "autoload": { "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] + "PhpParser\\": "lib/PhpParser" } }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "Nikita Popov" } ], - "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", - "time": "2017-11-30T07:14:17+00:00" + "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.17.1" + }, + "time": "2023-08-13T19:53:39+00:00" }, { - "name": "phpdocumentor/type-resolver", - "version": "0.4.0", + "name": "phar-io/manifest", + "version": "2.0.3", "source": { "type": "git", - "url": "https://github.com/phpDocumentor/TypeResolver.git", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7" + "url": "https://github.com/phar-io/manifest.git", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/9c977708995954784726e25d0cd1dddf4e65b0f7", - "reference": "9c977708995954784726e25d0cd1dddf4e65b0f7", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/97803eca37d319dfa7826cc2437fc020857acb53", + "reference": "97803eca37d319dfa7826cc2437fc020857acb53", "shasum": "" }, "require": { - "php": "^5.5 || ^7.0", - "phpdocumentor/reflection-common": "^1.0" - }, - "require-dev": { - "mockery/mockery": "^0.9.4", - "phpunit/phpunit": "^5.2||^4.8.24" + "ext-dom": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { - "psr-4": { - "phpDocumentor\\Reflection\\": [ - "src/" - ] - } + "classmap": [ + "src/" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ { - "name": "Mike van Riel", - "email": "me@mikevanriel.com" + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } ], - "time": "2017-07-14T14:27:02+00:00" + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.3" + }, + "time": "2021-07-20T11:28:43+00:00" }, { - "name": "phpspec/prophecy", - "version": "1.8.0", + "name": "phar-io/version", + "version": "3.2.1", "source": { "type": "git", - "url": "https://github.com/phpspec/prophecy.git", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06" + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpspec/prophecy/zipball/4ba436b55987b4bf311cb7c6ba82aa528aac0a06", - "reference": "4ba436b55987b4bf311cb7c6ba82aa528aac0a06", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.0.2", - "php": "^5.3|^7.0", - "phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0", - "sebastian/comparator": "^1.1|^2.0|^3.0", - "sebastian/recursion-context": "^1.0|^2.0|^3.0" - }, - "require-dev": { - "phpspec/phpspec": "^2.5|^3.2", - "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5 || ^7.1" + "php": "^7.2 || ^8.0" }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.8.x-dev" - } - }, "autoload": { - "psr-0": { - "Prophecy\\": "src/" + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04: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": [ - "MIT" + "LGPL-3.0-or-later" ], "authors": [ { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" + "name": "Wim Godden", + "homepage": "https://github.com/wimg", + "role": "lead" }, { - "name": "Marcello Duarte", - "email": "marcello.duarte@gmail.com" + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCompatibility/PHPCompatibility/graphs/contributors" } ], - "description": "Highly opinionated mocking framework for PHP 5.3+", - "homepage": "https://github.com/phpspec/prophecy", + "description": "A set of sniffs for PHP_CodeSniffer that checks for PHP cross-version compatibility.", + "homepage": "http://techblog.wimgodden.be/tag/codesniffer/", "keywords": [ - "Double", - "Dummy", - "fake", - "mock", - "spy", - "stub" - ], - "time": "2018-08-05T17:53:17+00:00" + "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": "phpunit/php-code-coverage", - "version": "6.1.4", + "version": "9.2.29", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-code-coverage.git", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d" + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", - "reference": "807e6013b00af69b6c5d9ceb4282d0393dbb9d8d", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76", + "reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76", "shasum": "" }, "require": { "ext-dom": "*", + "ext-libxml": "*", "ext-xmlwriter": "*", - "php": "^7.1", - "phpunit/php-file-iterator": "^2.0", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-token-stream": "^3.0", - "sebastian/code-unit-reverse-lookup": "^1.0.1", - "sebastian/environment": "^3.1 || ^4.0", - "sebastian/version": "^2.0.1", - "theseer/tokenizer": "^1.1" + "nikic/php-parser": "^4.15", + "php": ">=7.3", + "phpunit/php-file-iterator": "^3.0.3", + "phpunit/php-text-template": "^2.0.2", + "sebastian/code-unit-reverse-lookup": "^2.0.2", + "sebastian/complexity": "^2.0", + "sebastian/environment": "^5.1.2", + "sebastian/lines-of-code": "^1.0.3", + "sebastian/version": "^3.0.1", + "theseer/tokenizer": "^1.2.0" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.3" }, "suggest": { - "ext-xdebug": "^2.6.0" + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "6.1-dev" + "dev-master": "9.2-dev" } }, "autoload": { @@ -897,32 +1258,43 @@ "testing", "xunit" ], - "time": "2018-10-31T16:06:48+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-09-19T04:57:46+00:00" }, { "name": "phpunit/php-file-iterator", - "version": "2.0.2", + "version": "3.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/php-file-iterator.git", - "reference": "050bedf145a257b1ff02746c31894800e5122946" + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/050bedf145a257b1ff02746c31894800e5122946", - "reference": "050bedf145a257b1ff02746c31894800e5122946", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", + "reference": "cf1c2e7c203ac650e352f4cc675a7021e7d1b3cf", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -947,26 +1319,48 @@ "filesystem", "iterator" ], - "time": "2018-09-13T20:33:42+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/3.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2021-12-02T12:48:52+00:00" }, { - "name": "phpunit/php-text-template", - "version": "1.2.1", + "name": "phpunit/php-invoker", + "version": "3.1.1", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-text-template.git", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", - "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/5a10147d0aaf65b58940a0b72f71c9ac0423cc67", + "reference": "5a10147d0aaf65b58940a0b72f71c9ac0423cc67", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^9.3" + }, + "suggest": { + "ext-pcntl": "*" }, "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.1-dev" + } + }, "autoload": { "classmap": [ "src/" @@ -983,32 +1377,42 @@ "role": "lead" } ], - "description": "Simple template engine.", - "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", "keywords": [ - "template" + "process" ], - "time": "2015-06-21T13:50:34+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/3.1.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:58:55+00:00" }, { - "name": "phpunit/php-timer", - "version": "2.0.0", + "name": "phpunit/php-text-template", + "version": "2.0.4", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-timer.git", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f" + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/8b8454ea6958c3dee38453d3bd571e023108c91f", - "reference": "8b8454ea6958c3dee38453d3bd571e023108c91f", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", + "reference": "5da5f67fc95621df9ff4c4e5a84d6a8a2acf7c28", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { @@ -1032,38 +1436,47 @@ "role": "lead" } ], - "description": "Utility class for timing", - "homepage": "https://github.com/sebastianbergmann/php-timer/", + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", "keywords": [ - "timer" + "template" ], - "time": "2018-02-01T13:07:23+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T05:33:50+00:00" }, { - "name": "phpunit/php-token-stream", - "version": "3.0.1", + "name": "phpunit/php-timer", + "version": "5.0.3", "source": { "type": "git", - "url": "https://github.com/sebastianbergmann/php-token-stream.git", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18" + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/c99e3be9d3e85f60646f152f9002d46ed7770d18", - "reference": "c99e3be9d3e85f60646f152f9002d46ed7770d18", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", + "reference": "5a63ce20ed1b5bf577850e2c4e87f4aa902afbd2", "shasum": "" }, "require": { - "ext-tokenizer": "*", - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1078,65 +1491,73 @@ "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Wrapper around PHP's tokenizer extension.", - "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", "keywords": [ - "tokenizer" + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "source": "https://github.com/sebastianbergmann/php-timer/tree/5.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2018-10-30T05:52:18+00:00" + "time": "2020-10-26T13:16:10+00:00" }, { "name": "phpunit/phpunit", - "version": "7.5.3", + "version": "9.6.13", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "2cb759721e53bc05f56487f628c6b9fbb6c18746" + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2cb759721e53bc05f56487f628c6b9fbb6c18746", - "reference": "2cb759721e53bc05f56487f628c6b9fbb6c18746", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f3d767f7f9e191eab4189abe41ab37797e30b1be", + "reference": "f3d767f7f9e191eab4189abe41ab37797e30b1be", "shasum": "" }, "require": { - "doctrine/instantiator": "^1.1", + "doctrine/instantiator": "^1.3.1 || ^2", "ext-dom": "*", "ext-json": "*", "ext-libxml": "*", "ext-mbstring": "*", "ext-xml": "*", - "myclabs/deep-copy": "^1.7", - "phar-io/manifest": "^1.0.2", - "phar-io/version": "^2.0", - "php": "^7.1", - "phpspec/prophecy": "^1.7", - "phpunit/php-code-coverage": "^6.0.7", - "phpunit/php-file-iterator": "^2.0.1", - "phpunit/php-text-template": "^1.2.1", - "phpunit/php-timer": "^2.0", - "sebastian/comparator": "^3.0", - "sebastian/diff": "^3.0", - "sebastian/environment": "^4.0", - "sebastian/exporter": "^3.1", - "sebastian/global-state": "^2.0", - "sebastian/object-enumerator": "^3.0.3", - "sebastian/resource-operations": "^2.0", - "sebastian/version": "^2.0.1" - }, - "conflict": { - "phpunit/phpunit-mock-objects": "*" - }, - "require-dev": { - "ext-pdo": "*" + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.10.1", + "phar-io/manifest": "^2.0.3", + "phar-io/version": "^3.0.2", + "php": ">=7.3", + "phpunit/php-code-coverage": "^9.2.28", + "phpunit/php-file-iterator": "^3.0.5", + "phpunit/php-invoker": "^3.1.1", + "phpunit/php-text-template": "^2.0.3", + "phpunit/php-timer": "^5.0.2", + "sebastian/cli-parser": "^1.0.1", + "sebastian/code-unit": "^1.0.6", + "sebastian/comparator": "^4.0.8", + "sebastian/diff": "^4.0.3", + "sebastian/environment": "^5.1.3", + "sebastian/exporter": "^4.0.5", + "sebastian/global-state": "^5.0.1", + "sebastian/object-enumerator": "^4.0.3", + "sebastian/resource-operations": "^3.0.3", + "sebastian/type": "^3.2", + "sebastian/version": "^3.0.2" }, "suggest": { - "ext-soap": "*", - "ext-xdebug": "*", - "phpunit/php-invoker": "^2.0" + "ext-soap": "To be able to generate mocks based on WSDL files", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" }, "bin": [ "phpunit" @@ -1144,10 +1565,13 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "7.5-dev" + "dev-master": "9.6-dev" } }, "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], "classmap": [ "src/" ] @@ -1170,32 +1594,347 @@ "testing", "xunit" ], - "time": "2019-02-01T05:24:07+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.13" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2023-09-19T05:39:22+00:00" }, { - "name": "sebastian/code-unit-reverse-lookup", + "name": "roots/wordpress", + "version": "6.4.1", + "source": { + "type": "git", + "url": "https://github.com/roots/wordpress.git", + "reference": "41ff6e23ccbc3a1691406d69fe8c211a225514e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/roots/wordpress/zipball/41ff6e23ccbc3a1691406d69fe8c211a225514e2", + "reference": "41ff6e23ccbc3a1691406d69fe8c211a225514e2", + "shasum": "" + }, + "require": { + "roots/wordpress-core-installer": "^1.0.0", + "roots/wordpress-no-content": "self.version" + }, + "type": "metapackage", + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT", + "GPL-2.0-or-later" + ], + "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": { + "issues": "https://github.com/roots/wordpress/issues", + "source": "https://github.com/roots/wordpress/tree/6.4.1" + }, + "funding": [ + { + "url": "https://github.com/roots", + "type": "github" + } + ], + "time": "2022-06-01T16:54:37+00:00" + }, + { + "name": "roots/wordpress-core-installer", + "version": "1.100.0", + "source": { + "type": "git", + "url": "https://github.com/roots/wordpress-core-installer.git", + "reference": "73f8488e5178c5d54234b919f823a9095e2b1847" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/roots/wordpress-core-installer/zipball/73f8488e5178c5d54234b919f823a9095e2b1847", + "reference": "73f8488e5178c5d54234b919f823a9095e2b1847", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0 || ^2.0", + "php": ">=5.6.0" + }, + "conflict": { + "composer/installers": "<1.0.6" + }, + "replace": { + "johnpbloch/wordpress-core-installer": "*" + }, + "require-dev": { + "composer/composer": "^1.0 || ^2.0", + "phpunit/phpunit": ">=5.7.27" + }, + "type": "composer-plugin", + "extra": { + "class": "Roots\\Composer\\WordPressCorePlugin" + }, + "autoload": { + "psr-4": { + "Roots\\Composer\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "GPL-2.0-or-later" + ], + "authors": [ + { + "name": "John P. Bloch", + "email": "me@johnpbloch.com" + }, + { + "name": "Roots", + "email": "team@roots.io" + } + ], + "description": "A custom installer to handle deploying WordPress with composer", + "keywords": [ + "wordpress" + ], + "support": { + "issues": "https://github.com/roots/wordpress-core-installer/issues", + "source": "https://github.com/roots/wordpress-core-installer/tree/master" + }, + "funding": [ + { + "url": "https://github.com/roots", + "type": "github" + }, + { + "url": "https://www.patreon.com/rootsdev", + "type": "patreon" + } + ], + "time": "2020-08-20T00:27:30+00:00" + }, + { + "name": "roots/wordpress-no-content", + "version": "6.4.1", + "source": { + "type": "git", + "url": "https://github.com/WordPress/WordPress.git", + "reference": "6.4.1" + }, + "dist": { + "type": "zip", + "url": "https://downloads.wordpress.org/release/wordpress-6.4.1-no-content.zip", + "shasum": "eb9d263b8ca8f087086dd41439d02900c5f66f99" + }, + "require": { + "php": ">= 7.0.0" + }, + "provide": { + "wordpress/core-implementation": "6.4.1" + }, + "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": "2023-11-09T01:14:36+00:00" + }, + { + "name": "sebastian/cli-parser", "version": "1.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "reference": "442e7c7e687e42adc03470c7b668bc4b2402c0b2", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/1.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:08:49+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/1fc9f64c0927627ef78ba436c9b17d967e68e120", + "reference": "1fc9f64c0927627ef78ba436c9b17d967e68e120", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "source": "https://github.com/sebastianbergmann/code-unit/tree/1.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:08:54+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "2.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18" + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", - "reference": "4419fcdb5eabb9caa61a27c7a1db532a6b55dd18", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", + "reference": "ac91f01ccec49fb77bdc6fd1e548bc70f7faa3e5", "shasum": "" }, "require": { - "php": "^5.6 || ^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.0.x-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1215,34 +1954,44 @@ ], "description": "Looks up which function or method a line of code belongs to", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", - "time": "2017-03-04T06:30:41+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/2.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T05:30:19+00:00" }, { "name": "sebastian/comparator", - "version": "3.0.2", + "version": "4.0.8", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da" + "reference": "fa0f136dd2334583309d32b62544682ee972b51a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/5de4fc177adf9bce8df98d8d141a7559d7ccf6da", - "reference": "5de4fc177adf9bce8df98d8d141a7559d7ccf6da", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/fa0f136dd2334583309d32b62544682ee972b51a", + "reference": "fa0f136dd2334583309d32b62544682ee972b51a", "shasum": "" }, "require": { - "php": "^7.1", - "sebastian/diff": "^3.0", - "sebastian/exporter": "^3.1" + "php": ">=7.3", + "sebastian/diff": "^4.0", + "sebastian/exporter": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^7.1" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1255,6 +2004,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1266,46 +2019,109 @@ { "name": "Bernhard Schussek", "email": "bschussek@2bepublished.at" - }, + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "source": "https://github.com/sebastianbergmann/comparator/tree/4.0.8" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T12:41:17+00:00" + }, + { + "name": "sebastian/complexity", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88", + "reference": "739b35e53379900cc9ac327b2147867b8b6efd88", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.7", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ { "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], - "description": "Provides the functionality to compare PHP values for equality", - "homepage": "https://github.com/sebastianbergmann/comparator", - "keywords": [ - "comparator", - "compare", - "equality" + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } ], - "time": "2018-07-12T15:12:46+00:00" + "time": "2020-10-26T15:52:27+00:00" }, { "name": "sebastian/diff", - "version": "3.0.1", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/diff.git", - "reference": "366541b989927187c4ca70490a35615d3fef2dce" + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/366541b989927187c4ca70490a35615d3fef2dce", - "reference": "366541b989927187c4ca70490a35615d3fef2dce", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/74be17022044ebaaecfdf0c5cd504fc9cd5a7131", + "reference": "74be17022044ebaaecfdf0c5cd504fc9cd5a7131", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.0", - "symfony/process": "^2 || ^3.3 || ^4" + "phpunit/phpunit": "^9.3", + "symfony/process": "^4.2 || ^5" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1318,13 +2134,13 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Kore Nordmann", - "email": "mail@kore-nordmann.de" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" } ], "description": "Diff implementation", @@ -1335,27 +2151,37 @@ "unidiff", "unified diff" ], - "time": "2018-06-10T07:54:39+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "source": "https://github.com/sebastianbergmann/diff/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-05-07T05:35:17+00:00" }, { "name": "sebastian/environment", - "version": "4.1.0", + "version": "5.1.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/environment.git", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656" + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/6fda8ce1974b62b14935adc02a9ed38252eca656", - "reference": "6fda8ce1974b62b14935adc02a9ed38252eca656", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", + "reference": "830c43a844f1f8d5b7a1f6d6076b784454d8b7ed", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^7.5" + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-posix": "*" @@ -1363,7 +2189,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.1-dev" + "dev-master": "5.1-dev" } }, "autoload": { @@ -1388,34 +2214,44 @@ "environment", "hhvm" ], - "time": "2019-02-01T05:27:49+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "source": "https://github.com/sebastianbergmann/environment/tree/5.1.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:03:51+00:00" }, { "name": "sebastian/exporter", - "version": "3.1.0", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/exporter.git", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937" + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/234199f4528de6d12aaa58b612e98f7d36adb937", - "reference": "234199f4528de6d12aaa58b612e98f7d36adb937", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", + "reference": "ac230ed27f0f98f597c8a2b6eb7ac563af5e5b9d", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/recursion-context": "^4.0" }, "require-dev": { "ext-mbstring": "*", - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.1.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1428,6 +2264,10 @@ "BSD-3-Clause" ], "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, { "name": "Jeff Welch", "email": "whatthejeff@gmail.com" @@ -1436,46 +2276,55 @@ "name": "Volker Dusch", "email": "github@wallbash.com" }, - { - "name": "Bernhard Schussek", - "email": "bschussek@2bepublished.at" - }, - { - "name": "Sebastian Bergmann", - "email": "sebastian@phpunit.de" - }, { "name": "Adam Harvey", "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" } ], "description": "Provides the functionality to export PHP variables for visualization", - "homepage": "http://www.github.com/sebastianbergmann/exporter", + "homepage": "https://www.github.com/sebastianbergmann/exporter", "keywords": [ "export", "exporter" ], - "time": "2017-04-03T13:19:02+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "source": "https://github.com/sebastianbergmann/exporter/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2022-09-14T06:03:37+00:00" }, { "name": "sebastian/global-state", - "version": "2.0.0", + "version": "5.0.6", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/global-state.git", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4" + "reference": "bde739e7565280bda77be70044ac1047bc007e34" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", - "reference": "e8ba02eed7bbbb9e59e43dedd3dddeff4a56b0c4", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bde739e7565280bda77be70044ac1047bc007e34", + "reference": "bde739e7565280bda77be70044ac1047bc007e34", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "ext-dom": "*", + "phpunit/phpunit": "^9.3" }, "suggest": { "ext-uopz": "*" @@ -1483,7 +2332,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -1506,34 +2355,101 @@ "keywords": [ "global state" ], - "time": "2017-04-27T15:39:26+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "source": "https://github.com/sebastianbergmann/global-state/tree/5.0.6" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-08-02T09:26:13+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^4.6", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-11-28T06:42:11+00:00" }, { "name": "sebastian/object-enumerator", - "version": "3.0.3", + "version": "4.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-enumerator.git", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5" + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/7cfd9e65d11ffb5af41198476395774d4c8a84c5", - "reference": "7cfd9e65d11ffb5af41198476395774d4c8a84c5", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/5c9eeac41b290a3712d88851518825ad78f45c71", + "reference": "5c9eeac41b290a3712d88851518825ad78f45c71", "shasum": "" }, "require": { - "php": "^7.0", - "sebastian/object-reflector": "^1.1.1", - "sebastian/recursion-context": "^3.0" + "php": ">=7.3", + "sebastian/object-reflector": "^2.0", + "sebastian/recursion-context": "^4.0" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1553,32 +2469,42 @@ ], "description": "Traverses array structures and object graphs to enumerate all referenced objects", "homepage": "https://github.com/sebastianbergmann/object-enumerator/", - "time": "2017-08-03T12:35:26+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:12:34+00:00" }, { "name": "sebastian/object-reflector", - "version": "1.1.1", + "version": "2.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/object-reflector.git", - "reference": "773f97c67f28de00d397be301821b06708fca0be" + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/773f97c67f28de00d397be301821b06708fca0be", - "reference": "773f97c67f28de00d397be301821b06708fca0be", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", + "reference": "b4f479ebdbf63ac605d183ece17d8d7fe49c15c7", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.1-dev" + "dev-master": "2.0-dev" } }, "autoload": { @@ -1598,32 +2524,42 @@ ], "description": "Allows reflection of object attributes, including inherited and non-public ones", "homepage": "https://github.com/sebastianbergmann/object-reflector/", - "time": "2017-03-29T09:07:27+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-10-26T13:14:26+00:00" }, { "name": "sebastian/recursion-context", - "version": "3.0.0", + "version": "4.0.5", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8" + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", - "reference": "5b0cd723502bac3b006cbf3dbf7a1e3fcefe4fa8", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", + "reference": "e75bd0f07204fec2a0af9b0f3cfe97d05f92efc1", "shasum": "" }, "require": { - "php": "^7.0" + "php": ">=7.3" }, "require-dev": { - "phpunit/phpunit": "^6.0" + "phpunit/phpunit": "^9.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.0.x-dev" + "dev-master": "4.0-dev" } }, "autoload": { @@ -1636,44 +2572,57 @@ "BSD-3-Clause" ], "authors": [ - { - "name": "Jeff Welch", - "email": "whatthejeff@gmail.com" - }, { "name": "Sebastian Bergmann", "email": "sebastian@phpunit.de" }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, { "name": "Adam Harvey", "email": "aharvey@php.net" } ], "description": "Provides functionality to recursively process PHP variables", - "homepage": "http://www.github.com/sebastianbergmann/recursion-context", - "time": "2017-03-03T06:23:57+00:00" + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/4.0.5" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:07:39+00:00" }, { "name": "sebastian/resource-operations", - "version": "2.0.1", + "version": "3.0.3", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/resource-operations.git", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9" + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/4d7a795d35b889bf80a0cc04e08d77cedfa917a9", - "reference": "4d7a795d35b889bf80a0cc04e08d77cedfa917a9", + "url": "https://api.github.com/repos/sebastianbergmann/resource-operations/zipball/0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", + "reference": "0f4443cb3a1d92ce809899753bc0d5d5a8dd19a8", "shasum": "" }, "require": { - "php": "^7.1" + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1693,29 +2642,95 @@ ], "description": "Provides a list of PHP built-in functions that operate on resources", "homepage": "https://www.github.com/sebastianbergmann/resource-operations", - "time": "2018-10-04T04:07:39+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/resource-operations/issues", + "source": "https://github.com/sebastianbergmann/resource-operations/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:45:17+00:00" + }, + { + "name": "sebastian/type", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "reference": "75e2c2a32f5e0b3aef905b9ed0b179b953b3d7c7", + "shasum": "" + }, + "require": { + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "source": "https://github.com/sebastianbergmann/type/tree/3.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2023-02-03T06:13:03+00:00" }, { "name": "sebastian/version", - "version": "2.0.1", + "version": "3.0.2", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/version.git", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019" + "reference": "c6c1022351a901512170118436c764e473f6de8c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/99732be0ddb3361e16ad77b68ba41efc8e979019", - "reference": "99732be0ddb3361e16ad77b68ba41efc8e979019", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c6c1022351a901512170118436c764e473f6de8c", + "reference": "c6c1022351a901512170118436c764e473f6de8c", "shasum": "" }, "require": { - "php": ">=5.6" + "php": ">=7.3" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "2.0.x-dev" + "dev-master": "3.0-dev" } }, "autoload": { @@ -1736,68 +2751,51 @@ ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", "homepage": "https://github.com/sebastianbergmann/version", - "time": "2016-10-03T07:35:21+00:00" + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "source": "https://github.com/sebastianbergmann/version/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2020-09-28T06:39:44+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "2.9.2", + "version": "3.7.2", "source": { "type": "git", "url": "https://github.com/squizlabs/PHP_CodeSniffer.git", - "reference": "2acf168de78487db620ab4bc524135a13cfe6745" + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/2acf168de78487db620ab4bc524135a13cfe6745", - "reference": "2acf168de78487db620ab4bc524135a13cfe6745", + "url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/ed8e00df0a83aa96acf703f8c2979ff33341f879", + "reference": "ed8e00df0a83aa96acf703f8c2979ff33341f879", "shasum": "" }, "require": { "ext-simplexml": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": ">=5.1.2" + "php": ">=5.4.0" }, "require-dev": { - "phpunit/phpunit": "~4.0" + "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "bin": [ - "scripts/phpcs", - "scripts/phpcbf" + "bin/phpcs", + "bin/phpcbf" ], "type": "library", "extra": { "branch-alias": { - "dev-master": "2.x-dev" + "dev-master": "3.x-dev" } }, - "autoload": { - "classmap": [ - "CodeSniffer.php", - "CodeSniffer/CLI.php", - "CodeSniffer/Exception.php", - "CodeSniffer/File.php", - "CodeSniffer/Fixer.php", - "CodeSniffer/Report.php", - "CodeSniffer/Reporting.php", - "CodeSniffer/Sniff.php", - "CodeSniffer/Tokens.php", - "CodeSniffer/Reports/", - "CodeSniffer/Tokenizers/", - "CodeSniffer/DocGenerators/", - "CodeSniffer/Standards/AbstractPatternSniff.php", - "CodeSniffer/Standards/AbstractScopeSniff.php", - "CodeSniffer/Standards/AbstractVariableSniff.php", - "CodeSniffer/Standards/IncorrectPatternException.php", - "CodeSniffer/Standards/Generic/Sniffs/", - "CodeSniffer/Standards/MySource/Sniffs/", - "CodeSniffer/Standards/PEAR/Sniffs/", - "CodeSniffer/Standards/PSR1/Sniffs/", - "CodeSniffer/Standards/PSR2/Sniffs/", - "CodeSniffer/Standards/Squiz/Sniffs/", - "CodeSniffer/Standards/Zend/Sniffs/" - ] - }, "notification-url": "https://packagist.org/downloads/", "license": [ "BSD-3-Clause" @@ -1809,45 +2807,67 @@ } ], "description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.", - "homepage": "http://www.squizlabs.com/php-codesniffer", + "homepage": "https://github.com/squizlabs/PHP_CodeSniffer", "keywords": [ "phpcs", - "standards" + "standards", + "static analysis" ], - "time": "2018-11-07T22:31:41+00:00" + "support": { + "issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues", + "source": "https://github.com/squizlabs/PHP_CodeSniffer", + "wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki" + }, + "time": "2023-02-22T23:07:41+00:00" }, { - "name": "symfony/polyfill-ctype", - "version": "v1.10.0", + "name": "symfony/var-dumper", + "version": "v5.4.29", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-ctype.git", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19" + "url": "https://github.com/symfony/var-dumper.git", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19", - "reference": "e3d826245268269cd66f8326bd8bc066687b4a19", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6172e4ae3534d25ee9e07eb487c20be7760fcc65", + "reference": "6172e4ae3534d25ee9e07eb487c20be7760fcc65", "shasum": "" }, "require": { - "php": ">=5.3.3" + "php": ">=7.2.5", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php80": "^1.16" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^4.4|^5.0|^6.0", + "symfony/http-kernel": "^4.4|^5.0|^6.0", + "symfony/process": "^4.4|^5.0|^6.0", + "symfony/uid": "^5.1|^6.0", + "twig/twig": "^2.13|^3.0.4" }, "suggest": { - "ext-ctype": "For best performance" + "ext-iconv": "To convert non-UTF-8 strings to UTF-8 (or symfony/polyfill-iconv in case ext-iconv cannot be used).", + "ext-intl": "To show region name in time zone dump", + "symfony/console": "To use the ServerDumpCommand and/or the bin/var-dump-server script" }, + "bin": [ + "Resources/bin/var-dump-server" + ], "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.9-dev" - } - }, "autoload": { + "files": [ + "Resources/functions/dump.php" + ], "psr-4": { - "Symfony\\Polyfill\\Ctype\\": "" + "Symfony\\Component\\VarDumper\\": "" }, - "files": [ - "bootstrap.php" + "exclude-from-classmap": [ + "/Tests/" ] }, "notification-url": "https://packagist.org/downloads/", @@ -1856,43 +2876,58 @@ ], "authors": [ { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" + "name": "Nicolas Grekas", + "email": "p@tchwork.com" }, { - "name": "Gert de Pagter", - "email": "backendtea@gmail.com" + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" } ], - "description": "Symfony polyfill for ctype functions", + "description": "Provides mechanisms for walking through any arbitrary PHP variable", "homepage": "https://symfony.com", "keywords": [ - "compatibility", - "ctype", - "polyfill", - "portable" + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v5.4.29" + }, + "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": "2018-08-06T14:22:27+00:00" + "time": "2023-09-12T10:09:58+00:00" }, { "name": "theseer/tokenizer", - "version": "1.1.0", + "version": "1.2.1", "source": { "type": "git", "url": "https://github.com/theseer/tokenizer.git", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b" + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theseer/tokenizer/zipball/cb2f008f3f05af2893a87208fe6a6c4985483f8b", - "reference": "cb2f008f3f05af2893a87208fe6a6c4985483f8b", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/34a41e998c2183e22995f158c581e7b5e755ab9e", + "reference": "34a41e998c2183e22995f158c581e7b5e755ab9e", "shasum": "" }, "require": { "ext-dom": "*", "ext-tokenizer": "*", "ext-xmlwriter": "*", - "php": "^7.0" + "php": "^7.2 || ^8.0" }, "type": "library", "autoload": { @@ -1912,105 +2947,140 @@ } ], "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", - "time": "2017-04-07T12:08:54+00:00" + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2021-07-28T10:34:58+00:00" }, { - "name": "webmozart/assert", - "version": "1.4.0", + "name": "wp-phpunit/wp-phpunit", + "version": "6.3.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9" + "url": "https://github.com/wp-phpunit/wp-phpunit.git", + "reference": "4797791a311c41d213027333e4fcc48073f77df0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/83e253c8e0be5b0257b881e1827274667c5c17a9", - "reference": "83e253c8e0be5b0257b881e1827274667c5c17a9", + "url": "https://api.github.com/repos/wp-phpunit/wp-phpunit/zipball/4797791a311c41d213027333e4fcc48073f77df0", + "reference": "4797791a311c41d213027333e4fcc48073f77df0", "shasum": "" }, - "require": { - "php": "^5.3.3 || ^7.0", - "symfony/polyfill-ctype": "^1.8" - }, - "require-dev": { - "phpunit/phpunit": "^4.6", - "sebastian/version": "^1.0.1" - }, "type": "library", - "extra": { - "branch-alias": { - "dev-master": "1.3-dev" - } - }, "autoload": { - "psr-4": { - "Webmozart\\Assert\\": "src/" - } + "files": [ + "__loaded.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "GPL-2.0-or-later" ], "authors": [ { - "name": "Bernhard Schussek", - "email": "bschussek@gmail.com" + "name": "Evan Mattson", + "email": "me@aaemnnost.tv" + }, + { + "name": "WordPress Community", + "homepage": "https://wordpress.org/about/" } ], - "description": "Assertions to validate method input/output with nice error messages.", + "description": "WordPress core PHPUnit library", + "homepage": "https://github.com/wp-phpunit", "keywords": [ - "assert", - "check", - "validate" + "phpunit", + "test", + "wordpress" ], - "time": "2018-12-25T11:19:39+00:00" + "support": { + "docs": "https://github.com/wp-phpunit/docs", + "issues": "https://github.com/wp-phpunit/issues", + "source": "https://github.com/wp-phpunit/wp-phpunit" + }, + "time": "2023-08-09T01:26:57+00:00" }, { - "name": "wp-coding-standards/wpcs", - "version": "0.9.0", + "name": "yoast/phpunit-polyfills", + "version": "2.0.0", "source": { "type": "git", - "url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git", - "reference": "b415094aa5fd24da6eba2295323bcff840902dd3" + "url": "https://github.com/Yoast/PHPUnit-Polyfills.git", + "reference": "c758753e8f9dac251fed396a73c8305af3f17922" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/b415094aa5fd24da6eba2295323bcff840902dd3", - "reference": "b415094aa5fd24da6eba2295323bcff840902dd3", + "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/c758753e8f9dac251fed396a73c8305af3f17922", + "reference": "c758753e8f9dac251fed396a73c8305af3f17922", "shasum": "" }, "require": { - "squizlabs/php_codesniffer": "~2.2" + "php": ">=5.6", + "phpunit/phpunit": "^5.7.21 || ^6.0 || ^7.0 || ^8.0 || ^9.0 || ^10.0" + }, + "require-dev": { + "yoast/yoastcs": "^2.3.0" }, "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.x-dev" + } + }, + "autoload": { + "files": [ + "phpunitpolyfills-autoload.php" + ] + }, "notification-url": "https://packagist.org/downloads/", "license": [ - "MIT" + "BSD-3-Clause" ], "authors": [ + { + "name": "Team Yoast", + "email": "support@yoast.com", + "homepage": "https://yoast.com" + }, { "name": "Contributors", - "homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors" + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills/graphs/contributors" } ], - "description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions", + "description": "Set of polyfills for changed PHPUnit functionality to allow for creating PHPUnit cross-version compatible tests", + "homepage": "https://github.com/Yoast/PHPUnit-Polyfills", "keywords": [ - "phpcs", - "standards", - "wordpress" + "phpunit", + "polyfill", + "testing" ], - "time": "2016-02-01T16:14:59+00:00" + "support": { + "issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues", + "source": "https://github.com/Yoast/PHPUnit-Polyfills" + }, + "time": "2023-06-06T20:28:24+00:00" } ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "10up/wp_mock": 20 - }, + "stability-flags": [], "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": ">=7.1" + "php": "^8.0" + }, + "platform-dev": { + "ext-simplexml": "*" + }, + "platform-overrides": { + "php": "8.0" }, - "platform-dev": [] + "plugin-api-version": "2.3.0" } diff --git a/src/Edd/AbstractLicenceManager.php b/src/Edd/AbstractLicenceManager.php index fb3d686..5af4c68 100644 --- a/src/Edd/AbstractLicenceManager.php +++ b/src/Edd/AbstractLicenceManager.php @@ -7,35 +7,127 @@ use Dwnload\EddSoftwareLicenseManager\Edd\Models\DeactivateLicense; use Dwnload\EddSoftwareLicenseManager\Edd\Models\LicenseStatus; use Dwnload\EddSoftwareLicenseManager\Edd\Models\PluginData; -use Dwnload\WpEmailDownload\EmailDownload; +use Dwnload\WpSettingsApi\Settings\FieldManager; +use Dwnload\WpSettingsApi\Settings\SectionManager; +use Dwnload\WpSettingsApi\WpSettingsApi; +use TheFrosty\WpUtilities\Api\TransientsTrait; +use TheFrosty\WpUtilities\Plugin\Plugin; +use function __; /** - * Class LicenceManager - * + * Class AbstractLicenceManager * @package Dwnload\EddSoftwareLicenseManager\Edd */ -abstract class AbstractLicenceManager { +abstract class AbstractLicenceManager +{ - const ACTIVATE_LICENCE = 'activate_license'; - const CHECK_LICENCE = 'check_license'; - const DEACTIVATE_LICENCE = 'deactivate_license'; - const TRANSIENT_PREFIX = 'dwnload_edd_slm_'; - const LICENSE_SETTING = 'dwnload_license_data'; + use TransientsTrait; - /** @var string $api_url */ - private $api_url; + public const ACTIVATE_LICENCE = 'activate_license'; + public const CHECK_LICENCE = 'check_license'; + public const DEACTIVATE_LICENCE = 'deactivate_license'; + public const TRANSIENT_PREFIX = 'dwnload_edd_slm_'; + public const LICENSE_SETTING = 'dwnload_license_data'; + protected PluginData $pluginData; + + /** + * AbstractLicenceManager constructor. + * @param Plugin $parent + * @param array $data + */ + public function __construct(protected Plugin $parent, array $data) + { + $this->pluginData = new PluginData($data); + } + + /** + * Build the HTML submit button. + * @param string $plugin_id + * @param string $class + * @param string $action + * @param string $status + */ + public function buildSubmitButton(string $plugin_id, string $class, string $action, string $status): void + { + $text = match ($action) { + LicenseStatus::LICENSE_DEACTIVATE => $this->getStrings()['deactivate-license'], + LicenseStatus::LICENSE_CHECK_LICENSE => $this->getStrings()['check-license'], + LicenseStatus::LICENSE_ACTIVATE => $this->getStrings()['activate-license'], + default => 'Unknown', + }; + + \printf( + '%1$s', + $text, + $class, + $action, + $status, + $plugin_id + ); + } + + /** + * Get an array of translation strings. + * + * @return array + */ + public function getStrings(): array + { + return [ + 'plugin-license' => __('Plugin License', 'edd-software-license-manager'), + 'enter-key' => __('Enter your plugin license key.', 'edd-software-license-manager'), + 'license-key' => __('License Key', 'edd-software-license-manager'), + 'license-action' => __('License Action', 'edd-software-license-manager'), + 'deactivate-license' => __('Deactivate License', 'edd-software-license-manager'), + 'activate-license' => __('Activate License', 'edd-software-license-manager'), + 'check-license' => __('Check License Status', 'edd-software-license-manager'), + 'status-unknown' => __('License status is unknown.', 'edd-software-license-manager'), + 'renew' => __('Renew?', 'edd-software-license-manager'), + 'unlimited' => __('unlimited', 'edd-software-license-manager'), + 'license-key-is-active' => __('License key is active.', 'edd-software-license-manager'), + 'expires%s' => __('Expires %s.', 'edd-software-license-manager'), + '%1$s/%2$-sites' => __('You have %1$s / %2$s sites activated.', 'edd-software-license-manager'), + 'license-key-expired-%s' => __('License key expired %s.', 'edd-software-license-manager'), + 'license-key-expired' => __('License key has expired.', 'edd-software-license-manager'), + 'license-keys-do-not-match' => __('License keys do not match.', 'edd-software-license-manager'), + 'license-is-inactive' => __('License is inactive.', 'edd-software-license-manager'), + 'license-key-is-disabled' => __('License key is disabled.', 'edd-software-license-manager'), + 'site-is-inactive' => __('Site is inactive.', 'edd-software-license-manager'), + 'license-status-unknown' => __('License status is unknown.', 'edd-software-license-manager'), + 'update-notice' => __( + "Updating this plugin will lose any customizations you have made. 'Cancel' to stop, 'OK' to update.", + 'edd-software-license-manager' + ), + 'update-available' => __( + '%1$s %2$s is available. Check out what\'s new or update now.', + 'edd-software-license-manager' + ), + ]; + } + + /** + * Initiate the addon setting to the Section & Field Manager classes. + * @param SectionManager $section_manager + * @param FieldManager $field_manager + * @param WpSettingsApi $wp_settings_api + */ + abstract protected function init( + SectionManager $section_manager, + FieldManager $field_manager, + WpSettingsApi $wp_settings_api + ): void; /** * Activates the license key. * * @param string $license The incoming POST license key - * @param string $plugin_slug + * @param string $plugin_id * @param int $item_id - * - * @return bool + * @return false|array */ - protected function activateLicense( string $license, string $plugin_slug, int $item_id ): bool { - if ( empty( $license ) ) { + protected function activateLicense(string $license, string $plugin_id, int $item_id): false|array + { + if (empty($license)) { return false; } @@ -43,21 +135,24 @@ protected function activateLicense( string $license, string $plugin_slug, int $i 'edd_action' => self::ACTIVATE_LICENCE, 'license' => $license, 'item_id' => $item_id, + 'item_name' => rawurlencode($this->pluginData->getItemName()), + 'url' => home_url(), + 'environment' => wp_get_environment_type(), ]; - $response = $this->getActivateLicense( $api_params ); + $response = $this->getActivateLicense($api_params); - if ( $response->isValidResponse() && - strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_ACTIVE ) === 0 - ) { - $key = $this->getTransientKey( $plugin_slug . '_license_message' ); - $option = get_option( self::LICENSE_SETTING, [] ); - $option[ $plugin_slug ]['license'] = trim( $license ); - $option[ $plugin_slug ]['status'] = trim( $response->getLicense() ); + if ($response->isValidResponse()) { + $key = $this->getTransientKey($plugin_id . '_license_message', self::TRANSIENT_PREFIX); + $option = \get_option(self::LICENSE_SETTING, []); + $option[$plugin_id]['license'] = trim($license); + $option[$plugin_id]['expires'] = trim($response->getExpires()); + $option[$plugin_id]['status'] = trim($response->getLicense()); - update_option( self::LICENSE_SETTING, $option ); + \update_option(self::LICENSE_SETTING, $option); + \delete_transient($key); - return delete_transient( $key ); + return $option; } return false; @@ -67,31 +162,34 @@ protected function activateLicense( string $license, string $plugin_slug, int $i * Deactivates the license key. * * @param string $license The incoming POST license key - * @param string $plugin_slug + * @param string $plugin_id * @param int $item_id - * - * @return bool + * @return false|array */ - protected function deactivateLicense( string $license, string $plugin_slug, int $item_id ): bool { + protected function deactivateLicense(string $license, string $plugin_id, int $item_id): false|array + { $api_params = [ 'edd_action' => self::DEACTIVATE_LICENCE, 'license' => $license, 'item_id' => $item_id, + 'item_name' => rawurlencode($this->pluginData->getItemName()), + 'url' => home_url(), + 'environment' => wp_get_environment_type(), ]; - $response = $this->getDeactivateLicense( $api_params ); + $response = $this->getDeactivateLicense($api_params); - if ( $response->isValidResponse() && - strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_DEACTIVATED ) === 0 - ) { - $key = $this->getTransientKey( $plugin_slug . '_license_message' ); - $option = get_option( self::LICENSE_SETTING, [] ); - $option[ $plugin_slug ]['license'] = trim( $license ); - $option[ $plugin_slug ]['status'] = ''; + if ($response->isValidResponse()) { + $key = $this->getTransientKey($plugin_id . '_license_message', self::TRANSIENT_PREFIX); + $option = get_option(self::LICENSE_SETTING, []); + $option[$plugin_id]['license'] = trim($license); + $option[$plugin_id]['expires'] = trim($response->getExpires()); + $option[$plugin_id]['status'] = trim($response->getLicense()); - update_option( self::LICENSE_SETTING, $option ); + \update_option(self::LICENSE_SETTING, $option); + \delete_transient($key); - return delete_transient( $key ); + return $option; } return false; @@ -101,70 +199,81 @@ protected function deactivateLicense( string $license, string $plugin_slug, int * Checks if license is valid and gets expire date. * * @param string $license The incoming POST license key - * @param PluginData $plugin_data + * @param string $plugin_id * @param bool $update_option - * * @return string $message License status message. */ - protected function checkLicense( string $license = null, PluginData $plugin_data, bool $update_option = false ): string { - if ( empty( $license ) ) { + protected function checkLicense(string $license, string $plugin_id, bool $update_option = false): string + { + if (empty($license)) { return $this->getStrings()['enter-key']; } $api_params = [ 'edd_action' => self::CHECK_LICENCE, 'license' => $license, - 'item_id' => $plugin_data->getItemId(), + 'item_id' => $this->pluginData->getItemId(), + 'item_name' => rawurlencode($this->pluginData->getItemName()), + 'url' => home_url(), + 'environment' => wp_get_environment_type(), ]; - $response = $this->getCheckLicense( $api_params ); + $response = $this->getCheckLicense($api_params); // If response doesn't include license data, return - if ( ! $response->isValidResponse() ) { + if (!$response->isValidResponse()) { return $this->getStrings()['license-unknown']; } - $expires = date_i18n( get_option( 'date_format' ), strtotime( $response->getExpires() ) ); - $renew_link = '' . $this->getStrings()['renew'] . ''; + $expires = date_i18n(get_option('date_format'), strtotime($response->getExpires())); + $renew_link = \sprintf( + '%2$s', + esc_url($this->getRenewalUrl($license, $this->pluginData->getItemId())), + $this->getStrings()['renew'] + ); // Unlimited ?? - if ( $response->getLicenseLimit() === 0 ) { + if ($response->getLicenseLimit() === 0) { $license_limit = $this->getStrings()['unlimited']; } - if ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_ACTIVE ) === 0 ) { + if (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_ACTIVE) === 0) { $message = $this->getStrings()['license-key-is-active'] . ' '; - $message .= sprintf( $this->getStrings()['expires%s'], $expires ) . ' '; - $message .= sprintf( $this->getStrings()['%1$s/%2$-sites'], $response->getSiteCount(), $response->getLicenseLimit() ); - } elseif ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_EXPIRED ) === 0 ) { - if ( strtotime( $response->getExpires() ) > time() ) { - $message = sprintf( $this->getStrings()['license-key-expired-%s'], $expires ); + $message .= sprintf($this->getStrings()['expires%s'], $expires) . ' '; + $message .= sprintf( + $this->getStrings()['%1$s/%2$-sites'], + $response->getSiteCount(), + $response->getLicenseLimit() + ); + } elseif (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_EXPIRED) === 0) { + if (strtotime($response->getExpires()) > time()) { + $message = sprintf($this->getStrings()['license-key-expired-%s'], $expires); } else { $message = $this->getStrings()['license-key-expired']; $message .= ' ' . $renew_link; } - } elseif ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_INVALID ) === 0 ) { + } elseif (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_INVALID) === 0) { $message = $this->getStrings()['license-keys-do-not-match']; - } elseif ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_INACTIVE ) === 0 ) { + } elseif (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_INACTIVE) === 0) { $message = $this->getStrings()['license-is-inactive']; - } elseif ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_DISABLED ) === 0 ) { + } elseif (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_DISABLED) === 0) { $message = $this->getStrings()['license-key-is-disabled']; - } elseif ( strcasecmp( $response->getLicense(), LicenseStatus::LICENSE_SITE_INACTIVE ) === 0 ) { + } elseif (strcasecmp($response->getLicense(), LicenseStatus::LICENSE_SITE_INACTIVE) === 0) { $message = $this->getStrings()['site-is-inactive']; } else { $message = $this->getStrings()['license-status-unknown']; } - $option = get_option( self::LICENSE_SETTING, [] ); - $status = isset( $option[ $plugin_data->getItemId() ]['status'] ) ? $option[ $plugin_data->getItemId() ]['status'] : ''; - $option[ $plugin_data->getItemId() ]['status'] = $response->getLicense(); - $key = $this->getTransientKey( $plugin_data->getItemId() . '_license_message' ); + $option = get_option(self::LICENSE_SETTING, []); + $status = $option[$plugin_id]['status'] ?? ''; + $option[$plugin_id]['status'] = $response->getLicense(); + $key = $this->getTransientKey($this->pluginData->getItemId() . '_license_message', self::TRANSIENT_PREFIX); - if ( $update_option ) { - if ( ! empty( $status ) && $status != $option[ $plugin_data->getItemId() ]['status'] ) { - update_option( self::LICENSE_SETTING, $option ); - delete_transient( $key ); + if ($update_option) { + if (!empty($status) && $status !== $option[$plugin_id]['status']) { + \update_option(self::LICENSE_SETTING, $option); + \delete_transient($key); } } @@ -172,142 +281,80 @@ protected function checkLicense( string $license = null, PluginData $plugin_data } /** - * Get an array of translation strings. - * - * @return array - */ - protected function getStrings(): array { - return [ - 'plugin-license' => __( 'Plugin License', 'edd-software-license-manager' ), - 'enter-key' => __( 'Enter your plugin license key.', 'edd-software-license-manager' ), - 'license-key' => __( 'License Key', 'edd-software-license-manager' ), - 'license-action' => __( 'License Action', 'edd-software-license-manager' ), - 'deactivate-license' => __( 'Deactivate License', 'edd-software-license-manager' ), - 'activate-license' => __( 'Activate License', 'edd-software-license-manager' ), - 'check-license' => __( 'Check License Status', 'edd-software-license-manager' ), - 'status-unknown' => __( 'License status is unknown.', 'edd-software-license-manager' ), - 'renew' => __( 'Renew?', 'edd-software-license-manager' ), - 'unlimited' => __( 'unlimited', 'edd-software-license-manager' ), - 'license-key-is-active' => __( 'License key is active.', 'edd-software-license-manager' ), - 'expires%s' => __( 'Expires %s.', 'edd-software-license-manager' ), - '%1$s/%2$-sites' => __( 'You have %1$s / %2$s sites activated.', 'edd-software-license-manager' ), - 'license-key-expired-%s' => __( 'License key expired %s.', 'edd-software-license-manager' ), - 'license-key-expired' => __( 'License key has expired.', 'edd-software-license-manager' ), - 'license-keys-do-not-match' => __( 'License keys do not match.', 'edd-software-license-manager' ), - 'license-is-inactive' => __( 'License is inactive.', 'edd-software-license-manager' ), - 'license-key-is-disabled' => __( 'License key is disabled.', 'edd-software-license-manager' ), - 'site-is-inactive' => __( 'Site is inactive.', 'edd-software-license-manager' ), - 'license-status-unknown' => __( 'License status is unknown.', 'edd-software-license-manager' ), - 'update-notice' => __( "Updating this plugin will lose any customizations you have made. 'Cancel' to stop, 'OK' to update.", 'edd-software-license-manager' ), - 'update-available' => __( '%1$s %2$s is available. Check out what\'s new or update now.', 'edd-software-license-manager' ), - ]; - } - - /** - * @param string $value - * @param string $class - * @param string $name - * @param string $status - */ - protected function getSubmitButton( string $value, string $class, string $name, string $status ) { - printf( - '

', - $value, - $class, - $name, - $status - ); - } - - /** + * Get ActivateLicense object, * @param array $api_params - * * @return ActivateLicense */ - private function getActivateLicense( array $api_params ): ActivateLicense { - return new ActivateLicense( $this->getApiResponse( $api_params ) ); + private function getActivateLicense(array $api_params): ActivateLicense + { + return new ActivateLicense($this->getApiResponse($api_params)); } /** + * Get DeactivateLicense object, * @param array $api_params - * * @return DeactivateLicense */ - private function getDeactivateLicense( array $api_params ): DeactivateLicense { - return new DeactivateLicense( $this->getApiResponse( $api_params ) ); + private function getDeactivateLicense(array $api_params): DeactivateLicense + { + return new DeactivateLicense($this->getApiResponse($api_params)); } /** + * Get CheckLicense object, * @param array $api_params - * * @return CheckLicense */ - private function getCheckLicense( array $api_params ): CheckLicense { - return new CheckLicense( $this->getApiResponse( $api_params ) ); + private function getCheckLicense(array $api_params): CheckLicense + { + return new CheckLicense($this->getApiResponse($api_params)); } /** * Makes a call to the API. - * * @param array $api_params to be used for wp_remote_get. - * * @return array $response decoded JSON response. */ - private function getApiResponse( array $api_params ): array { - $response = wp_remote_get( - esc_url_raw( add_query_arg( $api_params, $this->api_url ) ), + private function getApiResponse(array $api_params): array + { + $response = \wp_remote_post( + \esc_url($this->pluginData->getApiUrl()), [ 'timeout' => 15, 'sslverify' => true, + 'body' => $api_params, ] ); // Make sure the response came back okay. - if ( is_wp_error( $response ) ) { + if (\is_wp_error($response)) { return []; } - return json_decode( wp_remote_retrieve_body( $response ), true ); + return \json_decode(\wp_remote_retrieve_body($response), true); } /** - * Constructs a renewal link - * + * Constructs a renewal link. * @param string $license_key - * @param int $item_id - * - * @since 1.0.0 + * @param int|null $item_id * @return string */ - private function getRenewalUrl( string $license_key, int $item_id ) { - if ( ! empty( $license_key ) || ! empty( $item_id ) ) { - $url = add_query_arg( + private function getRenewalUrl(string $license_key = '', ?int $item_id = null): string + { + if (!empty($license_key) || !empty($item_id)) { + return \add_query_arg( [ 'edd_license' => $license_key, 'download_id' => $item_id, 'utm_source' => 'wordpress', - 'utm_medium' => 'frosty-media-renew', - 'utm_campaign' => 'frosty-media-license', + 'utm_medium' => 'edd-software-licence', + 'utm_campaign' => 'licence', ], - sprintf( '%s/checkout/', untrailingslashit( EmailDownload::API_URL ) ) + \sprintf('%s/checkout/', \untrailingslashit($this->pluginData->getApiUrl())) ); - - return $url; } - return $this->api_url; - } - - /** - * Get's the cached transient key. - * - * @param string $input - * - * @return string - */ - private function getTransientKey( string $input ): string { - $prefix = self::TRANSIENT_PREFIX; - - return $prefix . substr( md5( $input ), 0, 45 - strlen( $prefix ) ); + return $this->pluginData->getApiUrl(); } } diff --git a/src/Edd/LicenseManager.php b/src/Edd/LicenseManager.php index 3535629..4560ef3 100644 --- a/src/Edd/LicenseManager.php +++ b/src/Edd/LicenseManager.php @@ -1,138 +1,169 @@ app = $app; - $this->plugin_data = new PluginData( $data ); + public function addHooks(): void + { + $this->addAction(WpSettingsApi::HOOK_INIT, [$this, 'init'], 299, 3); + $this->addAction('wp_ajax_' . sanitize_key(self::AJAX_ACTION), [$this, 'licenseAjax']); } /** - * @param SettingField $field + * Initiate our setting to the Section & Field Manager classes. + * @param SectionManager $section_manager + * @param FieldManager $field_manager + * @param WpSettingsApi $wp_settings_api */ - public function setSettingField( SettingField $field ) { - $this->field = $field; - } + protected function init( + SectionManager $section_manager, + FieldManager $field_manager, + WpSettingsApi $wp_settings_api + ): void { + if (!$wp_settings_api->isCurrentMenuSlug($this->parent->getSlug())) { + return; + } + $this->addAction('admin_enqueue_scripts', [$this, 'enqueueScripts']); - /** - * @return SettingField - */ - public function getSettingField(): SettingField { - return $this->field; - } + $section_id = $section_manager->addSection( + new SettingSection([ + SettingSection::SECTION_ID => 'edd_license_manager', + SettingSection::SECTION_TITLE => 'License(s)', + ]) + ); - public function addHooks() { - add_action( App::ACTION_PREFIX . 'settings_page_loaded', function() { - add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); - } ); - add_action( App::ACTION_PREFIX . 'form_top', [ $this, 'licenseData' ] ); - add_action( 'wp_ajax_' . sanitize_key( self::AJAX_ACTION ), [ $this, 'licenseAjax' ] ); + $licenses = (array)\apply_filters('dwnload_edd_slm_licenses', []); + foreach ($licenses as $plugin_id => $plugin_name) { + $field_manager->addField( + new SettingField( + [ + SettingField::NAME => $plugin_id, + SettingField::LABEL => \sprintf( + \__('%s License', 'edd-software-license-manager'), + $plugin_name + ), + SettingField::TYPE => FieldTypes::FIELD_TYPE_TEXT, + SettingField::DESC => include \dirname(__DIR__, 2) . '/views/license.php', + SettingField::SECTION_ID => $section_id, + ] + ) + ); + } } /** * Enqueue License only script */ - public function enqueue_scripts() { - wp_enqueue_style( + protected function enqueueScripts(): void + { + $use_local = \apply_filters('dwnload_edd_slm_use_local_scripts', false); + $get_src = function (string $path) use ($use_local): string { + if ($use_local) { + return \plugins_url($path, \dirname(__DIR__)); + } + + $debug = \defined('\SCRIPT_DEBUG') && \SCRIPT_DEBUG; + + return \sprintf( + 'https://cdn.jsdelivr.net/gh/dwnload/EddSoftwareLicenseManager@%s/%s', + \apply_filters('dwnload_edd_slm_scripts_version', self::VERSION), + $debug === true ? $path : \str_replace(['.css', '.js'], ['.min.css', '.min.js'], $path) + ); + }; + + \wp_enqueue_style( self::HANDLE, - plugins_url( '/assets/css/licensemanager.css', dirname( __DIR__ ) ), + $get_src('assets/css/licensemanager.css'), [], - $this->app->getVersion() + self::VERSION ); - wp_enqueue_script( + \wp_enqueue_script( self::HANDLE, - plugins_url( '/assets/js/licensemanager.js', dirname( __DIR__ ) ), - [ 'jquery' ], - $this->app->getVersion(), + $get_src('assets/js/licensemanager.js'), + ['jquery'], + self::VERSION, true ); - wp_localize_script( self::HANDLE, 'EddLicenseManager', [ - 'action' => sanitize_key( self::AJAX_ACTION ), - 'license_attr' => "{$this->field->getSectionId()}[{$this->field->getName()}]", - 'dirname' => __DIR__, - 'nonce' => wp_create_nonce( plugin_basename( __FILE__ ) . self::AJAX_ACTION . '-nonce' ), - 'loading' => admin_url( '/images/spinner-2x.gif' ), - ] ); + \wp_localize_script(self::HANDLE, 'EddLicenseManager', [ + 'action' => \sanitize_key(self::AJAX_ACTION), + 'nonce' => \wp_create_nonce(\plugin_basename(__FILE__) . self::AJAX_ACTION . '-nonce'), + 'loading' => \admin_url('/images/spinner-2x.gif'), + ]); } /** - * Output additional HTML to the top of the section form. - * - * @param SettingSection $section + * Licence check AJAX listener. */ - public function licenseData( SettingSection $section ) { - if ( $section->getId() === $this->field->getSectionId() ) { - include dirname( dirname( __DIR__ ) ) . '/views/license.php'; - } - } - - public function licenseAjax() { - check_ajax_referer( plugin_basename( __FILE__ ) . self::AJAX_ACTION . '-nonce', 'nonce' ); - - if ( empty( $_POST ) || empty( $_POST['license_key'] ) ) { - wp_send_json_error(); - } + protected function licenseAjax(): void + { + \check_ajax_referer(\plugin_basename(__FILE__) . self::AJAX_ACTION . '-nonce', 'nonce'); - $license_value = esc_html( wp_unslash( $_POST['license_key'] ) ); - $license_key = $this->field->isObfuscated() && - method_exists( Sanitize::class, 'sanitizeObfuscated' ) ? - Sanitize::sanitizeObfuscated( $license_value, [], $this->field->getName() ) : $license_value; - - $plugin_action = sanitize_text_field( wp_unslash( $_POST['plugin_action'] ) ); - - if ( $plugin_action === LicenseStatus::LICENSE_ACTIVATE ) { - if ( $this->activateLicense( $license_key, $this->plugin_data->getSlug(), $this->plugin_data->getItemId() ) ) { - wp_send_json_success(); - } - wp_send_json_error(); - } - - if ( $plugin_action === LicenseStatus::LICENSE_DEACTIVATE ) { - if ( $this->deactivateLicense( $license_key, $this->plugin_data->getSlug(), $this->plugin_data->getItemId() ) ) { - wp_send_json_success(); - } + if (empty($_POST) || empty($_POST['license_key'])) { wp_send_json_error(); } - if ( $plugin_action === LicenseStatus::LICENSE_CHECK_LICENSE ) { - $message = $this->checkLicense( $license_key, $this->plugin_data, $update_option = true ); - wp_send_json_success( $message ); + $license_key = sanitize_text_field(wp_unslash($_POST['license_key'])); + $plugin_action = sanitize_text_field(wp_unslash($_POST['plugin_action'])); + $plugin_id = sanitize_text_field(wp_unslash($_POST['plugin_id'])); + + switch ($plugin_action) { + case LicenseStatus::LICENSE_ACTIVATE: + $response = $this->activateLicense( + $license_key, + $plugin_id, + $this->pluginData->getItemId() + ); + if ($response !== false) { + wp_send_json_success($response); + } + break; + case LicenseStatus::LICENSE_DEACTIVATE: + $response = $this->deactivateLicense( + $license_key, + $plugin_id, + $this->pluginData->getItemId() + ); + if ($response !== false) { + wp_send_json_success($response); + } + break; + case LicenseStatus::LICENSE_CHECK_LICENSE: + $response = $this->checkLicense($license_key, $plugin_id, true); + wp_send_json_success($response); + break; } - // No matching action wp_send_json_error(); } } diff --git a/src/Edd/Models/ActivateLicense.php b/src/Edd/Models/ActivateLicense.php index bd84d17..9ec8b76 100644 --- a/src/Edd/Models/ActivateLicense.php +++ b/src/Edd/Models/ActivateLicense.php @@ -1,12 +1,14 @@ success = $success; } /** - * @return string + * @return bool */ - public function getSuccess(): string { + public function getSuccess(): bool + { return $this->success; } /** * @param string $checksum */ - public function setChecksum( string $checksum ) { + public function setChecksum(string $checksum): void + { $this->checksum = $checksum; } /** * @return string */ - public function getChecksum(): string { + public function getChecksum(): string + { return $this->checksum; } /** * @param int $license_limit */ - public function setLicenseLimit( int $license_limit ) { + public function setLicenseLimit(int $license_limit): void + { $this->license_limit = $license_limit; } /** * @return int */ - public function getLicenseLimit(): int { + public function getLicenseLimit(): int + { return $this->license_limit; } /** * @param int $site_count */ - public function setSiteCount( int $site_count ) { + public function setSiteCount(int $site_count): void + { $this->site_count = $site_count; } /** * @return int */ - public function getSiteCount(): int { + public function getSiteCount(): int + { return $this->site_count; } /** * @param int $activations_left */ - public function setActivationsLeft( int $activations_left ) { + public function setActivationsLeft(int $activations_left): void + { $this->activations_left = $activations_left; } /** * @return int */ - public function getActivationsLeft(): int { + public function getActivationsLeft(): int + { return $this->activations_left; } /** * @param mixed $price_id */ - public function setPriceId( $price_id ) { + public function setPriceId(int $price_id): void + { $this->price_id = $price_id; } /** * @return mixed */ - public function getPriceId() { + public function getPriceId(): int + { return $this->price_id; } } diff --git a/src/Edd/Models/DeactivateLicense.php b/src/Edd/Models/DeactivateLicense.php index 0384231..b77fbb2 100644 --- a/src/Edd/Models/DeactivateLicense.php +++ b/src/Edd/Models/DeactivateLicense.php @@ -1,12 +1,14 @@ license ); + public function isValidResponse(): bool + { + return !empty($this->license); } /** * @param string $licence */ - public function setLicense( string $licence ) { - $this->license = trim( $licence ); + protected function setLicense(string $licence): void + { + $this->license = trim($licence); } /** * @return string */ - public function getLicense(): string { + public function getLicense(): string + { return $this->license; } /** * @param string $item_name */ - public function setItemName( string $item_name ) { + protected function setItemName(string $item_name): void + { $this->item_name = $item_name; } /** * @return string */ - public function getItemName(): string { + public function getItemName(): string + { return $this->item_name; } /** * @param string $expires */ - public function setExpires( string $expires ) { + protected function setExpires(string $expires): void + { $this->expires = $expires; } /** * @return string */ - public function getExpires(): string { + public function getExpires(): string + { return $this->expires; } /** * @param int $payment_id */ - public function setPaymentId( int $payment_id ) { + protected function setPaymentId(int $payment_id): void + { $this->payment_id = $payment_id; } /** * @return int */ - public function getPaymentId(): int { + public function getPaymentId(): int + { return $this->payment_id; } /** * @param string $customer_name */ - public function setCustomerName( string $customer_name ) { + protected function setCustomerName(string $customer_name): void + { $this->customer_name = $customer_name; } /** * @return string */ - public function getCustomerName(): string { + public function getCustomerName(): string + { return $this->customer_name; } /** * @param string $customer_email */ - public function setCustomerEmail( string $customer_email ) { + public function setCustomerEmail(string $customer_email): void + { $this->customer_email = $customer_email; } /** * @return string */ - public function getCustomerEmail(): string { + protected function getCustomerEmail(): string + { return $this->customer_email; } } diff --git a/src/Edd/Models/PluginData.php b/src/Edd/Models/PluginData.php index 5adbd58..d168611 100644 --- a/src/Edd/Models/PluginData.php +++ b/src/Edd/Models/PluginData.php @@ -1,200 +1,224 @@ api_url = trailingslashit( $url ); + protected function setApiUrl(string $url): void + { + $this->api_url = trailingslashit($url); } /** * @return string */ - public function getApiUrl(): string { + public function getApiUrl(): string + { return $this->api_url; } - /** - * @param array $data - */ - public function setApiData( array $data ) { - $this->api_data = $data; - } - - /** - * @return array - */ - public function getApiData(): array { - return $this->api_data; - } - /** * @param bool $allow_beta */ - public function setBeta( bool $allow_beta ) { + protected function setBeta(bool $allow_beta): void + { $this->beta = $allow_beta; } /** * @return bool */ - public function getBeta(): bool { + public function getBeta(): bool + { return $this->beta; } /** * @param int $item_id */ - public function setItemId( int $item_id ) { + protected function setItemId(int $item_id): void + { $this->item_id = $item_id; } /** * @return int */ - public function getItemId(): int { + public function getItemId(): int + { return $this->item_id; } + /** + * @param string $item_name + */ + protected function setItemName(string $item_name): void + { + $this->item_name = $item_name; + } + + /** + * @return string + */ + public function getItemName(): string + { + return $this->item_name; + } + /** * @param string $name */ - public function setName( string $name ) { + protected function setName(string $name): void + { $this->name = $name; } /** * @return string */ - public function getName(): string { + public function getName(): string + { return $this->name; } /** * @param string $license */ - public function setLicense( string $license ) { + protected function setLicense(string $license): void + { $this->license = $license; } /** * @return string */ - public function getLicense(): string { + public function getLicense(): string + { return $this->license; } /** * @param string $file */ - public function setPluginFile( string $file ) { + protected function setPluginFile(string $file): void + { $this->plugin_file = $file; } /** * @return string */ - public function getPluginFile(): string { + public function getPluginFile(): string + { return $this->plugin_file; } /** * @param string $slug */ - public function setSlug( string $slug ) { + protected function setSlug(string $slug): void + { $this->slug = $slug; } /** * @return string */ - public function getSlug(): string { + public function getSlug(): string + { return $this->slug; } /** * @param string $version */ - public function setVersion( string $version ) { + protected function setVersion(string $version): void + { $this->version = $version; } /** * @return string */ - public function getVersion(): string { + public function getVersion(): string + { return $this->version; } /** * @param bool $wp_override */ - public function setWpOverride( bool $wp_override ) { + protected function setWpOverride(bool $wp_override): void + { $this->wp_override = $wp_override; } /** * @return bool */ - public function getWpOverride(): bool { + public function getWpOverride(): bool + { return $this->wp_override; } /** * @param string $cache_key */ - public function setCacheKey( string $cache_key ) { + protected function setCacheKey(string $cache_key): void + { $this->cache_key = $cache_key; } /** * @return string */ - public function getCacheKey(): string { - return md5( serialize( $this->slug . $this->license . $this->beta ) ); + public function getCacheKey(): string + { + return $this->cache_key ?? md5(serialize($this->slug . $this->license . $this->beta)); } } diff --git a/src/Edd/PluginUpdater.php b/src/Edd/PluginUpdater.php index 42ffb54..023144c 100755 --- a/src/Edd/PluginUpdater.php +++ b/src/Edd/PluginUpdater.php @@ -1,69 +1,74 @@ plugin_data = new PluginData( $this->formatPluginData( $args ) ); - $edd_plugin_data[ $this->plugin_data->getSlug() ] = $this->plugin_data->getApiData(); + $this->api_url = trailingslashit($api_url); + $this->api_data = $api_data; + $this->plugin_file = $plugin_file; + $this->name = plugin_basename($plugin_file); + $this->slug = basename($plugin_file, '.php'); + $this->version = $api_data['version']; + $this->wp_override = isset($api_data['wp_override']) && $api_data['wp_override']; + $this->beta = !empty($this->api_data['beta']); + $this->failed_request_cache_key = 'edd_sl_failed_http_' . md5($this->api_url); + + $edd_plugin_data[$this->slug] = $this->api_data; + + /** + * Fires after the $edd_plugin_data is set up. + * @param array $edd_plugin_data Array of EDD SL plugin data. + */ + do_action('post_edd_sl_plugin_updater_setup', $edd_plugin_data); } /** - * Set up WordPress filters to hook into WP's update process. + * Add class hooks. */ - public function addHooks() { - $name = $this->plugin_data->getName(); - add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'checkUpdate' ] ); - add_filter( 'plugins_api', [ $this, 'pluginsApiFilter' ], 10, 3 ); - remove_action( 'after_plugin_row_' . $name, 'wp_plugin_update_row', 10 ); - add_action( 'after_plugin_row_' . $name, [ $this, 'showUpdateNotification' ], 10, 2 ); - add_action( 'admin_init', [ $this, 'showChangelog' ] ); + public function addHooks(): void + { + $this->addFilter('pre_set_site_transient_update_plugins', [$this, 'checkUpdate']); + $this->addFilter('plugins_api', [$this, 'pluginsApiFilter'], 10, 3); + $this->addAction('after_plugin_row', [$this, 'showUpdateNotification'], 10, 2); + $this->addAction('admin_init', [$this, 'showChangelog']); } /** @@ -74,418 +79,491 @@ public function addHooks() { * It is reassembled from parts of the native WordPress plugin update code. * See wp-includes/update.php line 121 for the original wp_update_plugins() function. * - * @uses getApiRequest() - * * @param mixed $value Update array build by WordPress. - * - * @return array Modified update array with custom plugin data. + * @return array|\stdClass Modified update array with custom plugin data. */ - public function checkUpdate( $value ) { - global $pagenow; - - if ( is_multisite() && 'plugins.php' === $pagenow ) { - return $value; + protected function checkUpdate(mixed $value): array|\stdClass + { + if (!is_object($value)) { + $value = new \stdClass(); } - $_transient_data = $value; - - if ( ! is_object( $_transient_data ) ) { - $_transient_data = new \stdClass(); - } - - if ( ! empty( $_transient_data->response ) && - ! empty( $_transient_data->response[ $this->plugin_data->getName() ] ) && - ! $this->plugin_data->getWpOverride() - ) { + if (!empty($value->response) && !empty($value->response[$this->name]) && false === $this->wp_override) { return $value; } - $version_info = $this->getCachedVersionInfo(); - - if ( $version_info === false ) { - $version_info = $this->getApiRequest( 'plugin_latest_version', - [ - 'slug' => $this->plugin_data->getSlug(), - 'beta' => $this->plugin_data->getBeta(), - ] - ); - - $this->setVersionInfoCache( $version_info ); - } - - if ( $version_info !== false && is_object( $version_info ) && isset( $version_info->new_version ) ) { - - if ( version_compare( $this->plugin_data->getVersion(), $version_info->new_version, '<' ) ) { - $_transient_data->response[ $this->plugin_data->getName() ] = $version_info; + $current = $this->getRepoApiData(); + if (false !== $current && is_object($current) && isset($current->new_version)) { + if (version_compare($this->version, $current->new_version, '<')) { + $value->response[$this->name] = $current; + } else { + // Populating the no_update information is required to support auto-updates in WordPress 5.5. + $value->no_update[$this->name] = $current; } - - $_transient_data->last_checked = current_time( 'timestamp' ); - $_transient_data->checked[ $this->plugin_data->getName() ] = $this->plugin_data->getVersion(); } + $value->last_checked = time(); + $value->checked[$this->name] = $this->version; - return $_transient_data; + return $value; } /** - * show update notification row -- needed for Multisite subsites, because WP won't tell you - * otherwise! - * - * @param string $plugin_file Path to the plugin file, relative to the plugins directory. - * @param array $plugin_data An array of plugin data. + * Updates information on the "View version x.x details" page with custom data. + * @param mixed $result + * @param string $action + * @param object|null $args + * @return mixed */ - public function showUpdateNotification( string $plugin_file, array $plugin_data ) { - if ( is_network_admin() || - ! current_user_can( 'update_plugins' ) || - ! is_multisite() || - $this->plugin_data->getName() !== $plugin_file - ) { - return; + protected function pluginsApiFilter(mixed $result, string $action = '', object $args = null): mixed + { + if ('plugin_information' !== $action) { + return $result; } - // Remove our filter on the site transient - remove_filter( 'pre_set_site_transient_update_plugins', [ $this, 'checkUpdate' ], 10 ); - - $update_cache = get_site_transient( 'update_plugins' ); - $update_cache = is_object( $update_cache ) ? $update_cache : new \stdClass(); - - if ( empty( $update_cache->response ) || empty( $update_cache->response[ $this->plugin_data->getName() ] ) ) { - - $version_info = $this->getCachedVersionInfo(); + if (!isset($args->slug) || $args->slug !== $this->slug) { + return $result; + } - if ( $version_info === false ) { - $version_info = $this->getApiRequest( 'plugin_latest_version', [ - 'slug' => $this->plugin_data->getSlug(), - 'beta' => $this->plugin_data->getBeta(), - ] ); + $to_send = [ + 'slug' => $this->slug, + 'is_ssl' => is_ssl(), + 'fields' => [ + 'banners' => [], + 'reviews' => false, + 'icons' => [], + ], + ]; - $this->setVersionInfoCache( $version_info ); - } + // Get the transient where we store the api request for this plugin for 24 hours + $edd_api_request_transient = $this->getCachedVersionInfo(); - if ( ! is_object( $version_info ) ) { - return; - } + //If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now. + if (empty($edd_api_request_transient)) { + $api_response = $this->apiRequest('plugin_information', $to_send); - if ( version_compare( $this->plugin_data->getVersion(), $version_info->new_version, '<' ) ) { - $update_cache->response[ $this->plugin_data->getName() ] = $version_info; + if ($api_response !== false) { + $this->setVersionInfoCache($api_response); + $result = $api_response; } - - $update_cache->last_checked = current_time( 'timestamp' ); - $update_cache->checked[ $this->plugin_data->getName() ] = $this->plugin_data->getVersion(); - - set_site_transient( 'update_plugins', $update_cache ); } else { - $version_info = $update_cache->response[ $this->plugin_data->getName() ]; + $result = $edd_api_request_transient; } - // Restore our filter - add_filter( 'pre_set_site_transient_update_plugins', [ $this, 'checkUpdate' ] ); + // Convert sections into an associative array, since we're getting an object, but Core expects an array. + if (isset($result->sections) && !is_array($result->sections)) { + $result->sections = $this->convertObjectToArray($result->sections); + } - if ( ! empty( $update_cache->response[ $this->plugin_data->getName() ] ) && - version_compare( $this->plugin_data->getVersion(), $version_info->new_version, '<' ) - ) { - // build a plugin list row, with update notification - echo ''; - echo ''; - echo '
'; - - $changelog_link = self_admin_url( - 'index.php?edd_sl_action=view_plugin_changelog&plugin=' . $this->plugin_data->getName() . - '&slug=' . $this->plugin_data->getSlug() . '&TB_iframe=true&width=772&height=911' - ); + // Convert banners into an associative array, since we're getting an object, but Core expects an array. + if (isset($result->banners) && !is_array($result->banners)) { + $result->banners = $this->convertObjectToArray($result->banners); + } - if ( empty( $version_info->download_link ) ) { - printf( - __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s.', 'dwnload' ), - esc_html( $version_info->name ), - '', - esc_html( $version_info->new_version ), - '' - ); - } else { - printf( - __( 'There is a new version of %1$s available. %2$sView version %3$s details%4$s or %5$supdate now%6$s.', 'dwnload' ), - esc_html( $version_info->name ), - '', - esc_html( $version_info->new_version ), - '', - '', - '' - ); - } + // Convert icons into an associative array, since we're getting an object, but Core expects an array. + if (isset($result->icons) && !is_array($result->icons)) { + $result->icons = $this->convertObjectToArray($result->icons); + } - /** - * - * @param array $plugin_data An array of plugin data. - * @param \stdClass $version_info - */ - do_action( "in_plugin_update_message-{$plugin_file}", $plugin_data, $version_info ); + // Convert contributors into an associative array, since we're getting an object, but Core expects an array. + if (isset($result->contributors) && !is_array($result->contributors)) { + $result->contributors = $this->convertObjectToArray($result->contributors); + } - echo '
'; + if (!isset($result->plugin)) { + $result->plugin = $this->name; } - } + return $result; + } + /** - * Updates information on the "View version x.x details" page with custom data. - * - * @uses getApiRequest() - * - * @param mixed $_data - * @param string $_action - * @param object $_args - * - * @return object $_data + * Show the update notification on multisite subsites. + * @param string $file + * @param array $plugin */ - public function pluginsApiFilter( $_data, $_action = '', $_args = null ) { - if ( $_action !== 'plugin_information' ) { - return $_data; + protected function showUpdateNotification(string $file, array $plugin): void + { + // Return early if in the network admin, or if this is not a multisite install. + if (is_network_admin() || !is_multisite()) { + return; } - if ( ! isset( $_args->slug ) || ( $_args->slug != $this->plugin_data->getSlug() ) ) { - return $_data; + // Allow single site admins to see that an update is available. + if (!current_user_can('activate_plugins')) { + return; } - $to_send = [ - 'slug' => $this->plugin_data->getSlug(), - 'is_ssl' => is_ssl(), - 'fields' => [ - 'banners' => [], - 'reviews' => false, - ], - ]; - - $cache_key = 'edd_api_request_' . - md5( - serialize( - $this->plugin_data->getSlug() . - $this->plugin_data->getLicense() . - $this->plugin_data->getBeta() - ) - ); - - // Get the transient where we store the api request for this plugin for 24 hours - $edd_api_request_transient = $this->getCachedVersionInfo( $cache_key ); - - // If we have no transient-saved value, run the API, set a fresh transient with the API value, and return that value too right now. - if ( empty( $edd_api_request_transient ) ) { - - $api_response = $this->getApiRequest( 'plugin_information', $to_send ); + if ($this->name !== $file) { + return; + } - // Expires in 3 hours - $this->setVersionInfoCache( $api_response, $cache_key ); + // Do not print any message if update does not exist. + $update_cache = get_site_transient('update_plugins'); - if ( false !== $api_response ) { - $_data = $api_response; + if (!isset($update_cache->response[$this->name])) { + if (!is_object($update_cache)) { + $update_cache = new \stdClass(); } - } else { - $_data = $edd_api_request_transient; + $update_cache->response[$this->name] = $this->getRepoApiData(); } - // Convert sections into an associative array, since we're getting an object, but Core expects an array. - if ( isset( $_data->sections ) && ! is_array( $_data->sections ) ) { - $new_sections = []; - foreach ( $_data->sections as $key => $value ) { - $new_sections[ $key ] = $value; - } - - $_data->sections = $new_sections; + // Return early if this plugin isn't in the transient->response or if the site is running the current or newer version of the plugin. + if ( + empty($update_cache->response[$this->name]) || + version_compare($this->version, $update_cache->response[$this->name]->new_version, '>=') + ) { + return; } - // Convert banners into an associative array, since we're getting an object, but Core expects an array. - if ( isset( $_data->banners ) && ! is_array( $_data->banners ) ) { - $new_banners = []; - foreach ( $_data->banners as $key => $value ) { - $new_banners[ $key ] = $value; - } - - $_data->banners = $new_banners; - } + printf( + '', + $this->slug, + $file, + in_array($this->name, $this->getActivePlugins(), true) ? 'active' : 'inactive' + ); - return $_data; - } + echo ''; + echo '

'; - /** - * Disable SSL verification in order to prevent download update failures - * - * @param array $args - * @param string $url - * - * @return array - */ - public function getModifiedHttpRequestArgs( $args, $url ) { - if ( strpos( $url, 'https://' ) !== false && strpos( $url, 'edd_action=package_download' ) ) { - $args['sslverify'] = $this->sslVerify(); + $changelog_link = ''; + if (!empty($update_cache->response[$this->name]->sections->changelog)) { + $changelog_link = add_query_arg( + [ + 'edd_sl_action' => 'view_plugin_changelog', + 'plugin' => urlencode($this->name), + 'slug' => urlencode($this->slug), + 'TB_iframe' => 'true', + 'width' => 77, + 'height' => 911, + ], + self_admin_url('index.php') + ); } + $update_link = add_query_arg( + [ + 'action' => 'upgrade-plugin', + 'plugin' => urlencode($this->name), + ], + self_admin_url('update.php') + ); + + printf( + /* translators: the plugin name. */ + esc_html__('There is a new version of %1$s available.', 'edd-software-license-manager'), + esc_html($plugin['Name']) + ); + + if (!current_user_can('update_plugins')) { + echo ' '; + esc_html_e('Contact your network administrator to install the update.', 'edd-software-license-manager'); + } elseif (empty($update_cache->response[$this->name]->package) && !empty($changelog_link)) { + echo ' '; + printf( + /* translators: 1. opening anchor tag, do not translate 2. the new plugin version 3. closing anchor tag, do not translate. */ + __('%1$sView version %2$s details%3$s.', 'edd-software-license-manager'), + '', + esc_html($update_cache->response[$this->name]->new_version), + '' + ); + } elseif (!empty($changelog_link)) { + echo ' '; + printf( + __('%1$sView version %2$s details%3$s or %4$supdate now%5$s.', 'edd-software-license-manager'), + '', + esc_html($update_cache->response[$this->name]->new_version), + '', + '', + '' + ); + } else { + printf( + ' %1$s%2$s%3$s', + '', + esc_html__('Update now.', 'edd-software-license-manager'), + '' + ); + } + + do_action("in_plugin_update_message-$file", $plugin, $plugin); - return $args; + echo '

'; } /** - * Helper function to show the changelog. + * If available, show the changelog. */ - public function showChangelog() { - global $edd_plugin_data; + protected function showChangelog(): void + { + if (empty($_REQUEST['edd_sl_action']) || 'view_plugin_changelog' !== $_REQUEST['edd_sl_action']) { + return; + } - if ( empty( $_REQUEST['edd_sl_action'] ) || $_REQUEST['edd_sl_action'] !== 'view_plugin_changelog' ) { + if (empty($_REQUEST['plugin'])) { return; } - if ( empty( $_REQUEST['plugin'] ) || empty( $_REQUEST['slug'] ) ) { + if (empty($_REQUEST['slug']) || $this->slug !== $_REQUEST['slug']) { return; } - if ( ! current_user_can( 'update_plugins' ) ) { + if (!current_user_can('update_plugins')) { wp_die( - esc_html__( 'You do not have permission to install plugin updates', 'dwnload' ), - esc_html__( 'Error', 'dwnload' ), - [ 'response' => \WP_Http::FORBIDDEN ] + esc_html__('You do not have permission to install plugin updates', 'edd-software-license-manager'), + esc_html__('Error', 'edd-software-license-manager'), + ['response' => 403] ); } - $data = $edd_plugin_data[ $_REQUEST['slug'] ]; - $beta = ! empty( $data['beta'] ) ? true : false; - $cache_key = md5( 'edd_plugin_' . sanitize_key( $_REQUEST['plugin'] ) . '_' . $beta . '_version_info' ); - $version_info = $this->getCachedVersionInfo( $cache_key ); - - if ( $version_info === false ) { - $api_params = [ - 'edd_action' => 'get_version', - 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false, - 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false, - 'slug' => $_REQUEST['slug'], - 'author' => $data['author'], - 'url' => home_url(), - 'beta' => ! empty( $data['beta'] ), - ]; - - $request = wp_remote_post( esc_url_raw( $this->plugin_data->getApiUrl() ), [ - 'timeout' => 15, - 'sslverify' => $this->sslVerify(), - 'body' => $api_params, - ] ); - - if ( ! is_wp_error( $request ) ) { - $version_info = json_decode( wp_remote_retrieve_body( $request ) ); + $version_info = $this->getRepoApiData(); + if (isset($version_info->sections)) { + $sections = $this->convertObjectToArray($version_info->sections); + if (!empty($sections['changelog'])) { + echo '
' . wp_kses_post($sections['changelog']) . '
'; } + } - if ( ! empty( $version_info ) && isset( $version_info->sections ) ) { - $version_info->sections = maybe_unserialize( $version_info->sections ); - } else { - $version_info = false; - } + exit; + } + + /** + * Get repo API data from store. + * Save to cache. + * @return false|object + */ + private function getRepoApiData(): false|object + { + $version_info = $this->getCachedVersionInfo(); - if ( ! empty( $version_info ) ) { - foreach ( $version_info->sections as $key => $section ) { - $version_info->$key = (array)$section; - } + if ($version_info === false) { + $version_info = $this->apiRequest( + 'plugin_latest_version', + [ + 'slug' => $this->slug, + 'beta' => $this->beta, + ] + ); + if (!$version_info) { + return false; } - $this->setVersionInfoCache( $version_info, $cache_key ); - } + // This is required for your plugin to support auto-updates in WordPress 5.5. + $version_info->plugin = $this->name; + $version_info->id = $this->name; + $version_info->tested = $this->getTestedVersion($version_info); - if ( ! empty( $version_info ) && isset( $version_info->sections['changelog'] ) ) { - echo '
' . $version_info->sections['changelog'] . '
'; + $this->setVersionInfoCache($version_info); } - exit; + return $version_info; } /** - * @param string $cache_key + * Gets the plugin's tested version. * - * @return array|bool|mixed|object + * @param object $version_info + * @return null|string */ - protected function getCachedVersionInfo( string $cache_key = '' ) { - if ( empty( $cache_key ) ) { - $cache_key = $this->plugin_data->getCacheKey(); + private function getTestedVersion(object $version_info): ?string + { + // There is no tested version. + if (empty($version_info->tested)) { + return null; } - $cache = get_option( $cache_key ); + // Strip off extra version data so the result is x.y or x.y.z. + [$current_wp_version] = explode('-', get_bloginfo('version')); - if ( empty( $cache['timeout'] ) || current_time( 'timestamp' ) > $cache['timeout'] ) { - return false; // Cache is expired + // The tested version is greater than or equal to the current WP version, no need to do anything. + if (version_compare($version_info->tested, $current_wp_version, '>=')) { + return $version_info->tested; } - return json_decode( $cache['value'] ); + $current_version_parts = explode('.', $current_wp_version); + $tested_parts = explode('.', $version_info->tested); + + // The current WordPress version is x.y.z, so update the tested version to match it. + if (isset($current_version_parts[2]) && $current_version_parts[0] === $tested_parts[0] && $current_version_parts[1] === $tested_parts[1]) { + $tested_parts[2] = $current_version_parts[2]; + } + + return implode('.', $tested_parts); } /** - * @param string $value - * @param string $cache_key + * Gets the plugins active in a multisite network. + * @return array */ - protected function setVersionInfoCache( string $value = '', string $cache_key = '' ) { - if ( empty( $cache_key ) ) { - $cache_key = $this->plugin_data->getCacheKey(); + private function getActivePlugins(): array + { + $active_plugins = (array)get_option('active_plugins'); + $active_network_plugins = (array)get_site_option('active_sitewide_plugins'); + + return array_merge($active_plugins, array_keys($active_network_plugins)); + } + + /** + * Convert some objects to arrays when injecting data into the update API + * Some data like sections, banners, and icons are expected to be an associative array, however due to the JSON + * decoding, they are objects. This method allows us to pass in the object and return an associative array. + * + * @param mixed $data + * @return array + */ + private function convertObjectToArray(mixed $data): array + { + if (!is_array($data) && !is_object($data)) { + return []; } - $data = [ - 'timeout' => strtotime( '+3 hours', current_time( 'timestamp' ) ), - 'value' => json_encode( $value ), - ]; + $new_data = []; + foreach ($data as $key => $value) { + $new_data[$key] = is_object($value) ? $this->convertObjectToArray($value) : $value; + } - update_option( $cache_key, $data, 'no' ); + return $new_data; } /** * Calls the API and, if successful, returns the object delivered by the API. * - * @uses get_bloginfo() - * @uses wp_remote_post() - * @uses is_wp_error() - * * @param string $action The requested action. - * @param array $args Parameters for the API action. - * - * @return false|object + * @param array $data Parameters for the API action. + * @return object|bool */ - private function getApiRequest( string $action, array $args ) { - $data = array_merge( $this->plugin_data->getApiData(), $args ); + private function apiRequest(string $action, array $data): object|bool + { + $data = array_merge($this->api_data, $data); - if ( $this->plugin_data->getSlug() !== $data['slug'] ) { + if ($data['slug'] !== $this->slug) { return false; } - if ( $this->plugin_data->getApiUrl() === trailingslashit( home_url() ) ) { - return false; // Don't allow a plugin to ping itself + // Don't allow a plugin to ping itself + if (trailingslashit(home_url()) === $this->api_url) { + return false; } + if ($this->requestRecentlyFailed()) { + return false; + } + + return $this->getVersionFromRemote(); + } + + /** + * Determines if a request has recently failed. + * @return bool + */ + private function requestRecentlyFailed(): bool + { + $failed_request_details = get_option($this->failed_request_cache_key); + + // Request has never failed. + if (empty($failed_request_details) || !is_numeric($failed_request_details)) { + return false; + } + + /* + * Request previously failed, but the timeout has expired. + * This means we're allowed to try again. + */ + if (time() > $failed_request_details) { + delete_option($this->failed_request_cache_key); + + return false; + } + + return true; + } + + /** + * Logs a failed HTTP request for this API URL. + * We set a timestamp for 1 hour from now. This prevents future API requests from being + * made to this domain for 1 hour. Once the timestamp is in the past, API requests + * will be allowed again. This way if the site is down for some reason we don't bombard + * it with failed API requests. + * @see EDD_SL_Plugin_Updater::requestRecentlyFailed + */ + private function logFailedRequest(): void + { + update_option($this->failed_request_cache_key, strtotime('+1 hour')); + } + + /** + * Gets the current version information from the remote site. + * @return object|bool + */ + private function getVersionFromRemote(): object|bool + { $api_params = [ - 'edd_action' => $action, // 'get_version', - 'license' => ! empty( $data['license'] ) ? $data['license'] : '', - 'item_name' => isset( $data['item_name'] ) ? $data['item_name'] : false, - 'item_id' => isset( $data['item_id'] ) ? $data['item_id'] : false, - 'version' => isset( $data['version'] ) ? $data['version'] : false, - 'slug' => $data['slug'], - 'author' => $data['author'], + 'edd_action' => 'get_version', + 'license' => !empty($this->api_data['license']) ? $this->api_data['license'] : '', + 'item_name' => $this->api_data['item_name'] ?? false, + 'item_id' => $this->api_data['item_id'] ?? false, + 'version' => $this->api_data['version'] ?? false, + 'slug' => $this->slug, + 'author' => $this->api_data['author'], 'url' => home_url(), - 'beta' => ! empty( $data['beta'] ), + 'beta' => $this->beta, + 'php_version' => phpversion(), + 'wp_version' => get_bloginfo('version'), ]; - $request = wp_remote_post( esc_url_raw( $this->plugin_data->getApiUrl() ), [ - 'timeout' => 15, - 'sslverify' => $this->sslVerify(), - 'body' => $api_params, - ] ); + /** + * Filters the parameters sent in the API request. + * + * @param array $api_params The array of data sent in the request. + * @param array $this ->api_data The array of data set up in the class constructor. + * @param string $this ->plugin_file The full path and filename of the file. + */ + $api_params = apply_filters( + 'edd_sl_plugin_updater_api_params', + $api_params, + $this->api_data, + $this->plugin_file + ); + + $request = wp_remote_post( + $this->api_url, + [ + 'timeout' => 15, + 'sslverify' => $this->verifySsl(), + 'body' => $api_params, + ] + ); + + if (is_wp_error($request) || (200 !== wp_remote_retrieve_response_code($request))) { + $this->logFailedRequest(); - if ( ! is_wp_error( $request ) ) { - $request = json_decode( wp_remote_retrieve_body( $request ) ); + return false; } - if ( $request && isset( $request->sections ) ) { - $request->sections = maybe_unserialize( $request->sections ); + $request = json_decode(wp_remote_retrieve_body($request)); + + if ($request && isset($request->sections)) { + $request->sections = maybe_unserialize($request->sections); } else { $request = false; } - if ( $request && isset( $request->banners ) ) { - $request->banners = maybe_unserialize( $request->banners ); + if ($request && isset($request->banners)) { + $request->banners = maybe_unserialize($request->banners); + } + + if ($request && isset($request->icons)) { + $request->icons = maybe_unserialize($request->icons); } - if ( ! empty( $request->sections ) ) { - foreach ( $request->sections as $key => $section ) { + if (!empty($request->sections)) { + foreach ($request->sections as $key => $section) { $request->$key = (array)$section; } } @@ -493,26 +571,72 @@ private function getApiRequest( string $action, array $args ) { return $request; } + /** + * Get the version info from the cache, if it exists. + * @param string $cache_key + * @return object|bool + */ + private function getCachedVersionInfo(string $cache_key = ''): object|bool + { + if (empty($cache_key)) { + $cache_key = $this->getCacheKey(); + } + + $cache = get_option($cache_key); + + // Cache is expired + if (empty($cache['timeout']) || time() > $cache['timeout']) { + return false; + } + + // We need to turn the icons into an array, thanks to WP Core forcing these into an object at some point. + $cache['value'] = json_decode($cache['value']); + if (!empty($cache['value']->icons)) { + $cache['value']->icons = (array)$cache['value']->icons; + } + + return $cache['value']; + } + + /** + * Adds the plugin version information to the database. + * @param object $value + * @param string|null $cache_key + */ + private function setVersionInfoCache(object $value, ?string $cache_key = null): void + { + if (empty($cache_key)) { + $cache_key = $this->getCacheKey(); + } + + $data = [ + 'timeout' => strtotime('+3 hours', time()), + 'value' => wp_json_encode($value), + ]; + + update_option($cache_key, $data, 'no'); + + // Delete the duplicate option + delete_option('edd_api_request_' . md5(serialize($this->slug . $this->api_data['license'] . $this->beta))); + } + /** * Returns if the SSL of the store should be verified. - * * @return bool */ - private function sslVerify(): bool { - return (bool) apply_filters( 'edd_sl_api_request_verify_ssl', true, $this ); + private function verifySsl(): bool + { + return (bool)apply_filters('edd_sl_api_request_verify_ssl', true, $this); } /** - * @param array $args - * - * @return array + * Gets the unique key (option name) for a plugin. + * @return string */ - private function formatPluginData( array $args ): array { - // Make sure $plugin_file is the first key in the array! - $args = [ 'plugin_file' => $args['plugin_file'] ] + $args; - - $license = isset( $args['license'] ) ? $args['license'] : $args['api_data']['license'] ?? ''; + private function getCacheKey(): string + { + $string = $this->slug . $this->api_data['license'] . $this->beta; - return $args + [ 'license' => $license ]; + return 'edd_sl_' . md5(serialize($string)); } } diff --git a/views/license.php b/views/license.php index 4e289c8..28be096 100644 --- a/views/license.php +++ b/views/license.php @@ -1,45 +1,59 @@ getSettingField(); -$license_key = Options::getOption( $field->getName(), $field->getSectionId() ); -$license_data = get_option( LicenseManager::LICENSE_SETTING, [] ); -$license_status = $license_data['status'] ?? LicenseStatus::LICENSE_INACTIVE; +if (!isset($plugin_id) || !isset($section_id)) { + return; +} +$license_key = Options::getOption($plugin_id, $section_id); +$license_data = get_option(AbstractLicenceManager::LICENSE_SETTING, []); +$license_expires = $license_data[$plugin_id]['expires'] ?? ''; +$license_status = $license_data[$plugin_id]['status'] ?? LicenseStatus::LICENSE_INACTIVE; -if ( empty( $license_key ) ) { - echo 'Please save your license key.'; +ob_start(); - return; +echo "
"; +printf('License Status: %1$s', $license_status); +if (!empty($license_expires)) { + printf( + ' — License Expires: %1$s', + date_i18n(get_option('date_format'), strtotime($license_expires)) + ); } -printf('

License Status: %1$s

', $license_status ); +echo '

'; -if ( ! empty( $license_data ) && $license_data['status'] === LicenseStatus::LICENSE_ACTIVE ) { - $this->getSubmitButton( - $this->getStrings()['deactivate-license'], +if (!empty($license_data) && $license_status === LicenseStatus::LICENSE_ACTIVE) { + $this->buildSubmitButton( + $plugin_id, 'button-primary', LicenseStatus::LICENSE_DEACTIVATE, - $license_status + $license_status, ); echo '  '; - $this->getSubmitButton( - $this->getStrings()['check-license'], + $this->buildSubmitButton( + $plugin_id, 'button-secondary', LicenseStatus::LICENSE_CHECK_LICENSE, $license_status ); } else { - $this->getSubmitButton( - $this->getStrings()['activate-license'], - 'button-primary', + $this->buildSubmitButton( + $plugin_id, + empty($license_key) ? 'button-primary disabled' : 'button-primary', LicenseStatus::LICENSE_ACTIVATE, $license_status ); } +echo '
'; + +return ob_get_clean();