diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index b6becea2..09b091d5 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -21,7 +21,7 @@ jobs: - name: Setup proper PHP version uses: shivammathur/setup-php@v2 with: - php-version: 7.4 + php-version: 8.0 - name: Install Composer dependencies run: composer install --no-interaction --no-progress --no-suggest --optimize-autoloader @@ -34,10 +34,10 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - php: [ 5.6, 7.0, 7.1, 7.2, 7.3, 7.4, 8.0, 8.1 ] + php: [ 8.0, 8.1, 8.2, 8.3, 8.4 ] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: ref: ${{ github.event.inputs.ref }} diff --git a/.wordpress-org/banner-1544x500.png b/.wordpress-org/banner-1544x500.png index ed0b7d05..7ff495db 100644 Binary files a/.wordpress-org/banner-1544x500.png and b/.wordpress-org/banner-1544x500.png differ diff --git a/.wordpress-org/banner-772x250.png b/.wordpress-org/banner-772x250.png index 2f4d901f..c7cc37fb 100644 Binary files a/.wordpress-org/banner-772x250.png and b/.wordpress-org/banner-772x250.png differ diff --git a/.wordpress-org/icon-128x128.png b/.wordpress-org/icon-128x128.png index b4121d21..9ebd3136 100644 Binary files a/.wordpress-org/icon-128x128.png and b/.wordpress-org/icon-128x128.png differ diff --git a/.wordpress-org/icon-256x256.png b/.wordpress-org/icon-256x256.png index 91888915..90b76866 100644 Binary files a/.wordpress-org/icon-256x256.png and b/.wordpress-org/icon-256x256.png differ diff --git a/bin/build-zip.sh b/bin/build-zip.sh index 7f7dac3d..e379adb5 100755 --- a/bin/build-zip.sh +++ b/bin/build-zip.sh @@ -12,9 +12,9 @@ fi echo "➤ Preparing zip for $VERSION of $SLUG..." echo "➤ Building plugin..." -npm install && npm run build composer install composer update --no-dev --no-scripts +npm install && npm run build echo "✓ Plugin built!" # if directory already exists, delete it diff --git a/bin/release.sh b/bin/release.sh index 883fa9f2..22ca844d 100755 --- a/bin/release.sh +++ b/bin/release.sh @@ -16,12 +16,6 @@ fi echo "Preparing release $VERSION for $SLUG..." -echo "➤ Building plugin..." -npm install && npm run build -composer install -composer update --no-dev --no-scripts -echo "✓ Plugin built!" - # Check if svn user name is provided with -u flag and password with -p flag while getopts u:p: flag; do case "${flag}" in @@ -36,6 +30,17 @@ if [ -z "$SVN_USER" ] || [ -z "$SVN_PASSWORD" ]; then exit 1 fi +# Replace the version in readme.txt +sed -i '' "s/Stable tag: .*/Stable tag: $VERSION/" readme.txt +# Replace the version in plugin file +sed -i '' "s/Version: .*/Version: $VERSION/" $SLUG.php + +echo "➤ Building plugin..." +npm install && npm run build +composer install +composer update --no-dev --no-scripts +echo "✓ Plugin built!" + # if directory already exists, delete it if [ -d "$SVN_DIR" ]; then rm -rf $SVN_DIR @@ -63,9 +68,9 @@ find "$SVN_DIR/trunk/" -type d -empty -delete # Copy assets # If .wordpress-org is a directory and contains files, copy them to the SVN repo. -if [[ -d "$WORKSPACE/.wordpress-org" ]]; then +if [[ -d "$WORKING_DIR/.wordpress-org" ]]; then echo "➤ Copying assets..." - rsync -rc "$WORKSPACE/.wordpress-org/" "$SVN_DIR/assets/" --delete --delete-excluded + rsync -rc "$WORKING_DIR/.wordpress-org/" "$SVN_DIR/assets/" --delete --delete-excluded # Fix screenshots getting force downloaded when clicking them # https://developer.wordpress.org/plugins/wordpress-org/plugin-assets/ if test -d "$SVN_DIR/assets" && test -n "$(find "$SVN_DIR/assets" -maxdepth 1 -name "*.png" -print -quit)"; then diff --git a/composer.json b/composer.json index 9be86780..219bc5a2 100644 --- a/composer.json +++ b/composer.json @@ -7,10 +7,6 @@ "prefer-stable": true, "minimum-stability": "dev", "repositories": [ - { - "url": "git@github.com:byteever/byteever-sniffs.git", - "type": "github" - }, { "url": "git@github.com:pluginever/framework-plugin.git", "type": "github" @@ -28,7 +24,7 @@ "php": ">=7.0" }, "require-dev": { - "byteever/byteever-sniffs": "dev-master", + "byteever/byteever-sniffs": "^1.0", "codeception/lib-innerbrowser": "^1.0", "codeception/module-asserts": "^1.1", "codeception/module-cli": "^1.0", @@ -42,9 +38,9 @@ "level-level/wp-browser-woocommerce": "^0.1.8", "lucatume/wp-browser": "^3.1", "phpcompatibility/php-compatibility": "9.3.5", + "pluginever/framework-model": "dev-master", "pluginever/framework-plugin": "dev-master", - "pluginever/framework-settings": "dev-master", - "pluginever/framework-model": "dev-master" + "pluginever/framework-settings": "dev-master" }, "config": { "optimize-autoloader": true, diff --git a/composer.lock b/composer.lock index 310af389..561af23e 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d0754e64a5fccfc9c1bfbe9128d8df80", + "content-hash": "1708bb6e2309c5b3f2b0c1d7ea103daf", "packages": [], "packages-dev": [ { @@ -176,43 +176,28 @@ }, { "name": "byteever/byteever-sniffs", - "version": "dev-master", + "version": "v1.0.1", "source": { "type": "git", "url": "https://github.com/byteever/byteever-sniffs.git", - "reference": "12bbcbbd8bbdda2bd325ee7d744bbfb2378f3a02" + "reference": "8c20a95245a883bcbaea42e46653f7f788bf8290" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/byteever/byteever-sniffs/zipball/12bbcbbd8bbdda2bd325ee7d744bbfb2378f3a02", - "reference": "12bbcbbd8bbdda2bd325ee7d744bbfb2378f3a02", + "url": "https://api.github.com/repos/byteever/byteever-sniffs/zipball/8c20a95245a883bcbaea42e46653f7f788bf8290", + "reference": "8c20a95245a883bcbaea42e46653f7f788bf8290", "shasum": "" }, "require": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.7.1", - "phpcompatibility/phpcompatibility-wp": "2.1.0", - "wp-coding-standards/wpcs": "^2.3.0" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7", + "phpcompatibility/phpcompatibility-wp": "^2.1", + "wp-coding-standards/wpcs": "^3.0" }, "require-dev": { "roave/security-advisories": "dev-latest" }, - "default-branch": true, "type": "phpcodesniffer-standard", - "scripts": { - "config-cs": [ - "Dealerdirect\\Composer\\Plugin\\Installers\\PHPCodeSniffer\\Plugin::run", - "\"vendor/bin/phpcs\" --config-set default_standard ByteEver-Default" - ], - "post-install-cmd": [ - "@config-cs" - ], - "post-update-cmd": [ - "@config-cs" - ], - "lint": [ - "\"vendor/bin/phpcs\" . " - ] - }, + "notification-url": "https://packagist.org/downloads/", "license": [ "GPL-3.0-only" ], @@ -224,16 +209,16 @@ ], "description": "ByteEver PHP Coding Standards", "keywords": [ - "WordPress", "byteever", "phpcs", - "standards" + "standards", + "wordpress" ], "support": { - "source": "https://github.com/byteever/byteever-sniffs/tree/master", - "issues": "https://github.com/byteever/byteever-sniffs/issues" + "issues": "https://github.com/byteever/byteever-sniffs/issues", + "source": "https://github.com/byteever/byteever-sniffs/tree/v1.0.1" }, - "time": "2022-11-21T08:46:53+00:00" + "time": "2023-10-25T04:55:22+00:00" }, { "name": "codeception/codeception", @@ -1613,7 +1598,7 @@ }, { "name": "illuminate/collections", - "version": "v9.52.15", + "version": "v9.52.16", "source": { "type": "git", "url": "https://github.com/illuminate/collections.git", @@ -1668,7 +1653,7 @@ }, { "name": "illuminate/conditionable", - "version": "v9.52.15", + "version": "v9.52.16", "source": { "type": "git", "url": "https://github.com/illuminate/conditionable.git", @@ -1714,7 +1699,7 @@ }, { "name": "illuminate/contracts", - "version": "v9.52.15", + "version": "v9.52.16", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -1762,7 +1747,7 @@ }, { "name": "illuminate/macroable", - "version": "v9.52.15", + "version": "v9.52.16", "source": { "type": "git", "url": "https://github.com/illuminate/macroable.git", @@ -1808,7 +1793,7 @@ }, { "name": "illuminate/support", - "version": "v9.52.15", + "version": "v9.52.16", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", @@ -1879,16 +1864,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "5.2.12", + "version": "v5.2.13", "source": { "type": "git", "url": "https://github.com/justinrainbow/json-schema.git", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60" + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", - "reference": "ad87d5a5ca981228e0e205c2bc7dfb8e24559b60", + "url": "https://api.github.com/repos/justinrainbow/json-schema/zipball/fbbe7e5d79f618997bc3332a6f49246036c45793", + "reference": "fbbe7e5d79f618997bc3332a6f49246036c45793", "shasum": "" }, "require": { @@ -1943,9 +1928,9 @@ ], "support": { "issues": "https://github.com/justinrainbow/json-schema/issues", - "source": "https://github.com/justinrainbow/json-schema/tree/5.2.12" + "source": "https://github.com/justinrainbow/json-schema/tree/v5.2.13" }, - "time": "2022-04-13T08:02:27+00:00" + "time": "2023-09-26T02:20:38+00:00" }, { "name": "league/flysystem", @@ -2043,16 +2028,16 @@ }, { "name": "league/mime-type-detection", - "version": "1.13.0", + "version": "1.14.0", "source": { "type": "git", "url": "https://github.com/thephpleague/mime-type-detection.git", - "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96" + "reference": "b6a5854368533df0295c5761a0253656a2e52d9e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/a6dfb1194a2946fcdc1f38219445234f65b35c96", - "reference": "a6dfb1194a2946fcdc1f38219445234f65b35c96", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b6a5854368533df0295c5761a0253656a2e52d9e", + "reference": "b6a5854368533df0295c5761a0253656a2e52d9e", "shasum": "" }, "require": { @@ -2083,7 +2068,7 @@ "description": "Mime-type detection for Flysystem", "support": { "issues": "https://github.com/thephpleague/mime-type-detection/issues", - "source": "https://github.com/thephpleague/mime-type-detection/tree/1.13.0" + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.14.0" }, "funding": [ { @@ -2095,7 +2080,7 @@ "type": "tidelift" } ], - "time": "2023-08-05T12:09:49+00:00" + "time": "2023-10-17T14:13:20+00:00" }, { "name": "level-level/wp-browser-woocommerce", @@ -2737,16 +2722,16 @@ }, { "name": "php-webdriver/webdriver", - "version": "1.15.0", + "version": "1.15.1", "source": { "type": "git", "url": "https://github.com/php-webdriver/php-webdriver.git", - "reference": "a1578689290055586f1ee51eaf0ec9d52895bb6d" + "reference": "cd52d9342c5aa738c2e75a67e47a1b6df97154e8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/a1578689290055586f1ee51eaf0ec9d52895bb6d", - "reference": "a1578689290055586f1ee51eaf0ec9d52895bb6d", + "url": "https://api.github.com/repos/php-webdriver/php-webdriver/zipball/cd52d9342c5aa738c2e75a67e47a1b6df97154e8", + "reference": "cd52d9342c5aa738c2e75a67e47a1b6df97154e8", "shasum": "" }, "require": { @@ -2755,7 +2740,7 @@ "ext-zip": "*", "php": "^7.3 || ^8.0", "symfony/polyfill-mbstring": "^1.12", - "symfony/process": "^5.0 || ^6.0" + "symfony/process": "^5.0 || ^6.0 || ^7.0" }, "replace": { "facebook/webdriver": "*" @@ -2797,9 +2782,9 @@ ], "support": { "issues": "https://github.com/php-webdriver/php-webdriver/issues", - "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.0" + "source": "https://github.com/php-webdriver/php-webdriver/tree/1.15.1" }, - "time": "2023-08-29T13:52:26+00:00" + "time": "2023-10-20T12:21:20+00:00" }, { "name": "phpcompatibility/php-compatibility", @@ -2922,16 +2907,16 @@ }, { "name": "phpcompatibility/phpcompatibility-wp", - "version": "2.1.0", + "version": "2.1.4", "source": { "type": "git", "url": "https://github.com/PHPCompatibility/PHPCompatibilityWP.git", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f" + "reference": "b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/41bef18ba688af638b7310666db28e1ea9158b2f", - "reference": "41bef18ba688af638b7310666db28e1ea9158b2f", + "url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityWP/zipball/b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5", + "reference": "b6c1e3ee1c35de6c41a511d5eb9bd03e447480a5", "shasum": "" }, "require": { @@ -2939,10 +2924,10 @@ "phpcompatibility/phpcompatibility-paragonie": "^1.0" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5" + "dealerdirect/phpcodesniffer-composer-installer": "^0.7" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", + "dealerdirect/phpcodesniffer-composer-installer": "^0.7 || This Composer plugin will sort out the PHP_CodeSniffer 'installed_paths' automatically.", "roave/security-advisories": "dev-master || Helps prevent installing dependencies with known security issues." }, "type": "phpcodesniffer-standard", @@ -2966,13 +2951,150 @@ "compatibility", "phpcs", "standards", + "static analysis", "wordpress" ], "support": { "issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues", "source": "https://github.com/PHPCompatibility/PHPCompatibilityWP" }, - "time": "2019-08-28T14:22:28+00:00" + "time": "2022-10-24T09:00:36+00:00" + }, + { + "name": "phpcsstandards/phpcsextra", + "version": "1.1.2", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSExtra.git", + "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSExtra/zipball/746c3190ba8eb2f212087c947ba75f4f5b9a58d5", + "reference": "746c3190ba8eb2f212087c947ba75f4f5b9a58d5", + "shasum": "" + }, + "require": { + "php": ">=5.4", + "phpcsstandards/phpcsutils": "^1.0.8", + "squizlabs/php_codesniffer": "^3.7.1" + }, + "require-dev": { + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.6", + "phpcsstandards/phpcsdevtools": "^1.2.1", + "phpunit/phpunit": "^4.5 || ^5.0 || ^6.0 || ^7.0" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSExtra/graphs/contributors" + } + ], + "description": "A collection of sniffs and standards for use with PHP_CodeSniffer.", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "standards", + "static analysis" + ], + "support": { + "issues": "https://github.com/PHPCSStandards/PHPCSExtra/issues", + "source": "https://github.com/PHPCSStandards/PHPCSExtra" + }, + "time": "2023-09-20T22:06:18+00:00" + }, + { + "name": "phpcsstandards/phpcsutils", + "version": "1.0.8", + "source": { + "type": "git", + "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", + "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/69465cab9d12454e5e7767b9041af0cd8cd13be7", + "reference": "69465cab9d12454e5e7767b9041af0cd8cd13be7", + "shasum": "" + }, + "require": { + "dealerdirect/phpcodesniffer-composer-installer": "^0.4.1 || ^0.5 || ^0.6.2 || ^0.7 || ^1.0", + "php": ">=5.4", + "squizlabs/php_codesniffer": "^3.7.1 || 4.0.x-dev@dev" + }, + "require-dev": { + "ext-filter": "*", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", + "phpcsstandards/phpcsdevcs": "^1.1.6", + "yoast/phpunit-polyfills": "^1.0.5 || ^2.0.0" + }, + "type": "phpcodesniffer-standard", + "extra": { + "branch-alias": { + "dev-stable": "1.x-dev", + "dev-develop": "1.x-dev" + } + }, + "autoload": { + "classmap": [ + "PHPCSUtils/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Juliette Reinders Folmer", + "homepage": "https://github.com/jrfnl", + "role": "lead" + }, + { + "name": "Contributors", + "homepage": "https://github.com/PHPCSStandards/PHPCSUtils/graphs/contributors" + } + ], + "description": "A suite of utility functions for use with PHP_CodeSniffer", + "homepage": "https://phpcsutils.com/", + "keywords": [ + "PHP_CodeSniffer", + "phpcbf", + "phpcodesniffer-standard", + "phpcs", + "phpcs3", + "standards", + "static analysis", + "tokens", + "utility" + ], + "support": { + "docs": "https://phpcsutils.com/", + "issues": "https://github.com/PHPCSStandards/PHPCSUtils/issues", + "source": "https://github.com/PHPCSStandards/PHPCSUtils" + }, + "time": "2023-07-16T21:39:41+00:00" }, { "name": "phpunit/php-code-coverage", @@ -3402,12 +3524,12 @@ "source": { "type": "git", "url": "git@github.com:pluginever/framework-model.git", - "reference": "b1ab33c420c06012ba7dd1ddb873d082d5e272cc" + "reference": "5a5de16e378f2a7a3b8ba95d1eb3569f7a3a6574" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pluginever/framework-model/zipball/b1ab33c420c06012ba7dd1ddb873d082d5e272cc", - "reference": "b1ab33c420c06012ba7dd1ddb873d082d5e272cc", + "url": "https://api.github.com/repos/pluginever/framework-model/zipball/5a5de16e378f2a7a3b8ba95d1eb3569f7a3a6574", + "reference": "5a5de16e378f2a7a3b8ba95d1eb3569f7a3a6574", "shasum": "" }, "require": { @@ -3442,10 +3564,10 @@ ], "description": "Model for the framework", "support": { - "source": "https://github.com/pluginever/framework-model/tree/master", + "source": "https://github.com/pluginever/framework-model/tree/v1.0.8", "issues": "https://github.com/pluginever/framework-model/issues" }, - "time": "2023-08-10T07:52:03+00:00" + "time": "2023-10-25T08:49:24+00:00" }, { "name": "pluginever/framework-plugin", @@ -3453,12 +3575,12 @@ "source": { "type": "git", "url": "git@github.com:pluginever/framework-plugin.git", - "reference": "d24ae94397a74d334b450f02bfffb1c52d8cebc6" + "reference": "dd76127abd4a0c6dd8253fe6b885a807dfe8e4e0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pluginever/framework-plugin/zipball/d24ae94397a74d334b450f02bfffb1c52d8cebc6", - "reference": "d24ae94397a74d334b450f02bfffb1c52d8cebc6", + "url": "https://api.github.com/repos/pluginever/framework-plugin/zipball/dd76127abd4a0c6dd8253fe6b885a807dfe8e4e0", + "reference": "dd76127abd4a0c6dd8253fe6b885a807dfe8e4e0", "shasum": "" }, "require": { @@ -3493,10 +3615,10 @@ ], "description": "A set of related classes to kick start WordPress plugin development.", "support": { - "source": "https://github.com/pluginever/framework-plugin/tree/master", + "source": "https://github.com/pluginever/framework-plugin/tree/v1.0.8", "issues": "https://github.com/pluginever/framework-plugin/issues" }, - "time": "2023-09-24T10:21:09+00:00" + "time": "2023-10-25T08:44:40+00:00" }, { "name": "pluginever/framework-settings", @@ -3504,12 +3626,12 @@ "source": { "type": "git", "url": "git@github.com:pluginever/framework-settings.git", - "reference": "17aa1bebb38da0f4d8a9cbd791c2a2c4e282e493" + "reference": "f80a91b9a3aef06c56d85a5f3e097da7b9386a80" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/pluginever/framework-settings/zipball/17aa1bebb38da0f4d8a9cbd791c2a2c4e282e493", - "reference": "17aa1bebb38da0f4d8a9cbd791c2a2c4e282e493", + "url": "https://api.github.com/repos/pluginever/framework-settings/zipball/f80a91b9a3aef06c56d85a5f3e097da7b9386a80", + "reference": "f80a91b9a3aef06c56d85a5f3e097da7b9386a80", "shasum": "" }, "require": { @@ -3544,10 +3666,10 @@ ], "description": "A set of related classes to kick start WordPress plugin development.", "support": { - "source": "https://github.com/pluginever/framework-settings/tree/master", + "source": "https://github.com/pluginever/framework-settings/tree/v1.0.4", "issues": "https://github.com/pluginever/framework-settings/issues" }, - "time": "2023-09-27T10:14:00+00:00" + "time": "2023-10-25T08:44:07+00:00" }, { "name": "psr/clock", @@ -6845,16 +6967,16 @@ }, { "name": "wp-cli/php-cli-tools", - "version": "v0.11.20", + "version": "v0.11.21", "source": { "type": "git", "url": "https://github.com/wp-cli/php-cli-tools.git", - "reference": "d788a2c79e02f2f735fbb2b9a53db94d0e1bca4f" + "reference": "b3457a8d60cd0b1c48cab76ad95df136d266f0b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/d788a2c79e02f2f735fbb2b9a53db94d0e1bca4f", - "reference": "d788a2c79e02f2f735fbb2b9a53db94d0e1bca4f", + "url": "https://api.github.com/repos/wp-cli/php-cli-tools/zipball/b3457a8d60cd0b1c48cab76ad95df136d266f0b6", + "reference": "b3457a8d60cd0b1c48cab76ad95df136d266f0b6", "shasum": "" }, "require": { @@ -6902,9 +7024,9 @@ ], "support": { "issues": "https://github.com/wp-cli/php-cli-tools/issues", - "source": "https://github.com/wp-cli/php-cli-tools/tree/v0.11.20" + "source": "https://github.com/wp-cli/php-cli-tools/tree/v0.11.21" }, - "time": "2023-09-01T12:21:35+00:00" + "time": "2023-09-29T15:28:10+00:00" }, { "name": "wp-cli/wp-cli", @@ -6978,30 +7100,38 @@ }, { "name": "wp-coding-standards/wpcs", - "version": "2.3.0", + "version": "3.0.1", "source": { "type": "git", "url": "https://github.com/WordPress/WordPress-Coding-Standards.git", - "reference": "7da1894633f168fe244afc6de00d141f27517b62" + "reference": "b4caf9689f1a0e4a4c632679a44e638c1c67aff1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/7da1894633f168fe244afc6de00d141f27517b62", - "reference": "7da1894633f168fe244afc6de00d141f27517b62", + "url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/b4caf9689f1a0e4a4c632679a44e638c1c67aff1", + "reference": "b4caf9689f1a0e4a4c632679a44e638c1c67aff1", "shasum": "" }, "require": { + "ext-filter": "*", + "ext-libxml": "*", + "ext-tokenizer": "*", + "ext-xmlreader": "*", "php": ">=5.4", - "squizlabs/php_codesniffer": "^3.3.1" + "phpcsstandards/phpcsextra": "^1.1.0", + "phpcsstandards/phpcsutils": "^1.0.8", + "squizlabs/php_codesniffer": "^3.7.2" }, "require-dev": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.5 || ^0.6", + "php-parallel-lint/php-console-highlighter": "^1.0.0", + "php-parallel-lint/php-parallel-lint": "^1.3.2", "phpcompatibility/php-compatibility": "^9.0", - "phpcsstandards/phpcsdevtools": "^1.0", + "phpcsstandards/phpcsdevtools": "^1.2.0", "phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0" }, "suggest": { - "dealerdirect/phpcodesniffer-composer-installer": "^0.6 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically." + "ext-iconv": "For improved results", + "ext-mbstring": "For improved results" }, "type": "phpcodesniffer-standard", "notification-url": "https://packagist.org/downloads/", @@ -7018,6 +7148,7 @@ "keywords": [ "phpcs", "standards", + "static analysis", "wordpress" ], "support": { @@ -7025,7 +7156,13 @@ "source": "https://github.com/WordPress/WordPress-Coding-Standards", "wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki" }, - "time": "2020-05-13T23:57:56+00:00" + "funding": [ + { + "url": "https://opencollective.com/thewpcc/contribute/wp-php-63406", + "type": "custom" + } + ], + "time": "2023-09-14T07:06:09+00:00" }, { "name": "zordius/lightncandy", @@ -7087,10 +7224,9 @@ "aliases": [], "minimum-stability": "dev", "stability-flags": { - "byteever/byteever-sniffs": 20, + "pluginever/framework-model": 20, "pluginever/framework-plugin": 20, - "pluginever/framework-settings": 20, - "pluginever/framework-model": 20 + "pluginever/framework-settings": 20 }, "prefer-stable": true, "prefer-lowest": false, diff --git a/examples/api-test.php b/examples/api-test.txt similarity index 99% rename from examples/api-test.php rename to examples/api-test.txt index 2dc12629..680db184 100644 --- a/examples/api-test.php +++ b/examples/api-test.txt @@ -4,7 +4,6 @@ if ( ! current_user_can( 'manage_options' ) ) { die(); } - // API variables, please override. $base_url = 'http://domain.com'; $email = 'example@domain.com'; diff --git a/languages/wc-serial-numbers.pot b/languages/wc-serial-numbers.pot index e7cd6c41..c8ce3029 100644 --- a/languages/wc-serial-numbers.pot +++ b/languages/wc-serial-numbers.pot @@ -2,9 +2,9 @@ # This file is distributed under the GPLv2+. msgid "" msgstr "" -"Project-Id-Version: Serial Numbers for WooCommerce 1.6.2\n" +"Project-Id-Version: Serial Numbers for WooCommerce 1.6.3\n" "Report-Msgid-Bugs-To: https://pluginever.com/plugins/wc-serial-numbers/\n" -"POT-Creation-Date: 2023-09-27 14:32:49+00:00\n" +"POT-Creation-Date: 2023-10-25 08:52:01+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -53,7 +53,7 @@ msgstr "" msgid "More Plugins" msgstr "" -#: lib/Lib/Plugin.php:692 src/Admin/Menus.php:179 src/Admin/Menus.php:180 +#: lib/Lib/Plugin.php:692 src/Admin/Menus.php:169 src/Admin/Menus.php:170 msgid "Settings" msgstr "" @@ -61,125 +61,121 @@ msgstr "" msgid "Settings saved." msgstr "" -#: lib/Lib/Settings.php:260 lib/Lib/Settings.php:351 lib/Lib/Settings.php:360 -#: lib/Lib/Settings.php:369 +#: lib/Lib/Settings.php:310 lib/Lib/Settings.php:398 lib/Lib/Settings.php:406 +#: lib/Lib/Settings.php:414 msgid "Recommended" msgstr "" -#: lib/Lib/Settings.php:261 lib/Lib/Settings.php:352 lib/Lib/Settings.php:361 -#: lib/Lib/Settings.php:370 +#: lib/Lib/Settings.php:311 lib/Lib/Settings.php:399 lib/Lib/Settings.php:407 +#: lib/Lib/Settings.php:415 msgid "Install Now" msgstr "" -#: lib/Lib/Settings.php:322 +#: lib/Lib/Settings.php:370 msgid "Need Help?" msgstr "" -#: lib/Lib/Settings.php:384 +#: lib/Lib/Settings.php:429 msgid "Join our Community" msgstr "" -#: lib/Lib/Settings.php:388 +#: lib/Lib/Settings.php:433 msgid "Request a Feature" msgstr "" -#: lib/Lib/Settings.php:392 +#: lib/Lib/Settings.php:437 msgid "Report a Bug" msgstr "" -#: lib/classes/wp-background-process.php:653 -msgid "Every Minute" +#: src/API.php:54 +msgid "Invalid request method." msgstr "" -#: lib/classes/wp-background-process.php:655 -msgid "Every %d Minutes" -msgstr "" - -#: src/API.php:60 +#: src/API.php:81 msgid "Invalid action." msgstr "" -#: src/API.php:71 +#: src/API.php:92 msgid "Invalid product ID." msgstr "" -#: src/API.php:81 src/Models/Key.php:494 +#: src/API.php:102 src/Models/Key.php:494 msgid "Serial key is required." msgstr "" -#: src/API.php:97 +#: src/API.php:118 msgid "Serial key is invalid." msgstr "" -#: src/API.php:107 +#: src/API.php:128 msgid "Serial key is not authorized to use." msgstr "" -#: src/API.php:118 +#: src/API.php:139 msgid "Please complete your order to activate the serial key." msgstr "" -#: src/API.php:128 +#: src/API.php:149 msgid "Serial key is not valid for this product." msgstr "" -#: src/API.php:138 +#: src/API.php:159 msgid "Invalid email address." msgstr "" -#: src/API.php:148 +#: src/API.php:169 msgid "Serial key is expired." msgstr "" -#: src/API.php:155 +#: src/API.php:176 msgid "Serial key is cancelled." msgstr "" -#: src/API.php:162 +#: src/API.php:183 msgid "Invalid serial key." msgstr "" -#: src/API.php:181 +#: src/API.php:202 msgid "Serial key is valid." msgstr "" -#: src/API.php:220 src/API.php:321 +#: src/API.php:241 src/API.php:342 msgid "Instance is missing, You must provide an instance to deactivate license" msgstr "" -#: src/API.php:236 +#: src/API.php:257 msgid "Instance is already activated." msgstr "" -#: src/API.php:246 +#: src/API.php:267 msgid "Activation limit reached" msgstr "" -#: src/API.php:273 +#: src/API.php:294 msgid "Activation failed." msgstr "" -#: src/API.php:282 +#: src/API.php:303 msgid "Serial key is activated." msgstr "" -#: src/API.php:337 +#: src/API.php:358 msgid "Instance is not activated." msgstr "" -#: src/API.php:347 +#: src/API.php:368 msgid "Deactivation failed." msgstr "" -#: src/API.php:356 +#: src/API.php:377 msgid "Serial key is deactivated." msgstr "" -#: src/Admin/Actions.php:223 +#: src/Admin/Actions.php:222 msgid "Key added successfully." msgstr "" -#: src/Admin/Actions.php:225 +#: src/Admin/Actions.php:224 msgid "Key updated successfully." msgstr "" @@ -207,84 +203,84 @@ msgstr "" msgid "Copied" msgstr "" -#: src/Admin/Admin.php:105 +#: src/Admin/Admin.php:108 #. translators: 1: Plugin name 2: WordPress msgid "" "Thank you for using %1$s! Share your appreciation with a five-star review " "%2$s." msgstr "" -#: src/Admin/Admin.php:107 +#: src/Admin/Admin.php:110 msgid "Thanks :)" msgstr "" -#: src/Admin/Admin.php:125 +#: src/Admin/Admin.php:128 #. translators: 1: Plugin version msgid "Version %s" msgstr "" -#: src/Admin/Admin.php:138 src/Admin/Menus.php:56 src/Admin/Menus.php:97 -#: src/Admin/Menus.php:98 src/Admin/Menus.php:440 src/Admin/Metaboxes.php:33 -#: src/Admin/Metaboxes.php:229 src/Functions/Template.php:226 +#: src/Admin/Admin.php:141 src/Admin/Menus.php:52 src/Admin/Menus.php:87 +#: src/Admin/Menus.php:88 src/Admin/Menus.php:429 src/Admin/Metaboxes.php:36 +#: src/Admin/Metaboxes.php:248 src/Functions/Template.php:226 msgid "Serial Numbers" msgstr "" #: src/Admin/ListTables/ActivationsTable.php:39 -#: src/Admin/ListTables/KeysTable.php:320 +#: src/Admin/ListTables/KeysTable.php:355 msgid "Activation" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:40 src/Admin/Menus.php:128 -#: src/Admin/Menus.php:129 src/Admin/views/html-list-activations.php:18 +#: src/Admin/ListTables/ActivationsTable.php:40 src/Admin/Menus.php:118 +#: src/Admin/Menus.php:119 src/Admin/views/html-list-activations.php:18 msgid "Activations" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:101 +#: src/Admin/ListTables/ActivationsTable.php:100 msgid "No activations found. Once a serial key is activated, it will appear here." msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:125 -#: src/Admin/ListTables/KeysTable.php:244 -#: src/Admin/ListTables/StockTable.php:92 +#: src/Admin/ListTables/ActivationsTable.php:113 +#: src/Admin/ListTables/KeysTable.php:279 +#: src/Admin/ListTables/StockTable.php:82 msgid "Filter" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:177 -#: src/Admin/ListTables/ActivationsTable.php:252 -#: src/Admin/ListTables/KeysTable.php:300 -#: src/Admin/ListTables/KeysTable.php:391 src/Admin/views/html-edit-key.php:130 +#: src/Admin/ListTables/ActivationsTable.php:165 +#: src/Admin/ListTables/ActivationsTable.php:240 +#: src/Admin/ListTables/KeysTable.php:335 +#: src/Admin/ListTables/KeysTable.php:427 src/Admin/views/html-edit-key.php:130 msgid "Delete" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:189 -#: src/Admin/views/html-api-actions.php:141 src/Frontend/Shortcodes.php:141 +#: src/Admin/ListTables/ActivationsTable.php:177 +#: src/Admin/views/html-api-actions.php:141 src/Frontend/Shortcodes.php:142 msgid "Instance" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:190 -#: src/Admin/ListTables/KeysTable.php:314 -#: src/Admin/ListTables/StockTable.php:105 src/Admin/views/html-add-key.php:33 +#: src/Admin/ListTables/ActivationsTable.php:178 +#: src/Admin/ListTables/KeysTable.php:349 +#: src/Admin/ListTables/StockTable.php:95 src/Admin/views/html-add-key.php:33 #: src/Admin/views/html-api-actions.php:118 #: src/Admin/views/html-api-validation.php:121 -#: src/Admin/views/html-edit-key.php:37 src/Deprecated/Functions.php:359 -#: src/Frontend/Shortcodes.php:40 src/Frontend/Shortcodes.php:136 +#: src/Admin/views/html-edit-key.php:37 src/Deprecated/Functions.php:358 +#: src/Frontend/Shortcodes.php:40 src/Frontend/Shortcodes.php:137 msgid "Product" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:191 -#: src/Admin/ListTables/KeysTable.php:313 src/Admin/Orders.php:192 +#: src/Admin/ListTables/ActivationsTable.php:179 +#: src/Admin/ListTables/KeysTable.php:348 src/Admin/Orders.php:192 #: src/Admin/views/html-api-actions.php:131 #: src/Admin/views/html-api-validation.php:134 src/Functions/Template.php:42 -#: src/functions.php:998 +#: src/functions.php:1009 msgid "Key" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:192 -#: src/Admin/views/html-api-actions.php:152 src/Frontend/Shortcodes.php:143 +#: src/Admin/ListTables/ActivationsTable.php:180 +#: src/Admin/views/html-api-actions.php:152 src/Frontend/Shortcodes.php:144 msgid "Platform" msgstr "" -#: src/Admin/ListTables/ActivationsTable.php:193 +#: src/Admin/ListTables/ActivationsTable.php:181 msgid "Activation Time" msgstr "" @@ -296,135 +292,137 @@ msgstr "" msgid "keys" msgstr "" -#: src/Admin/ListTables/KeysTable.php:170 +#: src/Admin/ListTables/KeysTable.php:169 msgid "No keys found." msgstr "" -#: src/Admin/ListTables/KeysTable.php:170 +#: src/Admin/ListTables/KeysTable.php:169 msgid "Add new key" msgstr "" -#: src/Admin/ListTables/KeysTable.php:174 +#: src/Admin/ListTables/KeysTable.php:173 msgid "Keys can have one of the following statuses:" msgstr "" -#: src/Admin/ListTables/KeysTable.php:178 -#: src/Admin/ListTables/KeysTable.php:223 src/functions.php:46 +#: src/Admin/ListTables/KeysTable.php:177 +#: src/Admin/ListTables/KeysTable.php:233 src/functions.php:46 msgid "Available" msgstr "" -#: src/Admin/ListTables/KeysTable.php:180 +#: src/Admin/ListTables/KeysTable.php:179 msgid "This means the key is available for purchase." msgstr "" -#: src/Admin/ListTables/KeysTable.php:183 -#: src/Admin/ListTables/KeysTable.php:224 src/functions.php:47 +#: src/Admin/ListTables/KeysTable.php:182 +#: src/Admin/ListTables/KeysTable.php:240 src/functions.php:47 msgid "Pending" msgstr "" -#: src/Admin/ListTables/KeysTable.php:185 +#: src/Admin/ListTables/KeysTable.php:184 msgid "This means the key has been sold, but the order has not been completed yet." msgstr "" -#: src/Admin/ListTables/KeysTable.php:188 -#: src/Admin/ListTables/KeysTable.php:225 -#: src/Admin/ListTables/StockTable.php:107 src/functions.php:48 +#: src/Admin/ListTables/KeysTable.php:187 +#: src/Admin/ListTables/KeysTable.php:247 +#: src/Admin/ListTables/StockTable.php:97 src/functions.php:48 msgid "Sold" msgstr "" -#: src/Admin/ListTables/KeysTable.php:190 +#: src/Admin/ListTables/KeysTable.php:189 msgid "This means the key has been sold, and the order has been completed." msgstr "" -#: src/Admin/ListTables/KeysTable.php:193 -#: src/Admin/ListTables/KeysTable.php:226 src/Functions/Template.php:72 +#: src/Admin/ListTables/KeysTable.php:192 +#: src/Admin/ListTables/KeysTable.php:254 src/Functions/Template.php:72 #: src/functions.php:49 msgid "Expired" msgstr "" -#: src/Admin/ListTables/KeysTable.php:195 +#: src/Admin/ListTables/KeysTable.php:194 msgid "This means the key has expired and is no longer valid." msgstr "" -#: src/Admin/ListTables/KeysTable.php:198 -#: src/Admin/ListTables/KeysTable.php:227 src/functions.php:50 +#: src/Admin/ListTables/KeysTable.php:197 +#: src/Admin/ListTables/KeysTable.php:261 src/functions.php:50 msgid "Cancelled" msgstr "" -#: src/Admin/ListTables/KeysTable.php:200 +#: src/Admin/ListTables/KeysTable.php:199 msgid "" "This means the key has been cancelled and is no longer available for " "purchase or use." msgstr "" -#: src/Admin/ListTables/KeysTable.php:222 +#: src/Admin/ListTables/KeysTable.php:224 msgid "All keys." msgstr "" -#: src/Admin/ListTables/KeysTable.php:222 +#: src/Admin/ListTables/KeysTable.php:226 msgid "All" msgstr "" -#: src/Admin/ListTables/KeysTable.php:223 +#: src/Admin/ListTables/KeysTable.php:231 msgid "Available for sell." msgstr "" -#: src/Admin/ListTables/KeysTable.php:224 +#: src/Admin/ListTables/KeysTable.php:238 msgid "Pending payment." msgstr "" -#: src/Admin/ListTables/KeysTable.php:225 +#: src/Admin/ListTables/KeysTable.php:245 msgid "Sold keys." msgstr "" -#: src/Admin/ListTables/KeysTable.php:226 +#: src/Admin/ListTables/KeysTable.php:252 msgid "Expired keys." msgstr "" -#: src/Admin/ListTables/KeysTable.php:227 +#: src/Admin/ListTables/KeysTable.php:259 msgid "Cancelled keys." msgstr "" -#: src/Admin/ListTables/KeysTable.php:301 +#: src/Admin/ListTables/KeysTable.php:336 msgid "Reset Activations" msgstr "" -#: src/Admin/ListTables/KeysTable.php:315 src/Admin/views/html-add-key.php:120 +#: src/Admin/ListTables/KeysTable.php:350 src/Admin/views/html-add-key.php:120 msgid "Order" msgstr "" -#: src/Admin/ListTables/KeysTable.php:316 +#: src/Admin/ListTables/KeysTable.php:351 msgid "Validity" msgstr "" -#: src/Admin/ListTables/KeysTable.php:323 +#: src/Admin/ListTables/KeysTable.php:358 msgid "Order Date" msgstr "" -#: src/Admin/ListTables/KeysTable.php:324 src/Admin/Menus.php:328 +#: src/Admin/ListTables/KeysTable.php:359 src/Admin/Menus.php:316 #: src/Admin/Orders.php:204 src/Admin/views/html-add-key.php:91 #: src/Admin/views/html-edit-key.php:92 src/Functions/Template.php:78 -#: src/functions.php:1023 +#: src/functions.php:1034 msgid "Status" msgstr "" -#: src/Admin/ListTables/KeysTable.php:389 +#: src/Admin/ListTables/KeysTable.php:425 +#. translators: %d: key id. msgid "ID: %d" msgstr "" -#: src/Admin/ListTables/KeysTable.php:390 -#: src/Admin/ListTables/StockTable.php:153 +#: src/Admin/ListTables/KeysTable.php:426 +#: src/Admin/ListTables/StockTable.php:143 msgid "Edit" msgstr "" -#: src/Admin/ListTables/KeysTable.php:481 +#: src/Admin/ListTables/KeysTable.php:521 +#. translators: %1$s: validity, %2$s: validity. msgid "%s Day
After purchase" msgid_plural "%s Days
After purchase" msgstr[0] "" msgstr[1] "" -#: src/Admin/ListTables/KeysTable.php:481 src/Admin/Orders.php:197 -#: src/Functions/Template.php:63 src/functions.php:1019 +#: src/Admin/ListTables/KeysTable.php:531 src/Admin/Orders.php:197 +#: src/Functions/Template.php:63 src/functions.php:1030 msgid "Lifetime" msgstr "" @@ -453,161 +451,156 @@ msgstr "" msgid "No products selling serial keys from \"stock\" found." msgstr "" -#: src/Admin/ListTables/StockTable.php:106 +#: src/Admin/ListTables/StockTable.php:96 msgid "Source" msgstr "" -#: src/Admin/ListTables/StockTable.php:108 src/Admin/Menus.php:287 +#: src/Admin/ListTables/StockTable.php:98 src/Admin/Menus.php:277 msgid "Stock" msgstr "" -#: src/Admin/ListTables/StockTable.php:182 +#: src/Admin/ListTables/StockTable.php:172 msgid "Manual" msgstr "" -#: src/Admin/ListTables/StockTable.php:184 +#: src/Admin/ListTables/StockTable.php:174 msgid "Generator Rule" msgstr "" -#: src/Admin/ListTables/StockTable.php:186 +#: src/Admin/ListTables/StockTable.php:176 msgid "Auto Generated" msgstr "" -#: src/Admin/ListTables/StockTable.php:188 +#: src/Admin/ListTables/StockTable.php:178 msgid "Unknown" msgstr "" -#: src/Admin/Menus.php:108 src/Admin/Menus.php:109 +#: src/Admin/Menus.php:98 src/Admin/Menus.php:99 #: src/Admin/views/html-list-keys.php:18 msgid "Serial Keys" msgstr "" -#: src/Admin/Menus.php:145 src/Admin/Menus.php:146 +#: src/Admin/Menus.php:135 src/Admin/Menus.php:136 msgid "Tools" msgstr "" -#: src/Admin/Menus.php:162 src/Admin/Menus.php:163 +#: src/Admin/Menus.php:152 src/Admin/Menus.php:153 msgid "Reports" msgstr "" -#: src/Admin/Menus.php:199 src/Admin/Metaboxes.php:125 -#: src/Admin/Metaboxes.php:144 +#: src/Admin/Menus.php:189 src/Admin/Metaboxes.php:136 +#: src/Admin/Metaboxes.php:157 msgid "Upgrade to Pro" msgstr "" -#: src/Admin/Menus.php:253 src/Admin/Menus.php:389 +#: src/Admin/Menus.php:243 src/Admin/Menus.php:377 msgid "Generators" msgstr "" -#: src/Admin/Menus.php:254 +#: src/Admin/Menus.php:244 msgid "API Toolkit" msgstr "" -#: src/Admin/Menus.php:255 src/Admin/views/html-list-keys.php:25 +#: src/Admin/Menus.php:245 src/Admin/views/html-list-keys.php:25 msgid "Import" msgstr "" -#: src/Admin/Menus.php:256 src/Admin/views/html-list-keys.php:29 +#: src/Admin/Menus.php:246 src/Admin/views/html-list-keys.php:29 msgid "Export" msgstr "" -#: src/Admin/Menus.php:343 src/Admin/Menus.php:350 src/Admin/Menus.php:368 -#: src/Admin/Menus.php:386 +#: src/Admin/Menus.php:331 src/Admin/Menus.php:338 src/Admin/Menus.php:356 +#: src/Admin/Menus.php:374 msgid "Available in Pro Version" msgstr "" -#: src/Admin/Menus.php:344 src/Admin/Menus.php:351 src/Admin/Menus.php:369 -#: src/Admin/Menus.php:387 +#: src/Admin/Menus.php:332 src/Admin/Menus.php:339 src/Admin/Menus.php:357 +#: src/Admin/Menus.php:375 msgid "Upgrade to Pro Now" msgstr "" -#: src/Admin/Menus.php:346 src/Admin/Menus.php:353 +#: src/Admin/Menus.php:334 src/Admin/Menus.php:341 msgid "Import Serial Numbers" msgstr "" -#: src/Admin/Menus.php:371 +#: src/Admin/Menus.php:359 msgid "Export Serial Numbers" msgstr "" -#: src/Admin/Menus.php:416 +#: src/Admin/Menus.php:404 msgid "Table exists" msgstr "" -#: src/Admin/Menus.php:418 +#: src/Admin/Menus.php:406 msgid "Table does not exist" msgstr "" -#: src/Admin/Menus.php:424 +#: src/Admin/Menus.php:412 msgid "Hourly cron" msgstr "" -#: src/Admin/Menus.php:425 +#: src/Admin/Menus.php:413 msgid "Daily cron" msgstr "" -#: src/Admin/Menus.php:430 +#: src/Admin/Menus.php:419 +#. translators: %s: Next scheduled time. msgid "Next run: %s" msgstr "" -#: src/Admin/Menus.php:432 +#: src/Admin/Menus.php:421 msgid "Not scheduled" msgstr "" -#: src/Admin/Metaboxes.php:54 +#: src/Admin/Metaboxes.php:57 msgid "Sell keys" msgstr "" -#: src/Admin/Metaboxes.php:55 +#: src/Admin/Metaboxes.php:58 msgid "Enable this if you are selling keys or licensing this product." msgstr "" -#: src/Admin/Metaboxes.php:68 +#: src/Admin/Metaboxes.php:71 msgid "Delivery quantity" msgstr "" -#: src/Admin/Metaboxes.php:69 +#: src/Admin/Metaboxes.php:72 msgid "Number of key(s) will be delivered per item. Available in PRO." msgstr "" -#: src/Admin/Metaboxes.php:89 +#: src/Admin/Metaboxes.php:92 src/Admin/Metaboxes.php:124 msgid "Key source" msgstr "" -#: src/Admin/Metaboxes.php:107 +#: src/Admin/Metaboxes.php:110 msgid "Software version" msgstr "" -#: src/Admin/Metaboxes.php:108 +#: src/Admin/Metaboxes.php:111 msgid "Version number for the software. Ignore if it's not a software." msgstr "" -#: src/Admin/Metaboxes.php:109 +#: src/Admin/Metaboxes.php:112 msgid "e.g. 1.0" msgstr "" -#: src/Admin/Metaboxes.php:120 -msgid "Stock status" -msgstr "" - -#: src/Admin/Metaboxes.php:122 +#: src/Admin/Metaboxes.php:126 msgid "key available." msgid_plural "keys available." msgstr[0] "" msgstr[1] "" -#: src/Admin/Metaboxes.php:125 -msgid "" -"Want the keys to be generated automatically, auto assign with orders, and " -"many more?" +#: src/Admin/Metaboxes.php:134 +msgid "Want to sell keys for variable products?" msgstr "" -#: src/Admin/Metaboxes.php:144 +#: src/Admin/Metaboxes.php:155 msgid "" "The free version of Serial Numbers for WooCommerce does not support product " "variation." msgstr "" -#: src/Admin/Metaboxes.php:214 +#: src/Admin/Metaboxes.php:230 msgid "Order missing serial numbers for this item." msgstr "" @@ -1145,8 +1138,8 @@ msgstr "" #: src/Admin/views/html-api-actions.php:162 #: src/Admin/views/html-api-validation.php:144 -#: src/Admin/views/html-edit-key.php:154 src/Deprecated/Functions.php:361 -#: src/Frontend/Shortcodes.php:43 src/Frontend/Shortcodes.php:139 +#: src/Admin/views/html-edit-key.php:154 src/Deprecated/Functions.php:360 +#: src/Frontend/Shortcodes.php:43 src/Frontend/Shortcodes.php:140 msgid "Email" msgstr "" @@ -1162,15 +1155,15 @@ msgid "" "ignored." msgstr "" -#: src/Admin/views/html-api-actions.php:172 src/Frontend/Shortcodes.php:145 +#: src/Admin/views/html-api-actions.php:172 src/Frontend/Shortcodes.php:146 msgid "Action" msgstr "" -#: src/Admin/views/html-api-actions.php:175 src/Frontend/Shortcodes.php:152 +#: src/Admin/views/html-api-actions.php:175 src/Frontend/Shortcodes.php:153 msgid "Activate" msgstr "" -#: src/Admin/views/html-api-actions.php:176 src/Frontend/Shortcodes.php:153 +#: src/Admin/views/html-api-actions.php:176 src/Frontend/Shortcodes.php:154 msgid "Deactivate" msgstr "" @@ -1183,7 +1176,7 @@ msgstr "" msgid "API response" msgstr "" -#: src/Admin/views/html-api-actions.php:195 src/Frontend/Shortcodes.php:146 +#: src/Admin/views/html-api-actions.php:195 src/Frontend/Shortcodes.php:147 #: vendor/lucatume/wp-browser/src/data/plugins/wordpress-importer/wordpress-importer.php:284 msgid "Submit" msgstr "" @@ -1359,20 +1352,20 @@ msgstr "" msgid "Serial Numbers stock running low" msgstr "" -#: src/Deprecated/Functions.php:155 +#: src/Deprecated/Functions.php:154 msgid "Serial number not found." msgstr "" -#: src/Deprecated/Functions.php:360 +#: src/Deprecated/Functions.php:359 msgid "Serial Number" msgstr "" -#: src/Deprecated/Functions.php:362 src/Functions/Template.php:52 -#: src/functions.php:1008 +#: src/Deprecated/Functions.php:361 src/Functions/Template.php:52 +#: src/functions.php:1019 msgid "Activation Limit" msgstr "" -#: src/Deprecated/Functions.php:363 +#: src/Deprecated/Functions.php:362 msgid "Expires" msgstr "" @@ -1384,16 +1377,16 @@ msgstr "" msgid "Serial Key Validation" msgstr "" -#: src/Frontend/Shortcodes.php:41 src/Frontend/Shortcodes.php:137 +#: src/Frontend/Shortcodes.php:41 src/Frontend/Shortcodes.php:138 msgid "Serial Key" msgstr "" -#: src/Frontend/Shortcodes.php:42 src/Frontend/Shortcodes.php:138 +#: src/Frontend/Shortcodes.php:42 src/Frontend/Shortcodes.php:139 msgid "Enter your serial key" msgstr "" #: src/Frontend/Shortcodes.php:44 src/Frontend/Shortcodes.php:105 -#: src/Frontend/Shortcodes.php:140 src/Frontend/Shortcodes.php:216 +#: src/Frontend/Shortcodes.php:141 src/Frontend/Shortcodes.php:217 msgid "Enter your email" msgstr "" @@ -1401,40 +1394,40 @@ msgstr "" msgid "No products found." msgstr "" -#: src/Frontend/Shortcodes.php:90 src/Frontend/Shortcodes.php:200 +#: src/Frontend/Shortcodes.php:90 src/Frontend/Shortcodes.php:201 msgid "Select a product" msgstr "" -#: src/Frontend/Shortcodes.php:135 +#: src/Frontend/Shortcodes.php:136 msgid "Activate/Deactivate Serial Key" msgstr "" -#: src/Frontend/Shortcodes.php:142 +#: src/Frontend/Shortcodes.php:143 msgid "Enter your instance" msgstr "" -#: src/Frontend/Shortcodes.php:144 +#: src/Frontend/Shortcodes.php:145 msgid "Enter platform" msgstr "" -#: src/Frontend/Shortcodes.php:186 +#: src/Frontend/Shortcodes.php:187 msgid "Could not find any products with serial numbers enabled." msgstr "" -#: src/Functions/Template.php:47 src/functions.php:1003 +#: src/Functions/Template.php:47 src/functions.php:1014 msgid "Activation Email" msgstr "" #: src/Functions/Template.php:53 src/Functions/Template.php:58 -#: src/functions.php:1009 src/functions.php:1014 +#: src/functions.php:1020 src/functions.php:1025 msgid "None" msgstr "" -#: src/Functions/Template.php:57 src/functions.php:1013 +#: src/Functions/Template.php:57 src/functions.php:1024 msgid "Activation Count" msgstr "" -#: src/Functions/Template.php:62 src/functions.php:1018 +#: src/Functions/Template.php:62 src/functions.php:1029 msgid "Expire Date" msgstr "" @@ -1480,6 +1473,7 @@ msgid "Order id is invalid." msgstr "" #: src/Orders.php:67 +#. translators: %1$s: product title, %2$s: stock quantity. msgid "" "Sorry, there aren’t enough Serial Keys for %1$s. Please remove this item or " "lower the quantity. For now, we have %2$s Serial Keys for this product." @@ -1489,12 +1483,12 @@ msgstr "" msgid "Order automatically completed by the Serial Numbers for WooCommerce." msgstr "" -#: src/Plugin.php:69 +#: src/Plugin.php:63 #. translators: 1: plugin name 2: WooCommerce msgid "%1$s requires %2$s to be installed and active." msgstr "" -#: src/Plugin.php:71 +#: src/Plugin.php:65 msgid "WooCommerce" msgstr "" @@ -1502,24 +1496,25 @@ msgstr "" msgid "Manually added" msgstr "" -#: src/functions.php:537 +#: src/functions.php:533 #. translators: 1: product title 2: source and 3: Quantity msgid "" "There is not enough serial numbers for the product %1$s from selected " "source %2$s, needed total %3$d." msgstr "" -#: templates/email-stock-notification.php:12 +#: templates/email-stock-notification.php:14 msgid "Hi There," msgstr "" -#: templates/email-stock-notification.php:13 +#: templates/email-stock-notification.php:15 msgid "" "There are few products stock running low, please add serial numbers for " "these products" msgstr "" -#: templates/email-stock-notification.php:30 +#: templates/email-stock-notification.php:37 +#. translators: %s: plugin url. msgid "" "The email is sent by Serial Numbers for " "WooCommerce" diff --git a/lib/classes/wp-async-request.php b/lib/classes/wp-async-request.php deleted file mode 100644 index 9759ab09..00000000 --- a/lib/classes/wp-async-request.php +++ /dev/null @@ -1,202 +0,0 @@ -identifier = $this->prefix . '_' . $this->action; - - add_action( 'wp_ajax_' . $this->identifier, array( $this, 'maybe_handle' ) ); - add_action( 'wp_ajax_nopriv_' . $this->identifier, array( $this, 'maybe_handle' ) ); - } - - /** - * Set data used during the request. - * - * @param array $data Data. - * - * @return $this - */ - public function data( $data ) { - $this->data = $data; - - return $this; - } - - /** - * Dispatch the async request. - * - * @return array|WP_Error|false HTTP Response array, WP_Error on failure, or false if not attempted. - */ - public function dispatch() { - $url = add_query_arg( $this->get_query_args(), $this->get_query_url() ); - $args = $this->get_post_args(); - - return wp_remote_post( esc_url_raw( $url ), $args ); - } - - /** - * Get query args. - * - * @return array - */ - protected function get_query_args() { - if ( property_exists( $this, 'query_args' ) ) { - return $this->query_args; - } - - $args = array( - 'action' => $this->identifier, - 'nonce' => wp_create_nonce( $this->identifier ), - ); - - /** - * Filters the post arguments used during an async request. - * - * @param array $url - */ - return apply_filters( $this->identifier . '_query_args', $args ); - } - - /** - * Get query URL. - * - * @return string - */ - protected function get_query_url() { - if ( property_exists( $this, 'query_url' ) ) { - return $this->query_url; - } - - $url = admin_url( 'admin-ajax.php' ); - - /** - * Filters the post arguments used during an async request. - * - * @param string $url - */ - return apply_filters( $this->identifier . '_query_url', $url ); - } - - /** - * Get post args. - * - * @return array - */ - protected function get_post_args() { - if ( property_exists( $this, 'post_args' ) ) { - return $this->post_args; - } - - $args = array( - 'timeout' => 0.01, - 'blocking' => false, - 'body' => $this->data, - 'cookies' => $_COOKIE, // Passing cookies ensures request is performed as initiating user. - 'sslverify' => apply_filters( 'https_local_ssl_verify', false ), // Local requests, fine to pass false. - ); - - /** - * Filters the post arguments used during an async request. - * - * @param array $args - */ - return apply_filters( $this->identifier . '_post_args', $args ); - } - - /** - * Maybe handle a dispatched request. - * - * Check for correct nonce and pass to handler. - * - * @return void|mixed - */ - public function maybe_handle() { - // Don't lock up other requests while processing. - session_write_close(); - - check_ajax_referer( $this->identifier, 'nonce' ); - - $this->handle(); - - return $this->maybe_wp_die(); - } - - /** - * Should the process exit with wp_die? - * - * @param mixed $return What to return if filter says don't die, default is null. - * - * @return void|mixed - */ - protected function maybe_wp_die( $return = null ) { - /** - * Should wp_die be used? - * - * @return bool - */ - if ( apply_filters( $this->identifier . '_wp_die', true ) ) { - wp_die(); - } - - return $return; - } - - /** - * Handle a dispatched request. - * - * Override this method to perform any actions required - * during the async request. - */ - abstract protected function handle(); -} diff --git a/lib/classes/wp-background-process.php b/lib/classes/wp-background-process.php deleted file mode 100644 index fbc81fff..00000000 --- a/lib/classes/wp-background-process.php +++ /dev/null @@ -1,733 +0,0 @@ -cron_hook_identifier = $this->identifier . '_cron'; - $this->cron_interval_identifier = $this->identifier . '_cron_interval'; - - add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) ); - add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) ); - } - - /** - * Schedule the cron healthcheck and dispatch an async request to start processing the queue. - * - * @access public - * @return array|WP_Error|false HTTP Response array, WP_Error on failure, or false if not attempted. - */ - public function dispatch() { - if ( $this->is_processing() ) { - // Process already running. - return false; - } - - // Schedule the cron healthcheck. - $this->schedule_event(); - - // Perform remote post. - return parent::dispatch(); - } - - /** - * Push to the queue. - * - * Note, save must be called in order to persist queued items to a batch for processing. - * - * @param mixed $data Data. - * - * @return $this - */ - public function push_to_queue( $data ) { - $this->data[] = $data; - - return $this; - } - - /** - * Save the queued items for future processing. - * - * @return $this - */ - public function save() { - $key = $this->generate_key(); - - if ( ! empty( $this->data ) ) { - update_site_option( $key, $this->data ); - } - - // Clean out data so that new data isn't prepended with closed session's data. - $this->data = array(); - - return $this; - } - - /** - * Update a batch's queued items. - * - * @param string $key Key. - * @param array $data Data. - * - * @return $this - */ - public function update( $key, $data ) { - if ( ! empty( $data ) ) { - update_site_option( $key, $data ); - } - - return $this; - } - - /** - * Delete a batch of queued items. - * - * @param string $key Key. - * - * @return $this - */ - public function delete( $key ) { - delete_site_option( $key ); - - return $this; - } - - /** - * Delete entire job queue. - */ - public function delete_all() { - $batches = $this->get_batches(); - - foreach ( $batches as $batch ) { - $this->delete( $batch->key ); - } - - delete_site_option( $this->get_status_key() ); - - $this->cancelled(); - } - - /** - * Cancel job on next batch. - */ - public function cancel() { - update_site_option( $this->get_status_key(), self::STATUS_CANCELLED ); - - // Just in case the job was paused at the time. - $this->dispatch(); - } - - /** - * Has the process been cancelled? - * - * @return bool - */ - public function is_cancelled() { - $status = get_site_option( $this->get_status_key(), 0 ); - - if ( absint( $status ) === self::STATUS_CANCELLED ) { - return true; - } - - return false; - } - - /** - * Called when background process has been cancelled. - */ - protected function cancelled() { - do_action( $this->identifier . '_cancelled' ); - } - - /** - * Pause job on next batch. - */ - public function pause() { - update_site_option( $this->get_status_key(), self::STATUS_PAUSED ); - } - - /** - * Is the job paused? - * - * @return bool - */ - public function is_paused() { - $status = get_site_option( $this->get_status_key(), 0 ); - - if ( absint( $status ) === self::STATUS_PAUSED ) { - return true; - } - - return false; - } - - /** - * Called when background process has been paused. - */ - protected function paused() { - do_action( $this->identifier . '_paused' ); - } - - /** - * Resume job. - */ - public function resume() { - delete_site_option( $this->get_status_key() ); - - $this->schedule_event(); - $this->dispatch(); - $this->resumed(); - } - - /** - * Called when background process has been resumed. - */ - protected function resumed() { - do_action( $this->identifier . '_resumed' ); - } - - /** - * Is queued? - * - * @return bool - */ - public function is_queued() { - return ! $this->is_queue_empty(); - } - - /** - * Is the tool currently active, e.g. starting, working, paused or cleaning up? - * - * @return bool - */ - public function is_active() { - return $this->is_queued() || $this->is_processing() || $this->is_paused() || $this->is_cancelled(); - } - - /** - * Generate key for a batch. - * - * Generates a unique key based on microtime. Queue items are - * given a unique key so that they can be merged upon save. - * - * @param int $length Optional max length to trim key to, defaults to 64 characters. - * @param string $key Optional string to append to identifier before hash, defaults to "batch". - * - * @return string - */ - protected function generate_key( $length = 64, $key = 'batch' ) { - $unique = md5( microtime() . wp_rand() ); - $prepend = $this->identifier . '_' . $key . '_'; - - return substr( $prepend . $unique, 0, $length ); - } - - /** - * Get the status key. - * - * @return string - */ - protected function get_status_key() { - return $this->identifier . '_status'; - } - - /** - * Maybe process a batch of queued items. - * - * Checks whether data exists within the queue and that - * the process is not already running. - */ - public function maybe_handle() { - // Don't lock up other requests while processing. - session_write_close(); - - if ( $this->is_processing() ) { - // Background process already running. - return $this->maybe_wp_die(); - } - - if ( $this->is_cancelled() ) { - $this->clear_scheduled_event(); - $this->delete_all(); - - return $this->maybe_wp_die(); - } - - if ( $this->is_paused() ) { - $this->clear_scheduled_event(); - $this->paused(); - - return $this->maybe_wp_die(); - } - - if ( $this->is_queue_empty() ) { - // No data to process. - return $this->maybe_wp_die(); - } - - check_ajax_referer( $this->identifier, 'nonce' ); - - $this->handle(); - - return $this->maybe_wp_die(); - } - - /** - * Is queue empty? - * - * @return bool - */ - protected function is_queue_empty() { - return empty( $this->get_batch() ); - } - - /** - * Is process running? - * - * Check whether the current process is already running - * in a background process. - * - * @return bool - * - * @deprecated 1.1.0 Superseded. - * @see is_processing() - */ - protected function is_process_running() { - return $this->is_processing(); - } - - /** - * Is the background process currently running? - * - * @return bool - */ - public function is_processing() { - if ( get_site_transient( $this->identifier . '_process_lock' ) ) { - // Process already running. - return true; - } - - return false; - } - - /** - * Lock process. - * - * Lock the process so that multiple instances can't run simultaneously. - * Override if applicable, but the duration should be greater than that - * defined in the time_exceeded() method. - */ - protected function lock_process() { - $this->start_time = time(); // Set start time of current process. - - $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute - $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration ); - - set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration ); - } - - /** - * Unlock process. - * - * Unlock the process so that other instances can spawn. - * - * @return $this - */ - protected function unlock_process() { - delete_site_transient( $this->identifier . '_process_lock' ); - - return $this; - } - - /** - * Get batch. - * - * @return stdClass Return the first batch of queued items. - */ - protected function get_batch() { - return array_reduce( - $this->get_batches( 1 ), - function ( $carry, $batch ) { - return $batch; - }, - array() - ); - } - - /** - * Get batches. - * - * @param int $limit Number of batches to return, defaults to all. - * - * @return array of stdClass - */ - public function get_batches( $limit = 0 ) { - global $wpdb; - - if ( empty( $limit ) || ! is_int( $limit ) ) { - $limit = 0; - } - - $table = $wpdb->options; - $column = 'option_name'; - $key_column = 'option_id'; - $value_column = 'option_value'; - - if ( is_multisite() ) { - $table = $wpdb->sitemeta; - $column = 'meta_key'; - $key_column = 'meta_id'; - $value_column = 'meta_value'; - } - - $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%'; - - $sql = ' - SELECT * - FROM ' . $table . ' - WHERE ' . $column . ' LIKE %s - ORDER BY ' . $key_column . ' ASC - '; - - $args = array( $key ); - - if ( ! empty( $limit ) ) { - $sql .= ' LIMIT %d'; - - $args[] = $limit; - } - - $items = $wpdb->get_results( $wpdb->prepare( $sql, $args ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared - - $batches = array(); - - if ( ! empty( $items ) ) { - $batches = array_map( - function ( $item ) use ( $column, $value_column ) { - $batch = new stdClass(); - $batch->key = $item->{$column}; - $batch->data = maybe_unserialize( $item->{$value_column} ); - - return $batch; - }, - $items - ); - } - - return $batches; - } - - /** - * Handle a dispatched request. - * - * Pass each queue item to the task handler, while remaining - * within server memory and time limit constraints. - */ - protected function handle() { - $this->lock_process(); - - /** - * Number of seconds to sleep between batches. Defaults to 0 seconds, minimum 0. - * - * @param int $seconds - */ - $throttle_seconds = max( - 0, - apply_filters( - $this->identifier . '_seconds_between_batches', - apply_filters( - $this->prefix . '_seconds_between_batches', - 0 - ) - ) - ); - - do { - $batch = $this->get_batch(); - - foreach ( $batch->data as $key => $value ) { - $task = $this->task( $value ); - - if ( false !== $task ) { - $batch->data[ $key ] = $task; - } else { - unset( $batch->data[ $key ] ); - } - - // Keep the batch up to date while processing it. - if ( ! empty( $batch->data ) ) { - $this->update( $batch->key, $batch->data ); - } - - // Let the server breathe a little. - sleep( $throttle_seconds ); - - // Batch limits reached, or pause or cancel request. - if ( $this->time_exceeded() || $this->memory_exceeded() || $this->is_paused() || $this->is_cancelled() ) { - break; - } - } - - // Delete current batch if fully processed. - if ( empty( $batch->data ) ) { - $this->delete( $batch->key ); - } - } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() && ! $this->is_paused() && ! $this->is_cancelled() ); - - $this->unlock_process(); - - // Start next batch or complete process. - if ( ! $this->is_queue_empty() ) { - $this->dispatch(); - } else { - $this->complete(); - } - - return $this->maybe_wp_die(); - } - - /** - * Memory exceeded? - * - * Ensures the batch process never exceeds 90% - * of the maximum WordPress memory. - * - * @return bool - */ - protected function memory_exceeded() { - $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory - $current_memory = memory_get_usage( true ); - $return = false; - - if ( $current_memory >= $memory_limit ) { - $return = true; - } - - return apply_filters( $this->identifier . '_memory_exceeded', $return ); - } - - /** - * Get memory limit in bytes. - * - * @return int - */ - protected function get_memory_limit() { - if ( function_exists( 'ini_get' ) ) { - $memory_limit = ini_get( 'memory_limit' ); - } else { - // Sensible default. - $memory_limit = '128M'; - } - - if ( ! $memory_limit || -1 === intval( $memory_limit ) ) { - // Unlimited, set to 32GB. - $memory_limit = '32000M'; - } - - return wp_convert_hr_to_bytes( $memory_limit ); - } - - /** - * Time limit exceeded? - * - * Ensures the batch never exceeds a sensible time limit. - * A timeout limit of 30s is common on shared hosting. - * - * @return bool - */ - protected function time_exceeded() { - $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds - $return = false; - - if ( time() >= $finish ) { - $return = true; - } - - return apply_filters( $this->identifier . '_time_exceeded', $return ); - } - - /** - * Complete processing. - * - * Override if applicable, but ensure that the below actions are - * performed, or, call parent::complete(). - */ - protected function complete() { - delete_site_option( $this->get_status_key() ); - - // Remove the cron healthcheck job from the cron schedule. - $this->clear_scheduled_event(); - - $this->completed(); - } - - /** - * Called when background process has completed. - */ - protected function completed() { - do_action( $this->identifier . '_completed' ); - } - - /** - * Schedule the cron healthcheck job. - * - * @access public - * - * @param mixed $schedules Schedules. - * - * @return mixed - */ - public function schedule_cron_healthcheck( $schedules ) { - $interval = apply_filters( $this->cron_interval_identifier, 5 ); - - if ( property_exists( $this, 'cron_interval' ) ) { - $interval = apply_filters( $this->cron_interval_identifier, $this->cron_interval ); - } - - if ( 1 === $interval ) { - $display = __( 'Every Minute', 'wc-serial-numbers' ); - } else { - $display = sprintf( __( 'Every %d Minutes', 'wc-serial-numbers' ), $interval ); - } - - // Adds an "Every NNN Minute(s)" schedule to the existing cron schedules. - $schedules[ $this->cron_interval_identifier ] = array( - 'interval' => MINUTE_IN_SECONDS * $interval, - 'display' => $display, - ); - - return $schedules; - } - - /** - * Handle cron healthcheck event. - * - * Restart the background process if not already running - * and data exists in the queue. - */ - public function handle_cron_healthcheck() { - if ( $this->is_processing() ) { - // Background process already running. - exit; - } - - if ( $this->is_queue_empty() ) { - // No data to process. - $this->clear_scheduled_event(); - exit; - } - - $this->dispatch(); - } - - /** - * Schedule the cron healthcheck event. - */ - protected function schedule_event() { - if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) { - wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier ); - } - } - - /** - * Clear scheduled cron healthcheck event. - */ - protected function clear_scheduled_event() { - $timestamp = wp_next_scheduled( $this->cron_hook_identifier ); - - if ( $timestamp ) { - wp_unschedule_event( $timestamp, $this->cron_hook_identifier ); - } - } - - /** - * Cancel the background process. - * - * Stop processing queue items, clear cron job and delete batch. - * - * @deprecated 1.1.0 Superseded. - * @see cancel() - */ - public function cancel_process() { - $this->cancel(); - } - - /** - * Perform task with queued item. - * - * Override this method to perform any actions required on each - * queue item. Return the modified item for further processing - * in the next pass through. Or, return false to remove the - * item from the queue. - * - * @param mixed $item Queue item to iterate over. - * - * @return mixed - */ - abstract protected function task( $item ); -} diff --git a/package-lock.json b/package-lock.json index 55ce18c1..9216c9cf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "wc-serial-numbers", - "version": "1.6.2", + "version": "1.6.3", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wc-serial-numbers", - "version": "1.6.2", + "version": "1.6.3", "license": "GPL-3.0+", "devDependencies": { "@lodder/time-grunt": "^4.0.0", diff --git a/package.json b/package.json index 45051821..2d2a9c4d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "wc-serial-numbers", "title": "Serial Numbers for WooCommerce", - "version": "1.6.2", + "version": "1.6.4", "description": "The best WooCommerce extension to sell license & serial keys, gift cards and other secret numbers!", "homepage": "https://pluginever.com/plugins/wc-serial-numbers/", "license": "GPL-3.0+", diff --git a/readme.txt b/readme.txt index 838839d6..5434bb38 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: license manager, license, license number, serial number, activation number Requires at least: 5.0 Tested up to: 6.3 Requires PHP: 5.6 -Stable tag: 1.6.1 +Stable tag: 1.6.4 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -252,6 +252,13 @@ Yes, you are always welcome to [provide suggestions](https://github.com/pluginev == Changelog == += 1.6.4 (25 Oct 2023) = +* Enhance: Optimize and improve code for better performance & security. + += 1.6.3 (8 Oct 2023) = +* Fix: Dropdown active color is not working. +* Enhance: Allow keys to be sold without checking key source. + = 1.6.2 (27 Sep 2023) = * Enhance: Add compatibility with WooCommerce HPOS. diff --git a/src/API.php b/src/API.php index 6d8f1432..987e8105 100644 --- a/src/API.php +++ b/src/API.php @@ -35,11 +35,32 @@ public function __construct() { * @since 1.0.0 */ public static function process_request() { - $product_id = isset( $_REQUEST['product_id'] ) ? absint( $_REQUEST['product_id'] ) : 0; - $key = isset( $_REQUEST['serial_key'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['serial_key'] ) ) : ''; - $action = isset( $_REQUEST['request'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['request'] ) ) : ''; - $email = isset( $_REQUEST['email'] ) ? sanitize_text_field( strtolower( wp_unslash( $_REQUEST['email'] ) ) ) : ''; + $method = filter_input( INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_SPECIAL_CHARS ); + if ( 'POST' === strtoupper( $method ) ) { + $product_id = filter_input( INPUT_POST, 'product_id', FILTER_SANITIZE_NUMBER_INT ); + $key = filter_input( INPUT_POST, 'serial_key', FILTER_SANITIZE_SPECIAL_CHARS ); + $action = filter_input( INPUT_POST, 'request', FILTER_SANITIZE_SPECIAL_CHARS ); + $email = filter_input( INPUT_POST, 'email', FILTER_SANITIZE_SPECIAL_CHARS ); + } elseif ( 'GET' === strtoupper( $method ) ) { + $product_id = filter_input( INPUT_GET, 'product_id', FILTER_SANITIZE_NUMBER_INT ); + $key = filter_input( INPUT_GET, 'serial_key', FILTER_SANITIZE_SPECIAL_CHARS ); + $action = filter_input( INPUT_GET, 'request', FILTER_SANITIZE_SPECIAL_CHARS ); + $email = filter_input( INPUT_GET, 'email', FILTER_SANITIZE_SPECIAL_CHARS ); + } else { + // its unknown request method. + wp_send_json_error( + array( + 'code' => 'invalid_request_method', + 'message' => __( 'Invalid request method.', 'wc-serial-numbers' ), + ) + ); + } + // Clean up properties. + $product_id = absint( $product_id ); + $key = sanitize_text_field( wp_unslash( $key ) ); + $action = sanitize_key( wp_unslash( $action ) ); + $email = strtolower( sanitize_email( wp_unslash( $email ) ) ); WCSN()->log( 'API request', 'debug', @@ -208,7 +229,7 @@ public static function validate_key( $serial_key ) { * @since 1.0.0 */ public static function activate_key( $serial_key ) { - $user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? md5( sanitize_textarea_field( $_SERVER['HTTP_USER_AGENT'] ) . time() ) : md5( time() ); + $user_agent = ! empty( $_SERVER['HTTP_USER_AGENT'] ) ? md5( sanitize_textarea_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) . time() ) : md5( time() ); $instance = ! empty( $_REQUEST['instance'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['instance'] ) ) : $user_agent; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $platform = ! empty( $_REQUEST['platform'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['platform'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended diff --git a/src/Actions.php b/src/Actions.php index 457325c1..b26fe1f2 100644 --- a/src/Actions.php +++ b/src/Actions.php @@ -121,7 +121,6 @@ public static function revoke_order_item_keys( $revoke ) { * @since 1.0.0 */ public static function update_activation_count( $activation ) { - error_log($activation->get_serial_id()); $key = Key::get( $activation->get_serial_id() ); if ( $key ) { $key->recount_remaining_activation(); diff --git a/src/Admin/Actions.php b/src/Admin/Actions.php index 5b194ccb..77365bf4 100644 --- a/src/Admin/Actions.php +++ b/src/Admin/Actions.php @@ -194,7 +194,6 @@ public static function handle_add_key() { update_post_meta( $product_id, '_is_serial_number', 'yes' ); update_post_meta( $product_id, '_serial_key_source', 'custom_source' ); $status = isset( $data['status'] ) ? $data['status'] : ''; - } /** diff --git a/src/Admin/Admin.php b/src/Admin/Admin.php index 072bb2da..9d10ad4c 100644 --- a/src/Admin/Admin.php +++ b/src/Admin/Admin.php @@ -75,6 +75,9 @@ public function enqueue_scripts( $hook ) { 'apiurl' => site_url( '?wc-api=serial-numbers-api' ), ) ); + + // add inline style for select2 --wp-admin-theme-color. + wp_add_inline_style( 'common', ':root{--wp-admin-theme-color:#0073aa;}' ); } @@ -136,7 +139,7 @@ public function update_footer( $footer_text ) { */ public static function get_screen_ids() { $screen_id = sanitize_title( __( 'Serial Numbers', 'wc-serial-numbers' ) ); - $screen_ids = [ + $screen_ids = array( 'toplevel_page_' . $screen_id, 'toplevel_page_wc-serial-numbers', $screen_id . '_page_wc-serial-numbers-activations', @@ -144,7 +147,7 @@ public static function get_screen_ids() { $screen_id . '_page_wc-serial-numbers-tools', $screen_id . '_page_wc-serial-numbers-reports', $screen_id . '_page_wc-serial-numbers-settings', - ]; + ); return apply_filters( 'wc_serial_numbers_screen_ids', $screen_ids ); } @@ -159,7 +162,7 @@ public static function get_screen_ids() { * @since 1.0.0 * @return void */ - public static function view( $view, $args = [], $path = '' ) { + public static function view( $view, $args = array(), $path = '' ) { if ( empty( $path ) ) { $path = __DIR__ . '/views/'; } diff --git a/src/Admin/ListTables/ActivationsTable.php b/src/Admin/ListTables/ActivationsTable.php index a2677a8d..b7bb8755 100644 --- a/src/Admin/ListTables/ActivationsTable.php +++ b/src/Admin/ListTables/ActivationsTable.php @@ -51,18 +51,18 @@ public function __construct() { public function prepare_items() { $per_page = $this->get_items_per_page( 'wcsn_activations_per_page' ); $columns = $this->get_columns(); - $hidden = []; + $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $current_page = $this->get_pagenum(); - $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'order_date'; - $order = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'desc'; - $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : null; - $product_id = isset( $_GET['product_id'] ) ? absint( $_GET['product_id'] ) : ''; - $order_id = isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : ''; - $customer_id = isset( $_GET['customer_id'] ) ? absint( $_GET['customer_id'] ) : ''; - $id = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : ''; - $serial_id = isset( $_GET['serial_id'] ) ? absint( $_GET['serial_id'] ) : ''; + $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_SPECIAL_CHARS ); + $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_SPECIAL_CHARS ); + $search = filter_input( INPUT_GET, 's', FILTER_SANITIZE_SPECIAL_CHARS ); + $product_id = filter_input( INPUT_GET, 'product_id', FILTER_SANITIZE_NUMBER_INT ); + $order_id = filter_input( INPUT_GET, 'order_id', FILTER_SANITIZE_NUMBER_INT ); + $customer_id = filter_input( INPUT_GET, 'customer_id', FILTER_SANITIZE_NUMBER_INT ); + $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT ); + $serial_id = filter_input( INPUT_GET, 'serial_id', FILTER_SANITIZE_NUMBER_INT ); if ( array_key_exists( $orderby, $this->get_sortable_columns() ) && 'order_date' !== $orderby ) { $args['orderby'] = $orderby; @@ -91,7 +91,6 @@ public function prepare_items() { 'total_pages' => $this->total_count > 0 ? ceil( $this->total_count / $per_page ) : 0, ) ); - } /** @@ -101,27 +100,16 @@ public function no_items() { esc_html_e( 'No activations found. Once a serial key is activated, it will appear here.', 'wc-serial-numbers' ); } - /** - * Retrieve the view types - * - * @since 1.0.0 - * @return array $views All the views sellable - */ - public function get_views() { - return parent::get_views(); - } - /** * Adds the order and product filters to the licenses list. * - * @param string $which + * @param string $which Which nav. */ protected function extra_tablenav( $which ) { - if ( $which === 'top' ) { + if ( 'top' === $which ) { echo '
'; $this->order_dropdown(); $this->product_dropdown(); - // $this->customer_dropdown(); submit_button( __( 'Filter', 'wc-serial-numbers' ), '', 'filter-action', false ); echo '
'; } @@ -135,9 +123,9 @@ protected function extra_tablenav( $which ) { * @since 1.4.6 */ public function process_bulk_actions( $doaction ) { - if ( $doaction ) { + if ( $doaction && check_ajax_referer( 'bulk-activations' ) ) { if ( isset( $_REQUEST['id'] ) ) { - $ids = wp_parse_id_list( $_REQUEST['id'] ); + $ids = wp_parse_id_list( wp_unslash( $_REQUEST['id'] ) ); $doaction = ( - 1 !== $_REQUEST['action'] ) ? $_REQUEST['action'] : $_REQUEST['action2']; // phpcs:ignore } elseif ( isset( $_REQUEST['ids'] ) ) { $ids = array_map( 'absint', $_REQUEST['ids'] ); @@ -201,7 +189,7 @@ public function get_columns() { * * @return array */ - function get_sortable_columns() { + public function get_sortable_columns() { $sortable_columns = array( 'instance' => array( 'instance', false ), 'serial_id' => array( 'serial_id', false ), @@ -243,13 +231,13 @@ protected function column_cb( $item ) { */ protected function column_instance( $activation ) { $delete_url = add_query_arg( - [ + array( 'id' => $activation->id, 'action' => 'delete', - ], + ), admin_url( 'admin.php?page=wc-serial-numbers-activations' ) ); - $actions['delete'] = sprintf( '%2$s', esc_url( $delete_url ), __( 'Delete', 'wc-serial-numbers' ) ); + $actions['delete'] = sprintf( '%2$s', wp_nonce_url( $delete_url, 'bulk-activations' ), __( 'Delete', 'wc-serial-numbers' ) ); return sprintf( '%1$s %2$s', esc_html( $activation->get_instance() ), $this->row_actions( $actions ) ); } @@ -299,5 +287,4 @@ protected function column_platform( $activation ) { protected function column_activation_time( $activation ) { return empty( $activation->get_activation_time() ) ? '—' : esc_html( $activation->get_activation_time() ); } - } diff --git a/src/Admin/ListTables/KeysTable.php b/src/Admin/ListTables/KeysTable.php index 401cb9fe..4a6c5ae6 100644 --- a/src/Admin/ListTables/KeysTable.php +++ b/src/Admin/ListTables/KeysTable.php @@ -90,18 +90,18 @@ public function __construct() { public function prepare_items() { $per_page = $this->get_items_per_page( 'wc_serial_numbers_keys_per_page' ); $columns = $this->get_columns(); - $hidden = []; + $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $current_page = $this->get_pagenum(); - $status = isset( $_GET['status'] ) ? $_GET['status'] : ''; - $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'order_date'; - $order = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'desc'; - $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : null; - $product_id = isset( $_GET['product_id'] ) ? absint( $_GET['product_id'] ) : ''; - $order_id = isset( $_GET['order_id'] ) ? absint( $_GET['order_id'] ) : ''; - $customer_id = isset( $_GET['customer_id'] ) ? absint( $_GET['customer_id'] ) : ''; - $id = isset( $_GET['id'] ) ? absint( $_GET['id'] ) : ''; + $status = filter_input( INPUT_GET, 'status', FILTER_SANITIZE_SPECIAL_CHARS ); + $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_SPECIAL_CHARS ); + $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_SPECIAL_CHARS ); + $search = filter_input( INPUT_GET, 's', FILTER_SANITIZE_SPECIAL_CHARS ); + $product_id = filter_input( INPUT_GET, 'product_id', FILTER_SANITIZE_NUMBER_INT ); + $order_id = filter_input( INPUT_GET, 'order_id', FILTER_SANITIZE_NUMBER_INT ); + $customer_id = filter_input( INPUT_GET, 'customer_id', FILTER_SANITIZE_NUMBER_INT ); + $id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT ); if ( ! empty( $status ) && ! array_key_exists( $status, wcsn_get_key_statuses() ) ) { $status = 'available'; } @@ -124,12 +124,12 @@ public function prepare_items() { ); $this->items = Key::query( $args ); - $this->available_count = Key::count( array_merge( $args, [ 'status' => 'available' ] ) ); - $this->pending_count = Key::count( array_merge( $args, [ 'status' => 'pending' ] ) ); - $this->sold_count = Key::count( array_merge( $args, [ 'status' => 'sold' ] ) ); - $this->expired_count = Key::count( array_merge( $args, [ 'status' => 'expired' ] ) ); - $this->cancelled_count = Key::count( array_merge( $args, [ 'status' => 'cancelled' ] ) ); - $this->total_count = array_sum( [ $this->available_count, $this->sold_count, $this->pending_count, $this->expired_count, $this->cancelled_count ] ); + $this->available_count = Key::count( array_merge( $args, array( 'status' => 'available' ) ) ); + $this->pending_count = Key::count( array_merge( $args, array( 'status' => 'pending' ) ) ); + $this->sold_count = Key::count( array_merge( $args, array( 'status' => 'sold' ) ) ); + $this->expired_count = Key::count( array_merge( $args, array( 'status' => 'expired' ) ) ); + $this->cancelled_count = Key::count( array_merge( $args, array( 'status' => 'cancelled' ) ) ); + $this->total_count = array_sum( array( $this->available_count, $this->sold_count, $this->pending_count, $this->expired_count, $this->cancelled_count ) ); switch ( $status ) { case 'available': @@ -160,14 +160,13 @@ public function prepare_items() { 'total_pages' => $total_items > 0 ? ceil( $total_items / $per_page ) : 0, ) ); - } /** * No items found text. */ public function no_items() { - echo sprintf( '%s %s', esc_html__( 'No keys found.', 'wc-serial-numbers' ), '' . esc_html__( 'Add new key', 'wc-serial-numbers' ) . '' ); + printf( '%s %s', esc_html__( 'No keys found.', 'wc-serial-numbers' ), '' . esc_html__( 'Add new key', 'wc-serial-numbers' ) . '' ); // Show a documentation about key's statuses. ?>

@@ -210,7 +209,7 @@ public function no_items() { * @return array $views All the views sellable */ public function get_views() { - $current = isset( $_GET['status'] ) ? sanitize_key( $_GET['status'] ) : ''; + $current = isset( $_GET['status'] ) ? sanitize_key( wp_unslash( $_GET['status'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $available_count = ' (' . $this->available_count . ')'; $pending_count = ' (' . $this->pending_count . ')'; $sold_count = ' (' . $this->sold_count . ')'; @@ -219,12 +218,48 @@ public function get_views() { $total_count = ' (' . $this->total_count . ')'; $url = admin_url( 'admin.php?page=wc-serial-numbers' ); $views = array( - 'all' => sprintf( '%s', remove_query_arg( 'status', $url ), __( 'All keys.', 'wc-serial-numbers' ), $current === 'all' || $current == '' ? ' class="current"' : '', __( 'All', 'wc-serial-numbers' ) . $total_count ), - 'available' => sprintf( '%s', add_query_arg( 'status', 'available', $url ), __( 'Available for sell.', 'wc-serial-numbers' ), $current === 'available' ? ' class="current"' : '', __( 'Available', 'wc-serial-numbers' ) . $available_count ), - 'pending' => sprintf( '%s', add_query_arg( 'status', 'pending', $url ), __( 'Pending payment.', 'wc-serial-numbers' ), $current === 'pending' ? ' class="current"' : '', __( 'Pending', 'wc-serial-numbers' ) . $pending_count ), - 'sold' => sprintf( '%s', add_query_arg( 'status', 'sold', $url ), __( 'Sold keys.', 'wc-serial-numbers' ), $current === 'sold' ? ' class="current"' : '', __( 'Sold', 'wc-serial-numbers' ) . $sold_count ), - 'expired' => sprintf( '%s', add_query_arg( 'status', 'expired', $url ), __( 'Expired keys.', 'wc-serial-numbers' ), $current === 'expired' ? ' class="current"' : '', __( 'Expired', 'wc-serial-numbers' ) . $expired_count ), - 'cancelled' => sprintf( '%s', add_query_arg( 'status', 'cancelled', $url ), __( 'Cancelled keys.', 'wc-serial-numbers' ), $current === 'cancelled' ? ' class="current"' : '', __( 'Cancelled', 'wc-serial-numbers' ) . $cancelled_count ), + 'all' => sprintf( + '%s', + remove_query_arg( 'status', $url ), + __( 'All keys.', 'wc-serial-numbers' ), + 'all' === $current || '' === $current ? ' class="current"' : '', + __( 'All', 'wc-serial-numbers' ) . $total_count + ), + 'available' => sprintf( + '%s', + add_query_arg( 'status', 'available', $url ), + __( 'Available for sell.', 'wc-serial-numbers' ), + 'available' === $current ? ' class="current"' : '', + __( 'Available', 'wc-serial-numbers' ) . $available_count + ), + 'pending' => sprintf( + '%s', + add_query_arg( 'status', 'pending', $url ), + __( 'Pending payment.', 'wc-serial-numbers' ), + 'pending' === $current ? ' class="current"' : '', + __( 'Pending', 'wc-serial-numbers' ) . $pending_count + ), + 'sold' => sprintf( + '%s', + add_query_arg( 'status', 'sold', $url ), + __( 'Sold keys.', 'wc-serial-numbers' ), + 'sold' === $current ? ' class="current"' : '', + __( 'Sold', 'wc-serial-numbers' ) . $sold_count + ), + 'expired' => sprintf( + '%s', + add_query_arg( 'status', 'expired', $url ), + __( 'Expired keys.', 'wc-serial-numbers' ), + 'expired' === $current ? ' class="current"' : '', + __( 'Expired', 'wc-serial-numbers' ) . $expired_count + ), + 'cancelled' => sprintf( + '%s', + add_query_arg( 'status', 'cancelled', $url ), + __( 'Cancelled keys.', 'wc-serial-numbers' ), + 'cancelled' === $current ? ' class="current"' : '', + __( 'Cancelled', 'wc-serial-numbers' ) . $cancelled_count + ), ); return $views; @@ -236,7 +271,7 @@ public function get_views() { * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { - if ( $which === 'top' ) { + if ( 'top' === $which ) { echo '
'; $this->order_dropdown(); $this->product_dropdown(); @@ -255,9 +290,9 @@ protected function extra_tablenav( $which ) { * @since 1.4.6 */ public function process_bulk_actions( $doaction ) { - if ( $doaction ) { - if ( isset( $_REQUEST['id'] ) ) { - $ids = wp_parse_id_list( $_REQUEST['id'] ); + if ( $doaction && check_ajax_referer( 'bulk-' . $this->_args['plural'] ) ) { + if ( wp_unslash( isset( $_REQUEST['id'] ) ) ) { + $ids = wp_parse_id_list( wp_unslash( $_REQUEST['id'] ) ); $doaction = ( - 1 !== $_REQUEST['action'] ) ? $_REQUEST['action'] : $_REQUEST['action2']; // phpcs:ignore } elseif ( isset( $_REQUEST['ids'] ) ) { $ids = array_map( 'absint', $_REQUEST['ids'] ); @@ -331,7 +366,7 @@ public function get_columns() { * * @return array */ - function get_sortable_columns() { + public function get_sortable_columns() { $sortable_columns = array( 'key' => array( 'serial_key', false ), 'product' => array( 'product_id', false ), @@ -361,7 +396,7 @@ protected function get_primary_column_name() { /** * since 1.0.0 * - * @param object $item + * @param \StdClass $item Item. * * @return string|void */ @@ -372,23 +407,24 @@ protected function column_cb( $item ) { /** * Display key. * - * @param $item + * @param Key $item Item. * * @since 1.4.6 */ protected function column_key( $item ) { - $is_hidden = 'yes' === get_option( 'wc_serial_numbers_hide_serial_number', 'yes' ); - $edit_url = add_query_arg( [ 'edit' => $item->id ], admin_url( 'admin.php?page=wc-serial-numbers' ) ); - $delete_url = add_query_arg( - [ + $is_hidden = 'yes' === get_option( 'wc_serial_numbers_hide_serial_number', 'yes' ); + $edit_url = add_query_arg( array( 'edit' => $item->id ), admin_url( 'admin.php?page=wc-serial-numbers' ) ); + $delete_url = add_query_arg( + array( 'id' => $item->id, 'action' => 'delete', - ], + ), admin_url( 'admin.php?page=wc-serial-numbers' ) ); - $actions['id'] = sprintf( __( 'ID: %d', 'wc-serial-numbers' ), $item->id ); + // translators: %d: key id. + $actions['id'] = sprintf( __( 'ID: %d', 'wc-serial-numbers' ), esc_html( $item->id ) ); $actions['edit'] = sprintf( '%2$s', $edit_url, __( 'Edit', 'wc-serial-numbers' ) ); - $actions['delete'] = sprintf( '%2$s', $delete_url, __( 'Delete', 'wc-serial-numbers' ) ); + $actions['delete'] = sprintf( '%2$s', wp_nonce_url( $delete_url, 'bulk-keys' ), __( 'Delete', 'wc-serial-numbers' ) ); return sprintf( '%1$s %2$s', $item->print_key( $is_hidden ), $this->row_actions( $actions ) ); } @@ -396,7 +432,7 @@ protected function column_key( $item ) { /** * Display column product. * - * @param Key $key Key object. + * @param Key $item Item. * * @since 1.4.6 */ @@ -409,7 +445,7 @@ protected function column_product( $item ) { /** * Display column order. * - * @param Key $key Key object. + * @param Key $item Item. * * @since 1.4.6 */ @@ -425,7 +461,7 @@ protected function column_order( $item ) { /** * Display column customer. * - * @param Key $key Key object. + * @param \StdClass $item Item. * * @since 1.4.6 */ @@ -458,10 +494,10 @@ protected function column_activation( $key ) { $limit = ! empty( $key->activation_limit ) ? $key->activation_limit : '∞'; $count = (int) $key->activation_count; $link = add_query_arg( - [ + array( 'serial_id' => $key->id, 'page' => 'wc-serial-numbers-activations', - ], + ), admin_url( 'admin.php' ) ); @@ -478,7 +514,21 @@ protected function column_activation( $key ) { * @since 1.4.6 */ protected function column_valid_for( $key ) { - return ! empty( $key->get_validity() ) ? sprintf( _n( '%s Day
After purchase', '%s Days
After purchase', $key->get_validity(), 'wc-serial-numbers' ), number_format_i18n( $key->get_validity() ) ) : __( 'Lifetime', 'wc-serial-numbers' ); + if ( ! empty( $key->get_validity() ) ) { + return wp_kses_post( + sprintf( + // translators: %1$s: validity, %2$s: validity. + _n( + '%s Day
After purchase', + '%s Days
After purchase', + $key->get_validity(), + 'wc-serial-numbers' + ), + number_format_i18n( $key->get_validity() ) + ) + ); + } + return __( 'Lifetime', 'wc-serial-numbers' ); } /** @@ -489,7 +539,10 @@ protected function column_valid_for( $key ) { * @since 1.4.6 */ protected function column_order_date( $key ) { - return ! empty( $key->order_date ) && '0000-00-00 00:00:00' !== $key->order_date ? date( get_option( 'date_format' ), strtotime( $key->order_date ) ) : '—'; + if ( ! empty( $key->order_date ) && '0000-00-00 00:00:00' !== $key->order_date ) { + return wp_date( get_option( 'date_format' ), strtotime( $key->order_date ) ); + } + return '—'; } /** diff --git a/src/Admin/ListTables/ListTable.php b/src/Admin/ListTables/ListTable.php index f42e3ba7..3539c210 100644 --- a/src/Admin/ListTables/ListTable.php +++ b/src/Admin/ListTables/ListTable.php @@ -28,15 +28,15 @@ class ListTable extends \WP_List_Table { /** * Get a request var, or return the default if not set. * - * @param string $var Request var name. - * @param mixed $default Default value. + * @param string $param Request var name. + * @param mixed $fallback Default value. * * @since 1.4.6 * * @return mixed Un-sanitized request var */ - protected function get_request_var( $var = '', $default = false ) { - return isset( $_REQUEST[ $var ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $var ] ) ) : $default; // phpcs:ignore WordPress.Security.NonceVerification + protected function get_request_var( $param = '', $fallback = false ) { + return isset( $_REQUEST[ $param ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $param ] ) ) : $fallback; // phpcs:ignore WordPress.Security.NonceVerification } /** @@ -202,17 +202,6 @@ public function customer_dropdown() { * @since 1.4.6 */ public function process_bulk_actions( $doaction ) { - if ( ! empty( $_GET['_wp_http_referer'] ) ) { - wp_redirect( - remove_query_arg( - array( - '_wp_http_referer', - '_wpnonce', - ), - wp_unslash( $_SERVER['REQUEST_URI'] ) - ) - ); - exit; - } + $referer = wp_get_referer(); } } diff --git a/src/Admin/ListTables/StockTable.php b/src/Admin/ListTables/StockTable.php index 42f3e45b..6e08b512 100644 --- a/src/Admin/ListTables/StockTable.php +++ b/src/Admin/ListTables/StockTable.php @@ -32,14 +32,14 @@ public function __construct() { public function prepare_items() { $per_page = 20; $columns = $this->get_columns(); - $hidden = []; + $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $current_page = $this->get_pagenum(); - $orderby = isset( $_GET['orderby'] ) ? sanitize_key( $_GET['orderby'] ) : 'order_date'; - $order = isset( $_GET['order'] ) ? sanitize_key( $_GET['order'] ) : 'desc'; - $search = isset( $_GET['s'] ) ? sanitize_text_field( $_GET['s'] ) : null; - $product_id = isset( $_GET['product_id'] ) ? absint( $_GET['product_id'] ) : ''; + $orderby = filter_input( INPUT_GET, 'orderby', FILTER_SANITIZE_SPECIAL_CHARS ); + $order = filter_input( INPUT_GET, 'order', FILTER_SANITIZE_SPECIAL_CHARS ); + $search = filter_input( INPUT_GET, 's', FILTER_SANITIZE_SPECIAL_CHARS ); + $product_id = filter_input( INPUT_GET, 'product_id', FILTER_SANITIZE_NUMBER_INT ); $query_args = array( 'posts_per_page' => $per_page, @@ -70,23 +70,13 @@ public function no_items() { esc_html_e( 'No products selling serial keys from "stock" found.', 'wc-serial-numbers' ); } - /** - * Retrieve the view types - * - * @since 1.0.0 - * @return array $views All the views sellable - */ - public function get_views() { - return parent::get_views(); - } - /** * Adds the order and product filters to the licenses list. * * @param string $which The location of the extra table nav markup: 'top' or 'bottom'. */ protected function extra_tablenav( $which ) { - if ( $which === 'top' ) { + if ( 'top' === $which ) { echo '
'; $this->product_dropdown(); submit_button( __( 'Filter', 'wc-serial-numbers' ), '', 'filter-action', false ); @@ -116,7 +106,7 @@ public function get_columns() { * * @return array */ - function get_sortable_columns() { + public function get_sortable_columns() { $columns = array( 'product' => array( 'product_id', false ), ); @@ -169,7 +159,7 @@ public function column_default( $item, $column_name ) { case 'sold': $sold_count = wcsn_get_keys( array( - 'status__in' => [ 'sold', 'expired' ], + 'status__in' => array( 'sold', 'expired' ), 'product_id' => $item->get_id(), 'count' => true, ) diff --git a/src/Admin/Menus.php b/src/Admin/Menus.php index 2d96cfaf..5399f067 100644 --- a/src/Admin/Menus.php +++ b/src/Admin/Menus.php @@ -19,10 +19,6 @@ class Menus { * @since 1.0.0 */ public function __construct() { - // add_action( 'current_screen', array( $this, 'setup_screen' ) ); - // add_action( 'check_ajax_referer', array( $this, 'setup_screen' ) ); - // add_filter( 'set-screen-option', array( __CLASS__, 'save_screen_options' ), 10, 3 ); - // Register the menus. add_action( 'admin_menu', array( $this, 'main_menu' ) ); add_action( 'admin_menu', array( $this, 'activations_menu' ), 40 ); @@ -48,7 +44,7 @@ public function __construct() { * @since 1.4.6 */ public function setup_screen() { - if ( isset( $_GET['edit'] ) || isset( $_GET['delete'] ) || isset( $_GET['add'] ) || isset( $_GET['generate'] ) ) { + if ( isset( $_GET['edit'] ) || isset( $_GET['delete'] ) || isset( $_GET['add'] ) || isset( $_GET['generate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } @@ -59,12 +55,6 @@ public function setup_screen() { $screen_id = isset( $screen, $screen->id ) ? $screen->id : ''; } - // switch ( $screen_id ) { - // case $plugin_screen_id . '-page-wc-serial-numbers': - // $this->list_table = new ListTables\KeysTable(); - // break; - // } - // Ensure the table handler is only loaded once. Prevents multiple loads if a plugin calls check_ajax_referer many times. remove_action( 'current_screen', array( $this, 'setup_screen' ) ); remove_action( 'check_ajax_referer', array( $this, 'setup_screen' ) ); @@ -223,11 +213,11 @@ public function output_main_page() { if ( $add ) { $key = new Key(); - include dirname( __FILE__ ) . '/views/html-edit-key.php'; + include __DIR__ . '/views/html-edit-key.php'; } elseif ( $edit ) { - include dirname( __FILE__ ) . '/views/html-edit-key.php'; + include __DIR__ . '/views/html-edit-key.php'; } else { - include dirname( __FILE__ ) . '/views/html-list-keys.php'; + include __DIR__ . '/views/html-list-keys.php'; } } @@ -263,8 +253,8 @@ public function output_tools_page() { $tabs = apply_filters( 'wc_serial_numbers_tools_tabs', $tabs ); $tab_ids = array_keys( $tabs ); - $current_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : reset( $tab_ids ); - $page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : ''; + $current_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : reset( $tab_ids ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended Admin::view( 'html-tools.php', @@ -285,14 +275,12 @@ public function output_tools_page() { public function output_reports_page() { $tabs = array( 'stock' => __( 'Stock', 'wc-serial-numbers' ), - // 'sales' => __( 'Sales', 'wc-serial-numbers' ), - // 'activations' => __( 'Activations', 'wc-serial-numbers' ), ); $tabs = apply_filters( 'wc_serial_numbers_reports_tabs', $tabs ); $tab_ids = array_keys( $tabs ); - $current_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : reset( $tab_ids ); - $page = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : ''; + $current_tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : reset( $tab_ids ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended Admin::view( 'html-reports.php', @@ -311,8 +299,8 @@ public function output_reports_page() { * @return void */ public function go_pro_redirect() { - if ( isset( $_GET['page'] ) && 'go_wcsn_pro' === $_GET['page'] ) { - wp_redirect( 'https://pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=admin-menu&utm_medium=link&utm_campaign=upgrade&utm_id=wc-serial-numbers' ); + if ( isset( $_GET['page'] ) && 'go_wcsn_pro' === $_GET['page'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended + wp_redirect( 'https://pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=admin-menu&utm_medium=link&utm_campaign=upgrade&utm_id=wc-serial-numbers' ); // phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect die; } } @@ -427,7 +415,8 @@ public static function status_tab() { foreach ( $cron_jobs as $cron_job => $cron_job_name ) { $next_scheduled = wp_next_scheduled( $cron_job ); if ( $next_scheduled ) { - $statuses[ $cron_job_name ] = sprintf( __( 'Next run: %s', 'wc-serial-numbers' ), date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $next_scheduled ) ); + // translators: %s: Next scheduled time. + $statuses[ $cron_job_name ] = sprintf( __( 'Next run: %s', 'wc-serial-numbers' ), esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $next_scheduled ) ) ); } else { $statuses[ $cron_job_name ] = __( 'Not scheduled', 'wc-serial-numbers' ); } diff --git a/src/Admin/Metaboxes.php b/src/Admin/Metaboxes.php index 3c4760a0..8aa38054 100644 --- a/src/Admin/Metaboxes.php +++ b/src/Admin/Metaboxes.php @@ -25,8 +25,11 @@ public function __construct() { } /** - * product - * since 1.0.0 + * Add product data tab. + * + * @param array $tabs product data tabs. + * + * @return mixed */ public static function product_data_tab( $tabs ) { $tabs['wc_serial_numbers'] = array( @@ -46,7 +49,7 @@ public static function product_write_panel() { global $post, $woocommerce; ?> @@ -132,18 +145,19 @@ public static function product_write_panel() { /** * Show promo box. * - * @param $variation_data - * @param $variation - * - * @param $loop - * * @since 1.2.0 */ - public static function variable_product_content( $loop, $variation_data, $variation ) { + public static function variable_product_content() { if ( ! WCSN()->is_premium_active() ) { - echo sprintf( '

%s %s

', __( 'The free version of Serial Numbers for WooCommerce does not support product variation.', 'wc-serial-numbers' ), 'https://www.pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=product_page_license_area&utm_medium=link&utm_campaign=wc-serial-numbers&utm_content=Upgrade%20to%20Pro', __( 'Upgrade to Pro', 'wc-serial-numbers' ) ); + echo wp_kses_post( + sprintf( + '

%s %s

', + __( 'The free version of Serial Numbers for WooCommerce does not support product variation.', 'wc-serial-numbers' ), + 'https://www.pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=product_page_license_area&utm_medium=link&utm_campaign=wc-serial-numbers&utm_content=Upgrade%20to%20Pro', + __( 'Upgrade to Pro', 'wc-serial-numbers' ) + ) + ); } - } /** @@ -152,12 +166,13 @@ public static function variable_product_content( $loop, $variation_data, $variat public static function product_save_data() { global $post; $status = isset( $_POST['_is_serial_number'] ) ? 'yes' : 'no'; - $source = isset( $_POST['_serial_key_source'] ) ? sanitize_text_field( $_POST['_serial_key_source'] ) : 'custom_source'; + $source = isset( $_POST['_serial_key_source'] ) ? sanitize_text_field( wp_unslash( $_POST['_serial_key_source'] ) ) : 'custom_source'; update_post_meta( $post->ID, '_is_serial_number', $status ); update_post_meta( $post->ID, '_serial_key_source', $source ); - // save only if software licensing enabled - if ( ! wc_serial_numbers_software_support_disabled() ) { - update_post_meta( $post->ID, '_software_version', ! empty( $_POST['_software_version'] ) ? sanitize_text_field( $_POST['_software_version'] ) : '' ); + // save only if software licensing enabled. + if ( wcsn_is_software_support_enabled() ) { + $software_version = isset( $_POST['_software_version'] ) ? sanitize_text_field( wp_unslash( $_POST['_software_version'] ) ) : ''; + update_post_meta( $post->ID, '_software_version', $software_version ); } do_action( 'wcsn_save_simple_product_meta', $post ); @@ -165,42 +180,40 @@ public static function product_save_data() { /** + * Display serial numbers in order item meta. * - * @param $o_item - * @param $product - * - * @param $o_item_id + * @param int $o_item_id order item id. + * @param \WC_Order_Item $o_item order item object. + * @param \WC_Product $product product object. * * @since 1.1.6 * - * @return bool|string + * @return void */ public function order_itemmeta( $o_item_id, $o_item, $product ) { global $post; if ( ! is_object( $post ) || ! isset( $post->ID ) ) { - return false; + return; } $order = wc_get_order( $post->ID ); - // bail for no order + // bail for no order. if ( ! $order ) { - return false; + return; } if ( 'completed' !== $order->get_status( 'edit' ) ) { - return ''; + return; } - // if this is not product then no need to process + // if this is not product then no need to process. if ( empty( $product ) ) { - return false; + return; } - $is_serial_product = 'yes' == get_post_meta( $product->get_id(), '_is_serial_number', true ); - - if ( ! $is_serial_product ) { - return false; + if ( 'yes' !== get_post_meta( $product->get_id(), '_is_serial_number', true ) ) { + return; } $items = wcsn_get_keys( @@ -211,22 +224,28 @@ public function order_itemmeta( $o_item_id, $o_item, $product ) { ); if ( empty( $items ) && $order ) { - echo sprintf( '
%s
', __( 'Order missing serial numbers for this item.', 'wc-serial-numbers' ) ); - - return true; + echo wp_kses_post( + sprintf( + '
%s
', + __( 'Order missing serial numbers for this item.', 'wc-serial-numbers' ) + ) + ); + return; } $url = admin_url( 'admin.php?page=wc-serial-numbers' ); - echo sprintf( + printf( '
%s→', - add_query_arg( - [ - 'order_id' => $post->ID, - 'product_id' => $product->get_id(), - ], - $url + esc_url( + add_query_arg( + array( + 'order_id' => $post->ID, + 'product_id' => $product->get_id(), + ), + $url + ) ), - __( 'Serial Numbers', 'wc-serial-numbers' ) + esc_html__( 'Serial Numbers', 'wc-serial-numbers' ) ); $url = admin_url( 'admin.php?page=wc-serial-numbers' ); @@ -237,15 +256,19 @@ public function order_itemmeta( $o_item_id, $o_item, $product ) { $li .= sprintf( '
  •  %s
  • ', add_query_arg( - [ + array( 'edit' => $item->id, - ], + ), $url ), - wc_serial_numbers_decrypt_key( $item->serial_key ) + wcsn_decrypt_key( $item->serial_key ) ); } - - echo sprintf( '
      %s
    ', $li ); + echo wp_kses_post( + sprintf( + '
      %s
    ', + $li + ) + ); } } diff --git a/src/Admin/Notices.php b/src/Admin/Notices.php index 3972933b..014fc9d6 100644 --- a/src/Admin/Notices.php +++ b/src/Admin/Notices.php @@ -25,10 +25,10 @@ class Notices { * @since 1.0.0 */ public function __construct() { - add_action( 'admin_init', [ $this, 'add_notices' ] ); - add_action( 'admin_notices', [ $this, 'output_notices' ] ); - add_action( 'wp_ajax_wc_serial_numbers_dismiss_notice', [ $this, 'dismiss_notice' ] ); - add_action( 'admin_footer', [ $this, 'add_notice_script' ] ); + add_action( 'admin_init', array( $this, 'add_notices' ) ); + add_action( 'admin_notices', array( $this, 'output_notices' ) ); + add_action( 'wp_ajax_wc_serial_numbers_dismiss_notice', array( $this, 'dismiss_notice' ) ); + add_action( 'admin_footer', array( $this, 'add_notice_script' ) ); } /** @@ -39,7 +39,7 @@ public function __construct() { public function add_notices() { $is_outdated_pro = defined( 'WC_SERIAL_NUMBER_PRO_PLUGIN_VERSION' ) && version_compare( WC_SERIAL_NUMBER_PRO_PLUGIN_VERSION, '1.2.1', '<' ); if ( ! $is_outdated_pro ) { - $is_outdated_pro = function_exists( 'wc_serial_numbers_pro' ) && is_callable( [ 'wc_serial_numbers_pro', 'get_version' ] ) && wc_serial_numbers_pro()->get_version() && version_compare( wc_serial_numbers_pro()->get_version(), '1.2.1', '<' ); + $is_outdated_pro = function_exists( 'wc_serial_numbers_pro' ) && is_callable( array( 'wc_serial_numbers_pro', 'get_version' ) ) && wc_serial_numbers_pro()->get_version() && version_compare( wc_serial_numbers_pro()->get_version(), '1.2.1', '<' ); } if ( $is_outdated_pro ) { $this->notices[] = array( diff --git a/src/Admin/Orders.php b/src/Admin/Orders.php index 0524a153..92ce2635 100644 --- a/src/Admin/Orders.php +++ b/src/Admin/Orders.php @@ -97,7 +97,7 @@ public static function add_order_serial_column( $columns ) { public static function add_order_serial_column_content( $column, $order_id ) { $order_status = wc_get_order( $order_id )->get_status(); if ( 'order_serials' === $column ) { - if ( ! wcsn_order_has_products( $order_id ) || ! in_array( $order_status, [ 'completed', 'processing' ], true ) ) { + if ( ! wcsn_order_has_products( $order_id ) || ! in_array( $order_status, array( 'completed', 'processing' ), true ) ) { echo '—'; } else { if ( wcsn_order_is_fullfilled( $order_id ) ) { @@ -107,8 +107,8 @@ public static function add_order_serial_column_content( $column, $order_id ) { $style = 'color:red'; $title = __( 'Order is not fullfilled.', 'wc-serial-numbers' ); } - $url = add_query_arg( [ 'order_id' => $order_id ], admin_url( 'admin.php?page=wc-serial-numbers' ) ); - echo sprintf( '', esc_url( $url ), esc_html( $title ), esc_attr( $style ) ); + $url = add_query_arg( array( 'order_id' => $order_id ), admin_url( 'admin.php?page=wc-serial-numbers' ) ); + printf( '', esc_url( $url ), esc_html( $title ), esc_attr( $style ) ); } } } @@ -139,7 +139,7 @@ public function add_order_bulk_action( $actions ) { * @return string */ public function handle_order_bulk_action( $redirect_to, $action, $order_ids ) { - if ( in_array( $action, [ 'wcsn_add_keys', 'wcsn_remove_keys' ], true ) ) { + if ( in_array( $action, array( 'wcsn_add_keys', 'wcsn_remove_keys' ), true ) ) { foreach ( $order_ids as $order_id ) { switch ( $action ) { case 'wcsn_add_keys': @@ -217,7 +217,7 @@ public static function display_order_item_meta( $item_id, $item, $product ) { - + $field ) : ?> diff --git a/src/Admin/Products.php b/src/Admin/Products.php index b7cbdf2b..d5e1e7b9 100644 --- a/src/Admin/Products.php +++ b/src/Admin/Products.php @@ -27,7 +27,6 @@ public function __construct() { * @since 1.0.0 */ public static function print_style() { - ob_start(); ?> __( 'General Settings', 'wc-serial-numbers' ), 'type' => 'title', 'desc' => __( 'These options determine the behavior and operation of the plugin.', 'wc-serial-numbers' ), 'id' => 'section_serial_numbers', - ], - [ + ), + array( 'title' => __( 'Auto-complete orders', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_autocomplete_order', 'desc' => __( 'Automatically completes orders after successful payments.', 'wc-serial-numbers' ), 'type' => 'checkbox', 'default' => 'no', - ], - [ + ), + array( 'title' => __( 'Reuse keys', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_reuse_serial_number', 'desc' => __( 'Recover failed, refunded keys for selling again.', 'wc-serial-numbers' ), 'desc_tip' => __( 'If you enable this option, the keys will be available for selling again if the order is refunded or failed.', 'wc-serial-numbers' ), 'type' => 'checkbox', 'default' => 'no', - ], + ), // Revoke serial keys. - [ + array( 'title' => __( 'Revoke keys', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_revoke_keys', 'desc' => __( 'Revoke keys when the order status changes to cancelled or refunded.', 'wc-serial-numbers' ), 'desc_tip' => __( 'If you enable this option, the keys will be revoked when the order status changes to cancelled or refunded.', 'wc-serial-numbers' ), 'type' => 'checkbox', 'default' => 'no', - ], - [ + ), + array( 'title' => __( 'Hide keys', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_hide_serial_number', 'desc' => __( 'Keys will be masked in the list table.', 'wc-serial-numbers' ), 'default' => 'yes', 'type' => 'checkbox', - ], - [ - 'title' => __( 'Disable software support', 'wc-serial-numbers' ), - 'id' => 'wc_serial_numbers_disable_software_support', - 'desc' => __( 'Disable Software Licensing support & API functionalities.', 'wc-serial-numbers' ), + ), + array( + 'title' => __( 'Disable software support', 'wc-serial-numbers' ), + 'id' => 'wc_serial_numbers_disable_software_support', + 'desc' => __( 'Disable Software Licensing support & API functionalities.', 'wc-serial-numbers' ), 'desc_tip' => __( 'If you enable this option, the activation menu and it’s functionality will be turned off.', 'wc-serial-numbers' ), - 'default' => 'no', - 'type' => 'checkbox', - ], - [ + 'default' => 'no', + 'type' => 'checkbox', + ), + array( 'type' => 'sectionend', 'id' => 'section_serial_numbers', - ], - [ + ), + array( 'title' => __( 'Stock Notification', 'wc-serial-numbers' ), 'type' => 'title', 'desc' => __( 'These options determine the operation of the key\'s stock notification.', 'wc-serial-numbers' ), 'id' => 'stock_section', - ], - [ + ), + array( 'title' => __( 'Stock notification email', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_enable_stock_notification', 'desc' => __( 'Sends notification emails when key stock is low.', 'wc-serial-numbers' ), 'type' => 'checkbox', 'sanitize_callback' => 'intval', 'default' => 'yes', - ], + ), array( 'title' => __( 'Stock threshold', 'wc-serial-numbers' ), 'id' => 'wc_serial_numbers_stock_threshold', @@ -119,10 +119,10 @@ public function get_settings( $tab ) { 'type' => 'text', 'default' => get_option( 'admin_email' ), ), - [ + array( 'type' => 'sectionend', 'id' => 'stock_section', - ], + ), ); break; } @@ -187,7 +187,7 @@ protected function output_premium_widget() { public function output_tabs( $tabs ) { parent::output_tabs( $tabs ); if ( WCSN()->get_docs_url() ) { - echo sprintf( '%s', WCSN()->get_docs_url(), __( 'Documentation', 'wc-serial-numbers' ) ); + printf( '%s', esc_url( WCSN()->get_docs_url() ), esc_html__( 'Documentation', 'wc-serial-numbers' ) ); } } } diff --git a/src/Admin/views/html-edit-key.php b/src/Admin/views/html-edit-key.php index d99d676f..e018c16a 100644 --- a/src/Admin/views/html-edit-key.php +++ b/src/Admin/views/html-edit-key.php @@ -39,7 +39,7 @@ $option ) : ?> - %s', esc_attr( $status ), selected( $key->get_status(), $status, false ), esc_html( $option ) ); ?> + %s', esc_attr( $status ), selected( $key->get_status(), $status, false ), esc_html( $option ) ); ?>

    @@ -105,7 +105,7 @@

    + - 1, 'fields' => 'ids', - 'meta_query' => array( + 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query array( 'key' => '_is_serial_number', 'value' => 'yes', @@ -245,9 +246,9 @@ public function activation_form( $atts ) {

    + - %s', esc_url( get_permalink( $line_item['product_id'] ) ), esc_html( get_the_title( $line_item['product_id'] ) ) ); ?> + %s', esc_url( get_permalink( $line_item['product_id'] ) ), esc_html( get_the_title( $line_item['product_id'] ) ) ); ?> @@ -302,7 +302,7 @@ function wcsn_display_order_keys_table( $order, $line_items ) { - %s

    ', apply_filters( 'wc_serial_numbers_pending_notice', esc_html__( 'Order is waiting for serial numbers to be assigned.', 'wc-serial-numbers' ) ) ); ?> + %s

    ', esc_html( apply_filters( 'wc_serial_numbers_pending_notice', __( 'Order is waiting for serial numbers to be assigned.', 'wc-serial-numbers' ) ) ) ); ?> diff --git a/src/Installer.php b/src/Installer.php index 73a1eab7..39c2cb4d 100644 --- a/src/Installer.php +++ b/src/Installer.php @@ -138,7 +138,7 @@ public static function create_tables() { global $wpdb; $wpdb->hide_errors(); // todo rename table names to wcsn_keys and wcsn_activations. - $tables = [ + $tables = array( "CREATE TABLE IF NOT EXISTS {$wpdb->prefix}serial_numbers( id bigint(20) NOT NULL AUTO_INCREMENT, serial_key longtext DEFAULT NULL, @@ -173,7 +173,7 @@ public static function create_tables() { PRIMARY KEY (id), key serial_id (serial_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;", - ]; + ); require_once ABSPATH . 'wp-admin/includes/upgrade.php'; foreach ( $tables as $table ) { @@ -238,23 +238,22 @@ protected function update_120() { } global $wpdb; - $prefix = $wpdb->prefix; - $wpdb->query( "RENAME TABLE `{$prefix}wcsn_serial_numbers` TO `{$prefix}serial_numbers`" ); - $wpdb->query( "RENAME TABLE `{$prefix}wcsn_activations` TO `{$prefix}serial_numbers_activations`" ); - - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers DROP COLUMN `serial_image`;" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers DROP COLUMN `activation_email`;" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers CHANGE `created` `created_date` DATETIME NULL DEFAULT NULL;" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD vendor_id bigint(20) NOT NULL DEFAULT 0" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD activation_count int(9) NOT NULL DEFAULT 0" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD KEY vendor_id(`vendor_id`)" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD source varchar(200) NOT NULL default 'custom_source'" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers_activations CHANGE platform platform varchar(200) DEFAULT NULL" ); - // status update - $wpdb->query( $wpdb->prepare( "UPDATE {$prefix}serial_numbers set status=%s WHERE status=%s AND order_id=0", 'available', 'new' ) ); - $wpdb->query( $wpdb->prepare( "UPDATE {$prefix}serial_numbers set status=%s WHERE status=%s AND order_id != 0", 'sold', 'active' ) ); - $wpdb->query( $wpdb->prepare( "UPDATE {$prefix}serial_numbers set status=%s WHERE status=%s", 'cancelled', 'pending' ) ); - $wpdb->query( $wpdb->prepare( "UPDATE {$prefix}serial_numbers set status=%s WHERE status=%s", 'cancelled', 'rejected' ) ); + $wpdb->query( "RENAME TABLE `{$wpdb->prefix}wcsn_serial_numbers` TO `{$wpdb->prefix}serial_numbers`" ); + $wpdb->query( "RENAME TABLE `{$wpdb->prefix}wcsn_activations` TO `{$wpdb->prefix}serial_numbers_activations`" ); + + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers DROP COLUMN `serial_image`;" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers DROP COLUMN `activation_email`;" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers CHANGE `created` `created_date` DATETIME NULL DEFAULT NULL;" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD vendor_id bigint(20) NOT NULL DEFAULT 0" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD activation_count int(9) NOT NULL DEFAULT 0" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD KEY vendor_id(`vendor_id`)" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD source varchar(200) NOT NULL default 'custom_source'" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers_activations CHANGE platform platform varchar(200) DEFAULT NULL" ); + // status update. + $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers set status=%s WHERE status=%s AND order_id=0", 'available', 'new' ) ); + $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers set status=%s WHERE status=%s AND order_id != 0", 'sold', 'active' ) ); + $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers set status=%s WHERE status=%s", 'cancelled', 'pending' ) ); + $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers set status=%s WHERE status=%s", 'cancelled', 'rejected' ) ); global $current_user; if ( ! empty( $current_user->ID ) && current_user_can( 'manage_options' ) ) { $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers set vendor_id=%d", $current_user->ID ) ); @@ -268,7 +267,7 @@ protected function update_120() { $wpdb->query( "UPDATE {$wpdb->prefix}serial_numbers set status='available', order_date='0000-00-00 00:00:00', order_id='0' WHERE status !='available' AND order_id='0' AND expire_date='0000-00-00 00:00:00'" ); - // settings update + // settings update. $heading_text = $this->update_1_2_0_get_option( 'heading_text', 'Serial Numbers', 'wsn_delivery_settings' ); $serial_col_heading = $this->update_1_2_0_get_option( 'table_column_heading', 'Serial Number', 'wsn_delivery_settings' ); $serial_key_label = $this->update_1_2_0_get_option( 'serial_key_label', 'Serial Number', 'wsn_delivery_settings' ); @@ -276,33 +275,33 @@ protected function update_120() { $show_validity = 'yes' === $this->update_1_2_0_get_option( 'show_validity', 'yes', 'wsn_delivery_settings' ); $show_activation_limit = 'yes' === $this->update_1_2_0_get_option( 'show_activation_limit', 'yes', 'wsn_delivery_settings' ); $license = get_option( 'woocommerce_serial_numbers_pro_pluginever_license' ); - $options = [ - 'wc_serial_numbers_autocomplete_order' => $this->update_1_2_0_get_option( 'wsn_auto_complete_order', 'yes', 'wsn_delivery_settings' ), - 'wc_serial_numbers_reuse_serial_number' => $this->update_1_2_0_get_option( 'wsn_re_use_serial', 'no', 'wsn_delivery_settings' ), - 'wc_serial_numbers_disable_software_support' => 'no', - 'wc_serial_numbers_manual_delivery' => 'no', - 'wc_serial_numbers_hide_serial_number' => 'yes', - 'wc_serial_numbers_revoke_status_cancelled' => in_array( 'cancelled', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', [], 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', - 'wc_serial_numbers_revoke_status_refunded' => in_array( 'refunded', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', [], 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', - 'wc_serial_numbers_revoke_status_failed' => in_array( 'failed', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', [], 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', - 'wc_serial_numbers_enable_stock_notification' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_send_email', 'yes', 'wsn_notification_settings' ), - 'wc_serial_numbers_stock_threshold' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_number', '5', 'wsn_notification_settings' ), - 'wc_serial_numbers_notification_recipient' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_email', get_option( 'admin_email' ), 'wsn_notification_settings' ), - 'wc_serial_numbers_order_table_heading' => $heading_text, + $options = array( + 'wc_serial_numbers_autocomplete_order' => $this->update_1_2_0_get_option( 'wsn_auto_complete_order', 'yes', 'wsn_delivery_settings' ), + 'wc_serial_numbers_reuse_serial_number' => $this->update_1_2_0_get_option( 'wsn_re_use_serial', 'no', 'wsn_delivery_settings' ), + 'wc_serial_numbers_disable_software_support' => 'no', + 'wc_serial_numbers_manual_delivery' => 'no', + 'wc_serial_numbers_hide_serial_number' => 'yes', + 'wc_serial_numbers_revoke_status_cancelled' => in_array( 'cancelled', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', array(), 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', + 'wc_serial_numbers_revoke_status_refunded' => in_array( 'refunded', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', array(), 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', + 'wc_serial_numbers_revoke_status_failed' => in_array( 'failed', $this->update_1_2_0_get_option( 'wsn_revoke_serial_number', array(), 'wsn_delivery_settings' ), true ) ? 'yes' : 'no', + 'wc_serial_numbers_enable_stock_notification' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_send_email', 'yes', 'wsn_notification_settings' ), + 'wc_serial_numbers_stock_threshold' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_number', '5', 'wsn_notification_settings' ), + 'wc_serial_numbers_notification_recipient' => $this->update_1_2_0_get_option( 'wsn_admin_bar_notification_email', get_option( 'admin_email' ), 'wsn_notification_settings' ), + 'wc_serial_numbers_order_table_heading' => $heading_text, 'wc_serial_numbers_order_table_col_product_label' => 'Product', - 'wc_serial_numbers_order_table_col_key_label' => $serial_key_label, - 'wc_serial_numbers_order_table_col_email_label' => $serial_email_label, - 'wc_serial_numbers_order_table_col_limit_label' => 'Activation Limit', + 'wc_serial_numbers_order_table_col_key_label' => $serial_key_label, + 'wc_serial_numbers_order_table_col_email_label' => $serial_email_label, + 'wc_serial_numbers_order_table_col_limit_label' => 'Activation Limit', 'wc_serial_numbers_order_table_col_expires_label' => 'Expire Date', - 'wc_serial_numbers_order_table_col_product' => 'yes', - 'wc_serial_numbers_order_table_col_key' => 'yes', - 'wc_serial_numbers_order_table_col_email' => 'no', - 'wc_serial_numbers_order_table_col_limit' => $show_activation_limit ? 'yes' : 'no', - 'wc_serial_numbers_order_table_col_expires' => $show_validity ? 'yes' : 'no', - 'wc_serial_numbers_install_time' => get_option( 'woocommerceserialnumbers_install_time' ), - 'woocommerce-serial-numbers-pro_license_key' => array_key_exists( 'key', $license ) ? $license['key'] : '', - 'woocommerce-serial-numbers-pro_license_status' => array_key_exists( 'license', $license ) ? $license['license'] : '', - ]; + 'wc_serial_numbers_order_table_col_product' => 'yes', + 'wc_serial_numbers_order_table_col_key' => 'yes', + 'wc_serial_numbers_order_table_col_email' => 'no', + 'wc_serial_numbers_order_table_col_limit' => $show_activation_limit ? 'yes' : 'no', + 'wc_serial_numbers_order_table_col_expires' => $show_validity ? 'yes' : 'no', + 'wc_serial_numbers_install_time' => get_option( 'woocommerceserialnumbers_install_time' ), + 'woocommerce-serial-numbers-pro_license_key' => array_key_exists( 'key', $license ) ? $license['key'] : '', + 'woocommerce-serial-numbers-pro_license_status' => array_key_exists( 'license', $license ) ? $license['license'] : '', + ); foreach ( $options as $key => $option ) { add_option( $key, $option ); } @@ -312,15 +311,15 @@ protected function update_120() { * Get option from old settings. * * @param string $option_name Option name. - * @param string $default Default value. + * @param string $default_value Default value. * @param string $section Section name. * * @return string */ - protected function update_1_2_0_get_option( $option_name, $default, $section = 'serial_numbers_settings' ) { - $settings = get_option( $section, [] ); + protected function update_1_2_0_get_option( $option_name, $default_value, $section = 'serial_numbers_settings' ) { + $settings = get_option( $section, array() ); - return ! empty( $settings[ $option_name ] ) ? $settings[ $option_name ] : $default; + return ! empty( $settings[ $option_name ] ) ? $settings[ $option_name ] : $default_value; } /** @@ -331,9 +330,8 @@ protected function update_1_2_0_get_option( $option_name, $default, $section = ' */ protected function update_121() { global $wpdb; - $prefix = $wpdb->prefix; - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers CHANGE order_id order_id bigint(20) DEFAULT NULL" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers CHANGE vendor_id vendor_id bigint(20) DEFAULT NULL" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers CHANGE order_id order_id bigint(20) DEFAULT NULL" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers CHANGE vendor_id vendor_id bigint(20) DEFAULT NULL" ); } /** @@ -347,45 +345,42 @@ protected function update_146() { // Update key status default value to 'available'. // Change key status. // Drop expired column. - $statuses_map = [ + $statuses_map = array( 'refunded' => 'cancelled', 'expired' => 'expired', 'failed' => 'cancelled', 'inactive' => 'sold', - ]; - $prefix = $wpdb->prefix; + ); + foreach ( $statuses_map as $old_status => $new_status ) { - $wpdb->query( $wpdb->prepare( "UPDATE {$prefix}serial_numbers SET status = %s WHERE status = %s", $new_status, $old_status ) ); + $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}serial_numbers SET status = %s WHERE status = %s", $new_status, $old_status ) ); } - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers DROP expire_date" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers DROP expire_date" ); // Remove all inactive activations. - $wpdb->query( "DELETE FROM {$prefix}serial_numbers_activations WHERE active = 0" ); + $wpdb->query( "DELETE FROM {$wpdb->prefix}serial_numbers_activations WHERE active = 0" ); // Drop active column. - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers_activations DROP active" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers_activations DROP active" ); } /** * Update to version 1.5.6 * * @since 1.5.6 - * @return bool */ protected function update_156() { global $wpdb; - $prefix = $wpdb->prefix; // if order_item_id column not exist then add it. - if ( ! $wpdb->get_var( "SHOW COLUMNS FROM {$prefix}serial_numbers LIKE 'order_item_id'" ) ) { - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD order_item_id bigint(20) DEFAULT NULL AFTER order_id" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD KEY order_item_id (order_item_id)" ); + if ( ! $wpdb->get_var( "SHOW COLUMNS FROM {$wpdb->prefix}serial_numbers LIKE 'order_item_id'" ) ) { + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD order_item_id bigint(20) DEFAULT NULL AFTER order_id" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD KEY order_item_id (order_item_id)" ); } // if uuid column not exist then add it. - if ( ! $wpdb->get_var( "SHOW COLUMNS FROM {$prefix}serial_numbers LIKE 'uuid'" ) ) { - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD uuid varchar(50) DEFAULT NULL AFTER order_item_id" ); - $wpdb->query( "ALTER TABLE {$prefix}serial_numbers ADD UNIQUE KEY uuid (uuid)" ); - $wpdb->query( "UPDATE {$prefix}serial_numbers SET uuid = UUID()" ); + if ( ! $wpdb->get_var( "SHOW COLUMNS FROM {$wpdb->prefix}serial_numbers LIKE 'uuid'" ) ) { + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD uuid varchar(50) DEFAULT NULL AFTER order_item_id" ); + $wpdb->query( "ALTER TABLE {$wpdb->prefix}serial_numbers ADD UNIQUE KEY uuid (uuid)" ); + $wpdb->query( "UPDATE {$wpdb->prefix}serial_numbers SET uuid = UUID()" ); } - } } diff --git a/src/Models/Activation.php b/src/Models/Activation.php index 68672de6..b4328b24 100644 --- a/src/Models/Activation.php +++ b/src/Models/Activation.php @@ -295,5 +295,4 @@ protected function prepare_where_query( $clauses, $args = array() ) { return $clauses; } - } diff --git a/src/Models/Key.php b/src/Models/Key.php index acd50db7..77c09881 100644 --- a/src/Models/Key.php +++ b/src/Models/Key.php @@ -534,6 +534,7 @@ public function save() { return parent::save(); } + /* |-------------------------------------------------------------------------- | Query Methods @@ -760,7 +761,7 @@ public function get_expire_date() { $expiry_date = strtotime( "+{$validity} days", strtotime( $order_date ) ); - return date( 'Y-m-d H:i:s', $expiry_date ); + return wp_date( 'Y-m-d H:i:s', $expiry_date ); } /** @@ -831,6 +832,8 @@ public function get_activations( $args = array() ) { /** * Display the serial key. * + * @param bool $masked Whether to mask the key or not. + * * @since 1.5.0 * @return string */ diff --git a/src/Orders.php b/src/Orders.php index d451a4eb..f837320c 100644 --- a/src/Orders.php +++ b/src/Orders.php @@ -45,7 +45,7 @@ public function __construct() { public static function validate_checkout() { $cart_products = WC()->cart->get_cart_contents(); foreach ( $cart_products as $id => $cart_product ) { - /** @var \WC_Product $product */ + // @var \WC_Product $product Product object. $product = $cart_product['data']; $product_id = $product->get_id(); $quantity = $cart_product['quantity']; @@ -55,16 +55,16 @@ public static function validate_checkout() { $per_item_quantity = absint( apply_filters( 'wc_serial_numbers_per_product_delivery_qty', 1, $product_id ) ); $needed_quantity = $quantity * ( empty( $per_item_quantity ) ? 1 : absint( $per_item_quantity ) ); $source = apply_filters( 'wc_serial_numbers_product_serial_source', 'custom_source', $product_id, $needed_quantity ); - if ( 'custom_source' == $source ) { + if ( 'custom_source' === $source ) { $args = array( 'product_id' => $product_id, 'status' => 'available', - 'source' => $source, ); $total_found = Key::count( $args ); if ( $total_found < $needed_quantity ) { - $stock = floor( $total_found / $per_item_quantity ); - $message = sprintf( __( 'Sorry, there aren’t enough Serial Keys for %1$s. Please remove this item or lower the quantity. For now, we have %2$s Serial Keys for this product.', 'wc-serial-numbers' ), '{product_title}', '{stock_quantity}' ); + $stock = floor( $total_found / $per_item_quantity ); + // translators: %1$s: product title, %2$s: stock quantity. + $message = sprintf( esc_html__( 'Sorry, there aren’t enough Serial Keys for %1$s. Please remove this item or lower the quantity. For now, we have %2$s Serial Keys for this product.', 'wc-serial-numbers' ), '{product_title}', '{stock_quantity}' ); $notice = apply_filters( 'wc_serial_numbers_low_stock_message', $message ); $notice = str_replace( '{product_title}', $product->get_title(), $notice ); $notice = str_replace( '{stock_quantity}', $stock, $notice ); @@ -83,9 +83,9 @@ public static function validate_checkout() { /** * Automatically set the order's status to complete. * - * @param string $new_order_status - * @param int $order_id - * @param \WC_Order $order + * @param string $new_order_status The new order status. + * @param int $order_id The order ID. + * @param \WC_Order $order The order object. * * @since 1.4.6 * @return string $new_order_status diff --git a/src/Plugin.php b/src/Plugin.php index baf18093..c562220b 100644 --- a/src/Plugin.php +++ b/src/Plugin.php @@ -33,13 +33,7 @@ protected function __construct( $data ) { */ public function includes() { require_once __DIR__ . '/functions.php'; - require_once dirname( __FILE__ ) . '/Deprecated/Functions.php'; - if ( ! class_exists( '\WP_Async_Request', false ) ) { - require_once dirname( __DIR__ ) . '/lib/classes/wp-async-request.php'; - } - if ( ! class_exists( '\WP_Background_Process', false ) ) { - require_once dirname( __DIR__ ) . '/lib/classes/wp-background-process.php'; - } + require_once __DIR__ . '/Deprecated/Functions.php'; } /** diff --git a/src/Utilities/Utilities.php b/src/Utilities/Utilities.php index 7776477a..4dff1c35 100644 --- a/src/Utilities/Utilities.php +++ b/src/Utilities/Utilities.php @@ -2,7 +2,7 @@ namespace WooCommerceSerialNumbers\Utilities; -defined('ABSPATH') || exit; +defined( 'ABSPATH' ) || exit; /** * Class Utilities. diff --git a/src/functions.php b/src/functions.php index d3ffa602..9f807365 100644 --- a/src/functions.php +++ b/src/functions.php @@ -60,7 +60,7 @@ function wcsn_get_key_statuses() { * @return bool */ function wcsn_is_reusing_keys() { - return 'yes' == get_option( 'wc_serial_numbers_reuse_serial_number', 'no' ); + return 'yes' === get_option( 'wc_serial_numbers_reuse_serial_number', 'no' ); } /** @@ -70,12 +70,12 @@ function wcsn_is_reusing_keys() { * @return array */ function wcsn_get_revoke_statuses() { - $statues = [ + $statues = array( 'cancelled', 'refunded', 'failed', 'pending', - ]; + ); return apply_filters( 'wc_serial_numbers_revoke_statuses', $statues ); } @@ -294,7 +294,7 @@ function wcsn_delete_activation( $activation_id ) { * @return bool True if enabled, false otherwise. */ function wcsn_is_product_enabled( $product_id ) { - return 'yes' == get_post_meta( $product_id, '_is_serial_number', true ); + return 'yes' === get_post_meta( $product_id, '_is_serial_number', true ); } /** @@ -425,14 +425,9 @@ function wcsn_order_get_unfulfilled_items( $order_id ) { if ( $key->get_product_id() !== $line_item['product_id'] ) { continue; } -// todo uncomment this when we will support for order item id. -// if ( $key->get_variation_id() !== $line_item['variation_id'] ) { -// continue; -// } -// if ( $key->get_order_item_id() !== $line_item['order_item_id'] ) { -// continue; -// } - $qty --; + // todo uncomment this when we will support for order item id. + + --$qty; } if ( $qty > 0 ) { $items[] = array_merge( $line_item, array( 'quantity' => $qty ) ); @@ -476,8 +471,7 @@ function wcsn_order_update_keys( $order_id ) { $do_add = apply_filters( 'wc_serial_numbers_add_order_keys', true, $order_id, $line_items, $order_status ); - - if ( in_array( $order_status, [ 'processing', 'completed' ], true ) && ! wcsn_order_is_fullfilled( $order_id ) && $do_add ) { + if ( in_array( $order_status, array( 'processing', 'completed' ), true ) && ! wcsn_order_is_fullfilled( $order_id ) && $do_add ) { /** * Action hook to pre add order keys. @@ -495,11 +489,13 @@ function wcsn_order_update_keys( $order_id ) { continue; } - $delivered_qty = Key::count( array( - 'order_id' => $order_id, - 'product_id' => $item['product_id'], - 'status__not_in' => [ 'cancelled' ], - ) ); + $delivered_qty = Key::count( + array( + 'order_id' => $order_id, + 'product_id' => $item['product_id'], + 'status__not_in' => array( 'cancelled' ), + ) + ); if ( $item['refunded_qty'] >= $item['quantity'] ) { continue; } @@ -515,7 +511,7 @@ function wcsn_order_update_keys( $order_id ) { * @param int $order_id Order ID. * @param int $needed_count Needed count. */ - do_action( 'wc_serial_numbers_pre_add_order_item_eys', $item, $order_id, $needed_count ); + do_action( 'wc_serial_numbers_pre_add_order_item_keys', $item, $order_id, $needed_count ); // Deprecated. use wc_serial_numbers_pre_order_add_keys instead. Will be removed in 1.5.0. apply_filters( 'wc_serial_numbers_pre_order_item_connect_serial_numbers', $item['product_id'], $needed_count, $item['key_source'], $order_id ); @@ -527,7 +523,7 @@ function wcsn_order_update_keys( $order_id ) { 'status' => 'available', 'limit' => $needed_count, 'orderby' => 'id', - 'order' => 'ASC' + 'order' => 'ASC', ) ); if ( count( $keys ) < $needed_count ) { @@ -547,15 +543,17 @@ function wcsn_order_update_keys( $order_id ) { // Assign keys to order. foreach ( $keys as $key ) { - $key->set_data( array( - 'order_id' => $order_id, - 'order_item_id' => $item['order_item_id'], - 'order_date' => $order->get_date_created() ? $order->get_date_created()->format( 'Y-m-d H:i:s' ) : current_time( 'mysql' ), - 'customer_id' => $customer_id, - 'status' => 'sold', - ) ); + $key->set_data( + array( + 'order_id' => $order_id, + 'order_item_id' => $item['order_item_id'], + 'order_date' => $order->get_date_created() ? $order->get_date_created()->format( 'Y-m-d H:i:s' ) : current_time( 'mysql' ), + 'customer_id' => $customer_id, + 'status' => 'sold', + ) + ); if ( ! is_wp_error( $key->save() ) ) { - $added ++; + ++$added; } } @@ -599,10 +597,14 @@ function wcsn_order_update_keys( $order_id ) { if ( $is_expired && 'expired' !== $key->get_status() ) { $key->set_status( 'expired' ); $key->save(); - } elseif ( ! $is_expired && in_array( $order_status, [ + } elseif ( ! $is_expired && in_array( + $order_status, + array( 'processing', - 'complete' - ], true ) && 'sold' !== $key->get_status() ) { + 'complete', + ), + true + ) && 'sold' !== $key->get_status() ) { $key->set_status( 'sold' ); $key->save(); } elseif ( 'on-hold' === $order_status && ! $is_expired && 'pending' !== $key->get_status() ) { @@ -627,8 +629,8 @@ function wcsn_order_update_keys( $order_id ) { /** * Order remove keys. * - * @param int $order_id Order ID. - * @param array $line_items Order line items. + * @param int $order_id Order ID. + * @param int $product_id Product ID. * * @since 1.4.6 * @@ -664,7 +666,7 @@ function wcsn_order_remove_keys( $order_id, $product_id = null ) { foreach ( $keys as $key ) { $props = array( - 'status' => $is_reusing ? 'available' : 'cancelled' + 'status' => $is_reusing ? 'available' : 'cancelled', ); if ( ! $is_reusing ) { $props['order_id'] = 0; @@ -737,7 +739,7 @@ function wcsn_order_replace_key( $order_id, $product_id = null, $key_id = null ) foreach ( $keys as $key ) { $props = array( - 'status' => $is_reusing ? 'available' : 'cancelled' + 'status' => $is_reusing ? 'available' : 'cancelled', ); if ( ! $is_reusing ) { $props['order_id'] = 0; @@ -746,7 +748,7 @@ function wcsn_order_replace_key( $order_id, $product_id = null, $key_id = null ) } $key->set_data( $props ); if ( $key->save() ) { - $replaced ++; + ++$replaced; } } @@ -801,13 +803,13 @@ function wcsn_get_product_title( $product ) { */ function wcsn_get_products_query_args() { $args = array( - 'post_type' => [ 'product' ], + 'post_type' => array( 'product' ), 'tax_query' => array( // @codingStandardsIgnoreLine 'relation' => 'OR', array( 'taxonomy' => 'product_type', 'field' => 'slug', - 'terms' => [ 'simple' ], + 'terms' => array( 'simple' ), 'operator' => 'IN', ), ), @@ -819,13 +821,15 @@ function wcsn_get_products_query_args() { /** * Get enabled products. * + * @param array $args Query args. + * * @since 1.4.6 * @return array|int List of products or number of products. */ function wcsn_get_products( $args = array() ) { $args = wp_parse_args( $args, wcsn_get_products_query_args() ); if ( empty( $args['meta_query'] ) ) { - $args['meta_query'] = []; + $args['meta_query'] = array(); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query } $args['meta_query'][] = array( 'key' => '_is_serial_number', @@ -883,34 +887,41 @@ function wcsn_get_stocks_count( $stock_limit = null, $force = true ) { if ( $force || false === $counts ) { $counts = array(); - $post_ids = wcsn_get_products( array( - 'posts_per_page' => - 1, - 'fields' => 'ids', - 'meta_query' => array( // @codingStandardsIgnoreLine - 'relation' => 'AND', - array( - 'key' => '_serial_key_source', - 'value' => 'custom_source', - 'compare' => '=', - ) - ), - ) ); + $post_ids = wcsn_get_products( + array( + 'posts_per_page' => - 1, + 'fields' => 'ids', + 'meta_query' => array( // @codingStandardsIgnoreLine + 'relation' => 'AND', + array( + 'key' => '_serial_key_source', + 'value' => 'custom_source', + 'compare' => '=', + ), + ), + ) + ); foreach ( $post_ids as $post_id ) { - $counts[ $post_id ] = wcsn_get_keys( [ - 'product_id' => $post_id, - 'status' => 'available', - 'count' => true, - ] ); + $counts[ $post_id ] = wcsn_get_keys( + array( + 'product_id' => $post_id, + 'status' => 'available', + 'count' => true, + ) + ); } set_transient( $transient_key, $counts, 60 * 60 ); } if ( $stock_limit > 0 ) { // get the results where value is equal or less than max. - $counts = array_filter( $counts, function ( $value ) use ( $stock_limit ) { - return $value <= $stock_limit; - } ); + $counts = array_filter( + $counts, + function ( $value ) use ( $stock_limit ) { + return $value <= $stock_limit; + } + ); } return $counts; @@ -1029,8 +1040,8 @@ function wcsn_get_key_display_properties( $key, $context = 'order_details' ) { /** * Filter key properties. * - * @param array $props Key properties. - * @param Key $key Key object. + * @param array $props Key properties. + * @param Key $key Key object. * @param string $context Context. * * @since 1.4.9 @@ -1039,9 +1050,10 @@ function wcsn_get_key_display_properties( $key, $context = 'order_details' ) { usort( $properties, - function( $a, $b ) { + function ( $a, $b ) { $a_priority = isset( $a['priority'] ) ? $a['priority'] : 10; $b_priority = isset( $b['priority'] ) ? $b['priority'] : 10; + return $a_priority - $b_priority; } ); diff --git a/templates/email-stock-notification.php b/templates/email-stock-notification.php index 73eef989..47126236 100644 --- a/templates/email-stock-notification.php +++ b/templates/email-stock-notification.php @@ -4,7 +4,9 @@ * * @since 1.2.0 * @package WooCommerceSerialNumbers + * @var array $low_stock_products List of low stock products. */ + ?> @@ -20,11 +22,21 @@ } $product = wc_get_product( $product_id ); - echo sprintf( "
  • %s - Stock %s
  • ", get_edit_post_link( $product->get_id() ), $product->get_formatted_name(), $stock ); + printf( "
  • %s - Stock %s
  • ", esc_url( get_edit_post_link( $product->get_id() ) ), esc_html( $product->get_formatted_name() ), esc_html( $stock ) ); } ?>

    -

    Serial Numbers for WooCommerce', 'wc-serial-numbers' ), 'https://pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=serialnumberemail&utm_medium=email&utm_campaign=lowstocknotification' ); ?>

    +

    + Serial Numbers for WooCommerce', 'wc-serial-numbers' ), + 'https://pluginever.com/plugins/woocommerce-serial-numbers-pro/?utm_source=serialnumberemail&utm_medium=email&utm_campaign=lowstocknotification' + ) + ); + ?> +

    diff --git a/wc-serial-numbers.php b/wc-serial-numbers.php index bf5337af..8a84d7fa 100644 --- a/wc-serial-numbers.php +++ b/wc-serial-numbers.php @@ -3,7 +3,7 @@ * Plugin Name: WC Serial Numbers * Plugin URI: https://www.pluginever.com/plugins/wocommerce-serial-numbers-pro/ * Description: Sell and manage license keys/ serial numbers/ secret keys easily within your WooCommerce store. - * Version: 1.6.2 + * Version: 1.6.4 * Author: PluginEver * Author URI: http://pluginever.com * License: GPLv2+ @@ -11,7 +11,7 @@ * Domain Path: /languages * Tested up to: 6.3 * WC requires at least: 5.0 - * WC tested up to: 8.0 + * WC tested up to: 8.2 * * @package WooCommerceSerialNumbers * @@ -32,33 +32,35 @@ defined( 'ABSPATH' ) || exit(); // Autoload function. -spl_autoload_register( function ( $class ) { - $prefix = 'WooCommerceSerialNumbers\\'; - $len = strlen( $prefix ); +spl_autoload_register( + function ( $class_name ) { + $prefix = 'WooCommerceSerialNumbers\\'; + $len = strlen( $prefix ); - // Bail out if the class name doesn't start with our prefix. - if ( strncmp( $prefix, $class, $len ) !== 0 ) { - return; - } + // Bail out if the class name doesn't start with our prefix. + if ( strncmp( $prefix, $class_name, $len ) !== 0 ) { + return; + } - // Remove the prefix from the class name. - $relative_class = substr( $class, $len ); - // Replace the namespace separator with the directory separator. - $file = str_replace( '\\', DIRECTORY_SEPARATOR, $relative_class ) . '.php'; + // Remove the prefix from the class name. + $relative_class = substr( $class_name, $len ); + // Replace the namespace separator with the directory separator. + $file = str_replace( '\\', DIRECTORY_SEPARATOR, $relative_class ) . '.php'; - // Look for the file in the src and lib directories. - $file_paths = array( - __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $file, - __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . $file, - ); + // Look for the file in the src and lib directories. + $file_paths = array( + __DIR__ . DIRECTORY_SEPARATOR . 'src' . DIRECTORY_SEPARATOR . $file, + __DIR__ . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . $file, + ); - foreach ( $file_paths as $file_path ) { - if ( file_exists( $file_path ) ) { - require_once $file_path; - break; + foreach ( $file_paths as $file_path ) { + if ( file_exists( $file_path ) ) { + require_once $file_path; + break; + } } } -} ); +); /** @@ -82,7 +84,7 @@ function () { * @since 1.0.0 * @return Plugin */ -function WCSN() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid. +function WCSN() { // phpcs:ignore WordPress.NamingConventions.ValidFunctionName.FunctionNameInvalid $data = array( 'file' => __FILE__, 'settings_url' => admin_url( 'admin.php?page=wc-serial-numbers-settings' ),