diff --git a/changelog.txt b/changelog.txt index ff63e1e..2b1c0ea 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,39 @@ *** WooCommerce Subscriptions Changelog *** +2018.01.29 - version 2.2.17 +* Fix: Use line item meta values in a WC version compatible way. PR#2469 +* Fix: Only log cache manager messages if the logger has been loaded. PR#2468 +* Fix: Init `WC()->mailer()` to make sure our retry email classes are available and loaded. PR#2476 +* Fix: Update calls to 'woocommerce_payment_complete_order_status' to include order as 3rd argument. PR#2503 +* Fix: Prevent wp_kses from stripping off the allow_clear attribute of Select2 elements. PR#2354 +* Fix: Update `woocommerce_cart_totals_coupon_html` filter to include an extra arg introduced in WC 3.0. PR#2447 +* Fix: Ensure the Upcoming Revenue report correctly calculates revenue in periods beyond the next payment date. PR#2461 +* Fix: [WC3.2] Print the order downloads table in renewal order emails. PR#2522 +* Fix: [WC3.3] Replace uses of deprecated `woocommerce_params` with 'woocommerce_get_script_data'. PR#2509 +* Fix: [WC3.3] Get the active set of PayPal API credential depending on the gateway mode. PR#2514 +* Fix: [WC3.3] Display the filter by customer on the admin subscriptions table. PR#2521 +* Tweak: Add Subscriptions template overrides to system status. PR#2422 +* Tweak: Do not empty cart when adding additional units of a subscription product when mixed checkout is disabled. PR#2464 +* Tweak: Trigger a `do_action` when customers remove and readd line items to their subscription. PR#2458 +* Tweak: Untrash subscriptions when parent order is untrashed. PR#2472 +* Tweak: Skip the My Account Subscriptions table, linking directly to the subscription if customer only has one. PR#2474 +* Tweak: Change the subscription product length/expiration label from 'Expire after' to Subscription length. PR#2483 +* Tweak: Reword the Mixed Checkout setting description. PR#2490 +* Tweak: Cache user subscriptions to improve performance of limitation queries and user API functions. PR#2388 +* Tweak: Pass the `$number` parameter to callbacks hooked onto `woocommerce_subscription_periods` and `woocommerce_subscription_trial_periods`. PR#2520 + +2017.12.07 - version 2.2.16 +* Fix: Update PayPal doc links. PR#2414 +* Fix: [WC3.2] Make sure Subscriptions checks if the PayPal credentials have changed on correct hook. PR#2430 +* Fix: Only allow subscription line items to be removed from the My Account page when they should be allowed. PR#2440 +* Fix: Fix subscription ranges transient key when user has different language/locale than site default. PR#2286 +* Fix: Replace use of deprecated function with wc_get_cart_url(). PR#2442 +* Fix: Force payment method selection when switching when manual renewals are disabled. PR#2348 +* Tweak: Deprecate WC_Subscriptions::add_notice() and WC_Subscriptions::print_notices(). PR#2453 +* Tweak: Display "Free" for shipping that costs 0 only. PR#2437 +* Tweak: Format PayPal totals as strings when comparing. PR#2271 +* Tweak: Improve recurring fee support. PR#2462 + 2017.11.07 - version 2.2.15 * Fix: Don't include auto-draft subscriptions in the current subscriptions count in reports. PR#2414 * Fix: Reset cart item prorated amounts between calculations to avoid displaying double prorated prices. PR#2413 diff --git a/composer.lock b/composer.lock index 451c48c..51054e4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "f940d0fcab30dd0d30d8b2234dbbed1b", + "content-hash": "021c140a843bd5b969f18f6e06902332", "packages": [ { "name": "composer/installers", - "version": "v1.3.0", + "version": "v1.4.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045" + "reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/79ad876c7498c0bbfe7eed065b8651c93bfd6045", - "reference": "79ad876c7498c0bbfe7eed065b8651c93bfd6045", + "url": "https://api.github.com/repos/composer/installers/zipball/9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b", + "reference": "9ce17fb70e9a38dd8acff0636a29f5cf4d575c1b", "shasum": "" }, "require": { @@ -63,6 +63,7 @@ "Hurad", "ImageCMS", "Kanboard", + "Lan Management System", "MODX Evo", "Mautic", "Maya", @@ -86,6 +87,7 @@ "croogo", "dokuwiki", "drupal", + "eZ Platform", "elgg", "expressionengine", "fuelphp", @@ -102,6 +104,7 @@ "mediawiki", "modulework", "moodle", + "osclass", "phpbb", "piwik", "ppi", @@ -118,10 +121,1127 @@ "zend", "zikula" ], - "time": "2017-04-24T06:37:16+00:00" + "time": "2017-08-09T07:53:48+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/instantiator", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/doctrine/instantiator.git", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/instantiator/zipball/8e884e78f9f0eb1329e445619e04456e64d8051d", + "reference": "8e884e78f9f0eb1329e445619e04456e64d8051d", + "shasum": "" + }, + "require": { + "php": ">=5.3,<8.0-DEV" + }, + "require-dev": { + "athletic/athletic": "~0.1.8", + "ext-pdo": "*", + "ext-phar": "*", + "phpunit/phpunit": "~4.0", + "squizlabs/php_codesniffer": "~2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marco Pivetta", + "email": "ocramius@gmail.com", + "homepage": "http://ocramius.github.com/" + } + ], + "description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors", + "homepage": "https://github.com/doctrine/instantiator", + "keywords": [ + "constructor", + "instantiate" + ], + "time": "2015-06-14T21:17:01+00:00" + }, + { + "name": "phpdocumentor/reflection-common", + "version": "1.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionCommon.git", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionCommon/zipball/144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "reference": "144c307535e82c8fdcaacbcfc1d6d8eeb896687c", + "shasum": "" + }, + "require": { + "php": ">=5.5" + }, + "require-dev": { + "phpunit/phpunit": "^4.6" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jaap van Otterdijk", + "email": "opensource@ijaap.nl" + } + ], + "description": "Common reflection classes used by phpdocumentor to reflect the code structure", + "homepage": "http://www.phpdoc.org", + "keywords": [ + "FQSEN", + "phpDocumentor", + "phpdoc", + "reflection", + "static analysis" + ], + "time": "2015-12-27T11:43:31+00:00" + }, + { + "name": "phpdocumentor/reflection-docblock", + "version": "3.2.2", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", + "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/4aada1f93c72c35e22fb1383b47fee43b8f1d157", + "reference": "4aada1f93c72c35e22fb1383b47fee43b8f1d157", + "shasum": "" + }, + "require": { + "php": ">=5.5", + "phpdocumentor/reflection-common": "^1.0@dev", + "phpdocumentor/type-resolver": "^0.3.0", + "webmozart/assert": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^4.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", + "time": "2017-08-08T06:39:58+00:00" + }, + { + "name": "phpdocumentor/type-resolver", + "version": "0.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpDocumentor/TypeResolver.git", + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpDocumentor/TypeResolver/zipball/fb3933512008d8162b3cdf9e18dba9309b7c3773", + "reference": "fb3933512008d8162b3cdf9e18dba9309b7c3773", + "shasum": "" + }, + "require": { + "php": "^5.5 || ^7.0", + "phpdocumentor/reflection-common": "^1.0" + }, + "require-dev": { + "mockery/mockery": "^0.9.4", + "phpunit/phpunit": "^5.2||^4.8.24" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "phpDocumentor\\Reflection\\": [ + "src/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mike van Riel", + "email": "me@mikevanriel.com" + } + ], + "time": "2017-06-03T08:32:36+00:00" + }, + { + "name": "phpspec/prophecy", + "version": "v1.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpspec/prophecy.git", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpspec/prophecy/zipball/93d39f1f7f9326d746203c7c056f300f7f126073", + "reference": "93d39f1f7f9326d746203c7c056f300f7f126073", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": "^5.3|^7.0", + "phpdocumentor/reflection-docblock": "^2.0|^3.0.2", + "sebastian/comparator": "^1.1|^2.0", + "sebastian/recursion-context": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "phpspec/phpspec": "^2.5|^3.2", + "phpunit/phpunit": "^4.8 || ^5.6.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.6.x-dev" + } + }, + "autoload": { + "psr-0": { + "Prophecy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" + }, + { + "name": "Marcello Duarte", + "email": "marcello.duarte@gmail.com" + } + ], + "description": "Highly opinionated mocking framework for PHP 5.3+", + "homepage": "https://github.com/phpspec/prophecy", + "keywords": [ + "Double", + "Dummy", + "fake", + "mock", + "spy", + "stub" + ], + "time": "2017-03-02T20:05:34+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "2.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "reference": "eabf68b476ac7d0f73793aada060f1c1a9bf8979", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "phpunit/php-file-iterator": "~1.3", + "phpunit/php-text-template": "~1.2", + "phpunit/php-token-stream": "~1.3", + "sebastian/environment": "^1.3.2", + "sebastian/version": "~1.0" + }, + "require-dev": { + "ext-xdebug": ">=2.1.4", + "phpunit/phpunit": "~4" + }, + "suggest": { + "ext-dom": "*", + "ext-xdebug": ">=2.2.1", + "ext-xmlwriter": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "time": "2015-10-06T15:47:00+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "1.4.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "reference": "3cc8f69b3028d0f96a9078e6295d86e9bf019be5", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "time": "2016-10-03T07:40:28+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "reference": "31f8b717e51d9a2afca6c9f046f5d69fc27c8686", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "time": "2015-06-21T13:50:34+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "1.0.9", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "reference": "3dcf38ca72b158baf0bc245e9184d3fdffa9c46f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "time": "2017-02-26T11:10:40+00:00" + }, + { + "name": "phpunit/php-token-stream", + "version": "1.4.11", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-token-stream.git", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-token-stream/zipball/e03f8f67534427a787e21a385a67ec3ca6978ea7", + "reference": "e03f8f67534427a787e21a385a67ec3ca6978ea7", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Wrapper around PHP's tokenizer extension.", + "homepage": "https://github.com/sebastianbergmann/php-token-stream/", + "keywords": [ + "tokenizer" + ], + "time": "2017-02-27T10:12:30+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "4.8.36", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/46023de9a91eec7dfb06cc56cb4e260017298517", + "reference": "46023de9a91eec7dfb06cc56cb4e260017298517", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-pcre": "*", + "ext-reflection": "*", + "ext-spl": "*", + "php": ">=5.3.3", + "phpspec/prophecy": "^1.3.1", + "phpunit/php-code-coverage": "~2.1", + "phpunit/php-file-iterator": "~1.4", + "phpunit/php-text-template": "~1.2", + "phpunit/php-timer": "^1.0.6", + "phpunit/phpunit-mock-objects": "~2.3", + "sebastian/comparator": "~1.2.2", + "sebastian/diff": "~1.2", + "sebastian/environment": "~1.3", + "sebastian/exporter": "~1.2", + "sebastian/global-state": "~1.0", + "sebastian/version": "~1.0", + "symfony/yaml": "~2.1|~3.0" + }, + "suggest": { + "phpunit/php-invoker": "~1.1" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.8.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "time": "2017-06-21T08:07:12+00:00" + }, + { + "name": "phpunit/phpunit-mock-objects", + "version": "2.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit-mock-objects.git", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit-mock-objects/zipball/ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "reference": "ac8e7a3db35738d56ee9a76e78a4e03d97628983", + "shasum": "" + }, + "require": { + "doctrine/instantiator": "^1.0.2", + "php": ">=5.3.3", + "phpunit/php-text-template": "~1.2", + "sebastian/exporter": "~1.2" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "suggest": { + "ext-soap": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sb@sebastian-bergmann.de", + "role": "lead" + } + ], + "description": "Mock Object library for PHPUnit", + "homepage": "https://github.com/sebastianbergmann/phpunit-mock-objects/", + "keywords": [ + "mock", + "xunit" + ], + "time": "2015-10-02T06:51:40+00:00" + }, + { + "name": "sebastian/comparator", + "version": "1.2.4", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "reference": "2b7424b55f5047b47ac6e5ccb20b2aea4011d9be", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/diff": "~1.2", + "sebastian/exporter": "~1.2 || ~2.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "http://www.github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "time": "2017-01-29T09:50:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "reference": "7f066a26a962dbe58ddea9f72a4e82874a3975a4", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.4-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff" + ], + "time": "2017-05-22T07:24:03+00:00" + }, + { + "name": "sebastian/environment", + "version": "1.3.8", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "reference": "be2c607e43ce4c89ecd60e75c6a85c126e754aea", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8 || ^5.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "http://www.github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "time": "2016-08-18T05:49:44+00:00" + }, + { + "name": "sebastian/exporter", + "version": "1.2.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/42c4c2eec485ee3e159ec9884f95b431287edde4", + "reference": "42c4c2eec485ee3e159ec9884f95b431287edde4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3", + "sebastian/recursion-context": "~1.0" + }, + "require-dev": { + "ext-mbstring": "*", + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "http://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "time": "2016-06-17T09:04:28+00:00" + }, + { + "name": "sebastian/global-state", + "version": "1.1.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/bc37d50fea7d017d3d340f230811c9f1d7280af4", + "reference": "bc37d50fea7d017d3d340f230811c9f1d7280af4", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.2" + }, + "suggest": { + "ext-uopz": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "http://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "time": "2015-10-12T03:26:01+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "reference": "b19cc3298482a335a95f3016d2f8a6950f0fbcd7", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phpunit/phpunit": "~4.4" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "http://www.github.com/sebastianbergmann/recursion-context", + "time": "2016-10-03T07:41:43+00:00" + }, + { + "name": "sebastian/version", + "version": "1.0.6", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "reference": "58b3a85e7999757d6ad81c787a1fbf5ff6c628c6", + "shasum": "" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "time": "2015-06-21T13:59:46+00:00" + }, + { + "name": "symfony/yaml", + "version": "v3.3.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/ddc23324e6cfe066f3dd34a37ff494fa80b617ed", + "reference": "ddc23324e6cfe066f3dd34a37ff494fa80b617ed", + "shasum": "" + }, + "require": { + "php": ">=5.5.9" + }, + "require-dev": { + "symfony/console": "~2.8|~3.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "time": "2017-07-23T12:43:26+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.2.0", + "source": { + "type": "git", + "url": "https://github.com/webmozart/assert.git", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozart/assert/zipball/2db61e59ff05fe5126d152bd0655c9ea113e550f", + "reference": "2db61e59ff05fe5126d152bd0655c9ea113e550f", + "shasum": "" + }, + "require": { + "php": "^5.3.3 || ^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.6", + "sebastian/version": "^1.0.1" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "time": "2016-11-23T20:04:58+00:00" } ], - "packages-dev": [], "aliases": [], "minimum-stability": "stable", "stability-flags": [], diff --git a/includes/admin/class-wc-subscriptions-admin.php b/includes/admin/class-wc-subscriptions-admin.php index 58fede2..ac6cacb 100644 --- a/includes/admin/class-wc-subscriptions-admin.php +++ b/includes/admin/class-wc-subscriptions-admin.php @@ -231,7 +231,7 @@ class WC_Subscriptions_Admin { woocommerce_wp_select( array( 'id' => '_subscription_length', 'class' => 'wc_input_subscription_length select short', - 'label' => __( 'Subscription length', 'woocommerce-subscriptions' ), + 'label' => __( 'Expire after', 'woocommerce-subscriptions' ), 'options' => wcs_get_subscription_ranges( $chosen_period ), 'desc_tip' => true, 'description' => __( 'Automatically expire the subscription after this length of time. This length is in addition to any free trial or amount of time provided before a synchronised first renewal date.', 'woocommerce-subscriptions' ), @@ -354,7 +354,7 @@ class WC_Subscriptions_Admin { - + @@ -1142,11 +1142,11 @@ class WC_Subscriptions_Admin { array( 'name' => __( 'Mixed Checkout', 'woocommerce-subscriptions' ), - 'desc' => __( 'Allow subscriptions and products to be purchased simultaneously.', 'woocommerce-subscriptions' ), + 'desc' => __( 'Allow multiple subscriptions and products to be purchased simultaneously.', 'woocommerce-subscriptions' ), 'id' => self::$option_prefix . '_multiple_purchase', 'default' => 'no', 'type' => 'checkbox', - 'desc_tip' => __( 'Allow subscriptions and products to be purchased in a single transaction.', 'woocommerce-subscriptions' ), + 'desc_tip' => __( 'Allow a subscription product to be purchased with other products and subscriptions in the same transaction.', 'woocommerce-subscriptions' ), ), array( @@ -1419,6 +1419,14 @@ class WC_Subscriptions_Admin { 'success' => ( WC_Subscriptions::is_duplicate_site() ) ? 0 : 1, ); + $theme_overrides = self::get_theme_overrides(); + $debug_data['wcs_theme_overrides'] = array( + 'name' => _x( 'Subscriptions Template Theme Overrides', 'label for the system status page', 'woocommerce-subscriptions' ), + 'mark' => '', + 'mark_icon' => $theme_overrides['has_outdated_templates'] ? 'warning' : 'yes', + 'data' => $theme_overrides, + ); + $debug_data = apply_filters( 'wcs_system_status', $debug_data ); include( plugin_dir_path( WC_Subscriptions::$plugin_file ) . 'templates/admin/status.php' ); @@ -1665,6 +1673,57 @@ class WC_Subscriptions_Admin { return apply_filters( 'wcs_admin_is_subscription_product_save_request', $is_subscription_product_save_request, $post_id, $product_types ); } + /** + * Determine which of our files have been overridden by the theme. + * + * @author Jeremy Pry + * @return array Theme override data. + */ + private static function get_theme_overrides() { + $wcs_template_dir = dirname( WC_Subscriptions::$plugin_file ) . '/templates/'; + $wc_template_path = trailingslashit( wc()->template_path() ); + $theme_root = trailingslashit( get_theme_root() ); + $overridden = array(); + $outdated = false; + $templates = WC_Admin_Status::scan_template_files( $wcs_template_dir ); + + foreach ( $templates as $file ) { + $theme_file = $is_outdated = false; + $locations = array( + get_stylesheet_directory() . "/{$file}", + get_stylesheet_directory() . "/{$wc_template_path}{$file}", + get_template_directory() . "/{$file}", + get_template_directory() . "/{$wc_template_path}{$file}", + ); + + foreach ( $locations as $location ) { + if ( is_readable( $location ) ) { + $theme_file = $location; + break; + } + } + + if ( ! empty( $theme_file ) ) { + $core_version = WC_Admin_Status::get_file_version( $wcs_template_dir . $file ); + $theme_version = WC_Admin_Status::get_file_version( $theme_file ); + if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) { + $outdated = $is_outdated = true; + } + $overridden[] = array( + 'file' => str_replace( $theme_root, '', $theme_file ), + 'version' => $theme_version, + 'core_version' => $core_version, + 'is_outdated' => $is_outdated, + ); + } + } + + return array( + 'has_outdated_templates' => $outdated, + 'overridden_templates' => $overridden, + ); + } + /** * Outputs the contents of the "Renewal Orders" meta box. * diff --git a/includes/admin/class-wcs-admin-post-types.php b/includes/admin/class-wcs-admin-post-types.php index d410692..14347e7 100644 --- a/includes/admin/class-wcs-admin-post-types.php +++ b/includes/admin/class-wcs-admin-post-types.php @@ -51,6 +51,7 @@ class WCS_Admin_Post_Types { add_action( 'restrict_manage_posts', array( $this, 'restrict_by_product' ) ); add_action( 'restrict_manage_posts', array( $this, 'restrict_by_payment_method' ) ); + add_action( 'restrict_manage_posts', array( $this, 'restrict_by_customer' ) ); add_action( 'list_table_primary_column', array( $this, 'list_table_primary_column' ), 10, 2 ); add_filter( 'post_row_actions', array( $this, 'shop_subscription_row_actions' ), 10, 2 ); @@ -1092,6 +1093,41 @@ class WCS_Admin_Post_Types { return $item_html; } + + /** + * Renders the dropdown for the customer filter. + * + * @since 2.2.17 + */ + public static function restrict_by_customer() { + global $typenow; + + // Prior to WC 3.3 this was handled by WC core so exit early if an earlier version of WC is active. + if ( 'shop_subscription' !== $typenow || WC_Subscriptions::is_woocommerce_pre( '3.3' ) ) { + return; + } + + $user_string = ''; + $user_id = ''; + + if ( ! empty( $_GET['_customer_user'] ) ) { + $user_id = absint( $_GET['_customer_user'] ); + $user = get_user_by( 'id', $user_id ); + + $user_string = sprintf( + /* translators: 1: user display name 2: user ID 3: user email */ + esc_html__( '%1$s (#%2$s – %3$s)', 'woocommerce-subscriptions' ), + $user->display_name, + absint( $user->ID ), + $user->user_email + ); + } + ?> + + mailer(); + $retries = WCS_Retry_Manager::store()->get_retries_for_order( $post->ID ); include_once( 'views/html-retries-table.php' ); diff --git a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php index c1dfab0..89524f0 100644 --- a/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php +++ b/includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php @@ -30,11 +30,6 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { foreach ( $this->order_ids_recurring_totals as $r ) { - if ( strtotime( $r->scheduled_date ) >= $this->start_date ) { - $total_renewal_revenue += $r->recurring_total; - $total_renewal_count += $r->total_renewals; - } - $subscription_ids = explode( ',', $r->subscription_ids ); $billing_intervals = explode( ',', $r->billing_intervals ); $billing_periods = explode( ',', $r->billing_periods ); @@ -57,7 +52,7 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { $next_payment_timestamp = wcs_add_time( $billing_intervals[ $key ], $billing_periods[ $key ], $next_payment_timestamp ); // If there are more renewals add them to the existing object or create a new one - if ( $next_payment_timestamp < $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ) { + if ( $next_payment_timestamp <= $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ) { $update_key = date( 'Y-m-d', $next_payment_timestamp ); if ( $next_payment_timestamp >= $this->start_date ) { @@ -70,11 +65,18 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { } $this->order_ids_recurring_totals[ $update_key ]->total_renewals += 1; $this->order_ids_recurring_totals[ $update_key ]->recurring_total += $subscription_totals[ $key ]; - $total_renewal_revenue += $subscription_totals[ $key ];; - $total_renewal_count += 1; } } - } while ( $next_payment_timestamp < $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ); + } while ( $next_payment_timestamp <= $this->end_date && isset( $scheduled_ends[ $key ] ) && ( 0 == $scheduled_ends[ $key ] || $next_payment_timestamp < strtotime( $scheduled_ends[ $key ] ) ) ); + } + } + + // Sum up the total revenue and total renewal count separately to avoid adding up multiple times. + foreach ( $this->order_ids_recurring_totals as $r ) { + if ( strtotime( $r->scheduled_date ) >= $this->start_date && strtotime( $r->scheduled_date ) <= $this->end_date ) { + + $total_renewal_revenue += $r->recurring_total ; + $total_renewal_count += $r->total_renewals; } } @@ -140,13 +142,14 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { AND p.post_status = 'wc-active' AND mo.meta_key = '_order_total' AND ms.meta_key = '_schedule_next_payment' - AND ms.meta_value BETWEEN '%s' AND '%s' + AND ( ( ms.meta_value < '%s' AND me.meta_value = 0 ) OR ( me.meta_value > '%s' AND ms.meta_value < '%s' ) ) AND mi.meta_key = '_billing_interval' AND mp.meta_key = '_billing_period' AND me.meta_key = '_schedule_end ' GROUP BY {$this->group_by_query} ORDER BY ms.meta_value ASC", '%Y-%m-%d', + date( 'Y-m-d', strtotime( '+1 DAY', $this->end_date ) ), date( 'Y-m-d', $this->start_date ), date( 'Y-m-d', strtotime( '+1 DAY', $this->end_date ) ) ); @@ -364,7 +367,7 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { } // 3 months max for day view - if ( $interval > 3 ) { + if ( $interval >= 3 ) { $this->chart_groupby = 'month'; } else { $this->chart_groupby = 'day'; @@ -400,7 +403,7 @@ class WC_Report_Upcoming_Recurring_Revenue extends WC_Admin_Report { $this->barwidth = 60 * 60 * 24 * 1000; break; case 'month' : - $this->group_by_query = 'YEAR(ms.meta_value), MONTH(ms.meta_value)'; + $this->group_by_query = 'YEAR(ms.meta_value), MONTH(ms.meta_value), DAY(ms.meta_value)'; $this->chart_interval = 0; $min_date = $this->start_date; while ( ( $min_date = wcs_add_months( $min_date, '1' ) ) <= $this->end_date ) { diff --git a/includes/class-wc-subscription.php b/includes/class-wc-subscription.php index bbef503..ff4609a 100644 --- a/includes/class-wc-subscription.php +++ b/includes/class-wc-subscription.php @@ -628,7 +628,7 @@ class WC_Subscription extends WC_Order { 'wc-completed', ); - $custom_status = apply_filters( 'woocommerce_payment_complete_order_status', 'completed', $this->get_id() ); + $custom_status = apply_filters( 'woocommerce_payment_complete_order_status', 'completed', $this->get_id(), $this ); if ( '' !== $custom_status && ! in_array( $custom_status, $paid_statuses ) && ! in_array( 'wc-' . $custom_status, $paid_statuses ) ) { $paid_statuses[] = $custom_status; diff --git a/includes/class-wc-subscriptions-cart.php b/includes/class-wc-subscriptions-cart.php index cb26cb0..d2b049f 100644 --- a/includes/class-wc-subscriptions-cart.php +++ b/includes/class-wc-subscriptions-cart.php @@ -122,6 +122,8 @@ class WC_Subscriptions_Cart { add_filter( 'woocommerce_shipping_free_shipping_is_available', __CLASS__ . '::maybe_recalculate_shipping_method_availability', 10, 2 ); add_filter( 'woocommerce_add_to_cart_handler', __CLASS__ . '::add_to_cart_handler', 10, 2 ); + + add_action( 'woocommerce_cart_calculate_fees', __CLASS__ . '::apply_recurring_fees', 1000, 1 ); } /** @@ -1261,6 +1263,29 @@ class WC_Subscriptions_Cart { return $is_available; } + /** + * Allow third-parties to apply fees which apply to the cart to recurring carts. + * + * @param WC_Cart + * @since 2.2.16 + */ + public static function apply_recurring_fees( $cart ) { + + if ( ! empty( $cart->recurring_cart_key ) ) { + + foreach ( WC()->cart->get_fees() as $fee ) { + + if ( apply_filters( 'woocommerce_subscriptions_is_recurring_fee', false, $fee, $cart ) ) { + if ( is_callable( array( $cart, 'fees_api' ) ) ) { // WC 3.2 + + $cart->fees_api()->add_fee( $fee ); + } else { + $cart->add_fee( $fee->name, $fee->amount, $fee->taxable, $fee->tax_class ); + } + } + } + } + } + /* Deprecated */ /** diff --git a/includes/class-wc-subscriptions-change-payment-gateway.php b/includes/class-wc-subscriptions-change-payment-gateway.php index 41c2e10..f93e8fd 100644 --- a/includes/class-wc-subscriptions-change-payment-gateway.php +++ b/includes/class-wc-subscriptions-change-payment-gateway.php @@ -194,13 +194,13 @@ class WC_Subscriptions_Change_Payment_Gateway { if ( ! empty( self::$woocommerce_errors ) ) { foreach ( self::$woocommerce_errors as $error ) { - WC_Subscriptions::add_notice( $error, 'error' ); + wc_add_notice( $error, 'error' ); } } if ( ! empty( self::$woocommerce_messages ) ) { foreach ( self::$woocommerce_messages as $message ) { - WC_Subscriptions::add_notice( $message, 'success' ); + wc_add_notice( $message, 'success' ); } } @@ -208,19 +208,19 @@ class WC_Subscriptions_Change_Payment_Gateway { if ( wp_verify_nonce( $_GET['_wpnonce'] ) === false ) { - WC_Subscriptions::add_notice( __( 'There was an error with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'There was an error with your request. Please try again.', 'woocommerce-subscriptions' ), 'error' ); } elseif ( empty( $subscription ) ) { - WC_Subscriptions::add_notice( __( 'Invalid Subscription.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'Invalid Subscription.', 'woocommerce-subscriptions' ), 'error' ); } elseif ( ! current_user_can( 'edit_shop_subscription_payment_method', $subscription->get_id() ) ) { - WC_Subscriptions::add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' ); } elseif ( ! $subscription->can_be_updated_to( 'new-payment-method' ) ) { - WC_Subscriptions::add_notice( __( 'The payment method can not be changed for that subscription.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'The payment method can not be changed for that subscription.', 'woocommerce-subscriptions' ), 'error' ); } else { @@ -232,8 +232,8 @@ class WC_Subscriptions_Change_Payment_Gateway { } // translators: placeholder is either empty or "Next payment is due..." - WC_Subscriptions::add_notice( sprintf( __( 'Choose a new payment method.%s', 'woocommerce-subscriptions' ), $next_payment_string ), 'notice' ); - WC_Subscriptions::print_notices(); + wc_add_notice( sprintf( __( 'Choose a new payment method.%s', 'woocommerce-subscriptions' ), $next_payment_string ), 'notice' ); + wc_print_notices(); if ( $subscription->get_order_key() == $_GET['key'] ) { @@ -261,14 +261,14 @@ class WC_Subscriptions_Change_Payment_Gateway { } else { - WC_Subscriptions::add_notice( __( 'Invalid order.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'Invalid order.', 'woocommerce-subscriptions' ), 'error' ); } } } if ( false === $valid_request ) { - WC_Subscriptions::print_notices(); + wc_print_notices(); } } @@ -363,7 +363,7 @@ class WC_Subscriptions_Change_Payment_Gateway { // Redirect to success/confirmation/payment page if ( 'success' == $result['result'] ) { - WC_Subscriptions::add_notice( __( 'Payment method updated.', 'woocommerce-subscriptions' ), 'success' ); + wc_add_notice( __( 'Payment method updated.', 'woocommerce-subscriptions' ), 'success' ); wp_redirect( $result['redirect'] ); exit; } diff --git a/includes/class-wc-subscriptions-checkout.php b/includes/class-wc-subscriptions-checkout.php index 960b916..224d00c 100644 --- a/includes/class-wc-subscriptions-checkout.php +++ b/includes/class-wc-subscriptions-checkout.php @@ -32,9 +32,8 @@ class WC_Subscriptions_Checkout { // Restore the settings after switching them for the checkout form add_action( 'woocommerce_after_checkout_form', __CLASS__ . '::restore_checkout_registration_settings', 100 ); - // Make sure guest checkout is not enabled in option param passed to WC JS - add_filter( 'woocommerce_params', __CLASS__ . '::filter_woocommerce_script_paramaters', 10, 1 ); - add_filter( 'wc_checkout_params', __CLASS__ . '::filter_woocommerce_script_paramaters', 10, 1 ); + // Some callbacks need to hooked after WC has loaded. + add_action( 'woocommerce_loaded', array( __CLASS__, 'attach_dependant_hooks' ) ); // Force registration during checkout process add_action( 'woocommerce_before_checkout_process', __CLASS__ . '::force_registration_during_checkout', 10 ); @@ -43,6 +42,19 @@ class WC_Subscriptions_Checkout { add_action( 'woocommerce_checkout_create_order_line_item', __CLASS__ . '::remove_backorder_meta_from_subscription_line_item', 10, 4 ); } + /** + * @since 2.2.17 + */ + public static function attach_dependant_hooks() { + // Make sure guest checkout is not enabled in option param passed to WC JS + if ( WC_Subscriptions::is_woocommerce_pre( '3.3' ) ) { + add_filter( 'woocommerce_params', __CLASS__ . '::filter_woocommerce_script_paramaters', 10, 1 ); + add_filter( 'wc_checkout_params', __CLASS__ . '::filter_woocommerce_script_paramaters', 10, 1 ); + } else { + add_filter( 'woocommerce_get_script_data', __CLASS__ . '::filter_woocommerce_script_paramaters', 10, 2 ); + } + } + /** * Create subscriptions purchased on checkout. * @@ -445,7 +457,11 @@ class WC_Subscriptions_Checkout { * * @since 1.1 */ - public static function filter_woocommerce_script_paramaters( $woocommerce_params ) { + public static function filter_woocommerce_script_paramaters( $woocommerce_params, $handle = '' ) { + // WC 3.3+ deprecates handle-specific filters in favor of 'woocommerce_get_script_data'. + if ( 'woocommerce_get_script_data' === current_filter() && ! in_array( $handle, array( 'woocommerce', 'wc-checkout' ) ) ) { + return $woocommerce_params; + } if ( WC_Subscriptions_Cart::cart_contains_subscription() && ! is_user_logged_in() && isset( $woocommerce_params['option_guest_checkout'] ) && 'yes' == $woocommerce_params['option_guest_checkout'] ) { $woocommerce_params['option_guest_checkout'] = 'no'; diff --git a/includes/class-wc-subscriptions-email.php b/includes/class-wc-subscriptions-email.php index f759568..c00cb09 100644 --- a/includes/class-wc-subscriptions-email.php +++ b/includes/class-wc-subscriptions-email.php @@ -26,6 +26,7 @@ class WC_Subscriptions_Email { add_filter( 'woocommerce_resend_order_emails_available', __CLASS__ . '::renewal_order_emails_available', -1 ); // run before other plugins so we don't remove their emails + add_action( 'woocommerce_subscriptions_email_order_details', __CLASS__ . '::order_download_details', 10, 4 ); add_action( 'woocommerce_subscriptions_email_order_details', __CLASS__ . '::order_details', 10, 4 ); } @@ -343,6 +344,21 @@ class WC_Subscriptions_Email { } } + /** + * With WooCommerce 3.2+ active display the downloads table. + * + * @param WC_Order $order + * @param bool $sent_to_admin Whether the email is sent to admin - defaults to false + * @param bool $plain_text Whether the email should use plain text templates - defaults to false + * @param WC_Email $email + * @since 2.2.17 + */ + public static function order_download_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) { + if ( is_callable( array( 'WC_Emails', 'order_downloads' ) ) ) { + WC_Emails::instance()->order_downloads( $order, $sent_to_admin, $plain_text, $email ); + } + } + /** * Init the mailer and call the notifications for the current filter. * diff --git a/includes/class-wc-subscriptions-manager.php b/includes/class-wc-subscriptions-manager.php index 682f443..1176b2c 100644 --- a/includes/class-wc-subscriptions-manager.php +++ b/includes/class-wc-subscriptions-manager.php @@ -50,6 +50,9 @@ class WC_Subscriptions_Manager { // Order is trashed, trash subscription add_action( 'wp_trash_post', __CLASS__ . '::maybe_trash_subscription', 10 ); + // Order is restored (untrashed), restore subscription + add_action( 'untrashed_post', __CLASS__ . '::maybe_untrash_subscription', 10 ); + // When order is deleted, delete the subscription. add_action( 'before_delete_post', array( __CLASS__, 'maybe_delete_subscription' ) ); @@ -792,6 +795,19 @@ class WC_Subscriptions_Manager { } } + /** + * Untrash all subscriptions attached to an order when it's restored. + * @param int $post_id The post ID of the WC Order being restored + * @since 2.2.17 + */ + public static function maybe_untrash_subscription( $post_id ) { + if ( 'shop_order' == get_post_type( $post_id ) ) { + foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'parent', 'subscription_status' => array( 'trash' ) ) ) as $subscription ) { + wp_untrash_post( $subscription->get_id() ); + } + } + } + /** * Delete related subscriptions when an order is deleted. * diff --git a/includes/class-wc-subscriptions-order.php b/includes/class-wc-subscriptions-order.php index f7e3fac..92c2120 100644 --- a/includes/class-wc-subscriptions-order.php +++ b/includes/class-wc-subscriptions-order.php @@ -477,7 +477,7 @@ class WC_Subscriptions_Order { $subscriptions = wcs_get_subscriptions_for_order( $order_id, array( 'order_type' => 'parent' ) ); $was_activated = false; $order = wc_get_order( $order_id ); - $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id ), 'processing', 'completed' ) ) && in_array( $old_order_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); + $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ) && in_array( $old_order_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); foreach ( $subscriptions as $subscription ) { diff --git a/includes/class-wc-subscriptions-renewal-order.php b/includes/class-wc-subscriptions-renewal-order.php index 566a109..b1afe47 100644 --- a/includes/class-wc-subscriptions-renewal-order.php +++ b/includes/class-wc-subscriptions-renewal-order.php @@ -80,7 +80,7 @@ class WC_Subscriptions_Renewal_Order { $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id ); $was_activated = false; $order = wc_get_order( $order_id ); - $order_completed = in_array( $orders_new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id ), 'processing', 'completed' ) ); + $order_completed = in_array( $orders_new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ); $order_needed_payment = in_array( $orders_old_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); if ( $order_completed && $order_needed_payment ) { diff --git a/includes/class-wc-subscriptions-switcher.php b/includes/class-wc-subscriptions-switcher.php index 77e6c61..952429d 100644 --- a/includes/class-wc-subscriptions-switcher.php +++ b/includes/class-wc-subscriptions-switcher.php @@ -176,7 +176,7 @@ class WC_Subscriptions_Switcher { $switch_message = __( 'Choose a new subscription.', 'woocommerce-subscriptions' ); } - WC_Subscriptions::add_notice( $switch_message, 'notice' ); + wc_add_notice( $switch_message, 'notice' ); } } elseif ( ( is_cart() || is_checkout() ) && ! is_order_received_page() && false !== ( $switch_items = self::cart_contains_switches() ) ) { @@ -195,9 +195,9 @@ class WC_Subscriptions_Switcher { } if ( $removed_item_count > 0 ) { - WC_Subscriptions::add_notice( _n( 'Your cart contained an invalid subscription switch request. It has been removed.', 'Your cart contained invalid subscription switch requests. They have been removed.', $removed_item_count, 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( _n( 'Your cart contained an invalid subscription switch request. It has been removed.', 'Your cart contained invalid subscription switch requests. They have been removed.', $removed_item_count, 'woocommerce-subscriptions' ), 'error' ); - wp_redirect( WC()->cart->get_cart_url() ); + wp_redirect( wc_get_cart_url() ); exit(); } } elseif ( is_product() && $product = wc_get_product( $post ) ) { // Automatically initiate the switch process for limited variable subscriptions @@ -249,7 +249,7 @@ class WC_Subscriptions_Switcher { $subscribed_notice = sprintf( __( '%1$s Complete payment on %2$sOrder %3$s%4$s to be able to change your subscription.', 'woocommerce-subscriptions' ), $subscribed_notice, sprintf( '', $last_order->get_checkout_payment_url() ), $last_order->get_order_number(), '' ); } - WC_Subscriptions::add_notice( $subscribed_notice, 'notice' ); + wc_add_notice( $subscribed_notice, 'notice' ); break; } else { @@ -1017,7 +1017,7 @@ class WC_Subscriptions_Switcher { $subscription_switches[ $cart_item_key ] = $cart_item['subscription_switch']; } else { WC()->cart->remove_cart_item( $cart_item_key ); - WC_Subscriptions::add_notice( __( 'Your cart contained an invalid subscription switch request. It has been removed.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'Your cart contained an invalid subscription switch request. It has been removed.', 'woocommerce-subscriptions' ), 'error' ); } } } @@ -1164,7 +1164,7 @@ class WC_Subscriptions_Switcher { // Requesting a switch for someone elses subscription if ( ! current_user_can( 'switch_shop_subscription', $subscription->get_id() ) ) { - WC_Subscriptions::add_notice( __( 'You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'You can not switch this subscription. It appears you do not own the subscription.', 'woocommerce-subscriptions' ), 'error' ); WC()->cart->empty_cart( true ); wp_redirect( get_permalink( $subscription['product_id'] ) ); exit(); @@ -1205,7 +1205,7 @@ class WC_Subscriptions_Switcher { } catch ( Exception $e ) { - WC_Subscriptions::add_notice( __( 'There was an error locating the switch details.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'There was an error locating the switch details.', 'woocommerce-subscriptions' ), 'error' ); WC()->cart->empty_cart( true ); wp_redirect( get_permalink( wc_get_page_id( 'cart' ) ) ); exit(); @@ -1682,7 +1682,7 @@ class WC_Subscriptions_Switcher { return; } - $order_completed = in_array( $order_new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id ), 'processing', 'completed' ) ); + $order_completed = in_array( $order_new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ); if ( $order_completed ) { try { @@ -2047,7 +2047,16 @@ class WC_Subscriptions_Switcher { // Check that the existing subscriptions are for $0 recurring $old_recurring_total = $subscription->get_total(); - if ( 0 == $old_recurring_total && $new_recurring_total > 0 && true === $has_future_payments && $subscription->is_manual() ) { + // Check for $0 / period to a non-zero $ / period and manual subscription + $switch_from_zero_manual_subscription = ( 0 == $old_recurring_total && $subscription->is_manual() ); + + // Check for manual renewals accepted, in case of automatic subscription switch with no proration + $accept_manual_renewals = ( 'yes' == get_option( WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no' ) ); + + // Check if old subscription is automatic + $old_subscription_automatic = ! $subscription->is_manual(); + + if ( ( $switch_from_zero_manual_subscription || ! $accept_manual_renewals || ( $accept_manual_renewals && $old_subscription_automatic ) ) && $new_recurring_total > 0 && true === $has_future_payments ) { WC()->cart->cart_contents[ $cart_item_key ]['subscription_switch']['force_payment'] = true; } } @@ -2234,7 +2243,6 @@ class WC_Subscriptions_Switcher { * @param WC_Order $order the switch order * @param WC_Subscription $subscription the subscription being switched * @since 2.1.2 - * TODO Remove this function in 2.1.n - compatibility code for 2.1 - 2.1.2 */ protected static function switch_line_items_pre_2_1_2( $switches, $order, $subscription ) { @@ -2288,7 +2296,6 @@ class WC_Subscriptions_Switcher { * @param WC_Subscription $subscription the subscription being switched * @param array $shipping_methods an array of shipping line items and meta * @since 2.1.2 - * TODO Remove this function in 2.1.n - compatibility code for 2.1 - 2.1.2 */ protected static function switch_shipping_line_items_pre_2_1_2( $subscription, $shipping_methods ) { // Archive the old subscription shipping methods diff --git a/includes/class-wcs-cached-data-manager.php b/includes/class-wcs-cached-data-manager.php index f76eec1..70d64ce 100644 --- a/includes/class-wcs-cached-data-manager.php +++ b/includes/class-wcs-cached-data-manager.php @@ -19,12 +19,16 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { add_action( 'trashed_post', array( $this, 'purge_delete' ), 9999 ); // trashed posts aren't included in 'any' queries add_action( 'untrashed_post', array( $this, 'purge_delete' ), 9999 ); // however untrashed posts are add_action( 'before_delete_post', array( $this, 'purge_delete' ), 9999 ); // if forced delete is enabled + add_action( 'update_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); add_action( 'updated_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys add_action( 'deleted_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys add_action( 'added_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys add_action( 'admin_init', array( $this, 'initialize_cron_check_size' ) ); // setup cron task to truncate big logs. add_filter( 'cron_schedules', array( $this, 'add_weekly_cron_schedule' ) ); // create a weekly cron schedule + + // Add actions to handle cache purge for users. + add_action( 'save_post', array( $this, 'purge_delete' ), 9999, 2 ); } /** @@ -40,7 +44,7 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { * @param string $message Message to log */ public function log( $message ) { - if ( defined( 'WCS_DEBUG' ) && WCS_DEBUG ) { + if ( is_object( $this->logger ) && defined( 'WCS_DEBUG' ) && WCS_DEBUG ) { $this->logger->add( 'wcs-cache', $message ); } } @@ -71,20 +75,29 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { /** * Clearing cache when a post is deleted * - * @param $post_id integer the ID of a post + * @param int $post_id The ID of a post + * @param WP_Post $post The post object (on certain hooks). */ - public function purge_delete( $post_id ) { - if ( 'shop_order' === get_post_type( $post_id ) ) { + public function purge_delete( $post_id, $post = null ) { + $post_type = get_post_type( $post_id ); + if ( 'shop_order' === $post_type ) { foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $subscription ) { $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $subscription->get_id() ); $this->clear_related_order_cache( $subscription ); } } - // Purge wcs_do_subscriptions_exist cache, but only on the before_delete_post hook. - if ( 'shop_subscription' === get_post_type( $post_id ) && doing_action( 'before_delete_post' ) ) { - $this->log( "Subscription {$post_id} deleted. Purging subscription cache." ); - $this->delete_cached( 'wcs_do_subscriptions_exist' ); + if ( 'shop_subscription' === $post_type ) { + // Purge wcs_do_subscriptions_exist cache, but only on the before_delete_post hook. + if ( doing_action( 'before_delete_post' ) ) { + $this->log( "Subscription {$post_id} deleted. Purging subscription cache." ); + $this->delete_cached( 'wcs_do_subscriptions_exist' ); + } + + // Purge cache for a specific user on the save_post hook. + if ( doing_action( 'save_post' ) ) { + $this->purge_subscription_user_cache( $post_id ); + } } } @@ -97,13 +110,37 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { * @param $meta_value mixed the ID of the subscription that relates to the order */ public function purge_from_metadata( $meta_id, $object_id, $meta_key, $meta_value ) { - if ( ! in_array( $meta_key, array( '_subscription_renewal', '_subscription_resubscribe', '_subscription_switch' ) ) || 'shop_order' !== get_post_type( $object_id ) ) { + static $combined_keys = null; + static $order_keys = array( + '_subscription_renewal' => 1, + '_subscription_resubscribe' => 1, + '_subscription_switch' => 1, + ); + static $subscription_keys = array( + '_customer_user' => 1, + ); + + if ( null === $combined_keys ) { + $combined_keys = array_merge( $order_keys, $subscription_keys ); + } + + // Ensure we're handling a meta key we actually care about. + if ( ! isset( $combined_keys[ $meta_key ] ) ) { return; } - $this->log( 'Calling purge from ' . current_filter() . ' on object ' . $object_id . ' and meta value ' . $meta_value . ' due to ' . $meta_key . ' meta key.' ); - - $this->clear_related_order_cache( $meta_value ); + if ( 'shop_order' === get_post_type( $object_id ) && isset( $order_keys[ $meta_key ] ) ) { + $this->log( sprintf( + 'Calling purge from %1$s on object %2$s and meta value %3$s due to %4$s meta key.', + current_filter(), + $object_id, + $meta_value, + $meta_key + ) ); + $this->clear_related_order_cache( $meta_value ); + } elseif ( 'shop_subscription' === get_post_type( $object_id ) && isset( $subscription_keys[ $meta_key ] ) ) { + $this->purge_subscription_user_cache( $object_id ); + } } /** @@ -133,13 +170,15 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { * Delete cached data with key * * @param string $key Key that needs deleting + * + * @return bool */ public function delete_cached( $key ) { if ( ! is_string( $key ) || empty( $key ) ) { - return; + return false; } - delete_transient( $key ); + return delete_transient( $key ); } /** @@ -206,6 +245,24 @@ class WCS_Cached_Data_Manager extends WCS_Cache_Manager { return $schedules; } + /** + * Purge the cache for the subscription's user. + * + * @author Jeremy Pry + * + * @param int $subscription_id The subscription to purge. + */ + protected function purge_subscription_user_cache( $subscription_id ) { + $subscription = wcs_get_subscription( $subscription_id ); + $subscription_user_id = $subscription->get_user_id(); + $this->log( sprintf( + 'Clearing cache for user ID %1$s on %2$s hook.', + $subscription_user_id, + current_action() + ) ); + $this->delete_cached( "wcs_user_subscriptions_{$subscription_user_id}" ); + } + /* Deprecated Functions */ /** diff --git a/includes/class-wcs-cart-resubscribe.php b/includes/class-wcs-cart-resubscribe.php index 79b4e82..6e92d2e 100644 --- a/includes/class-wcs-cart-resubscribe.php +++ b/includes/class-wcs-cart-resubscribe.php @@ -305,7 +305,7 @@ class WCS_Cart_Resubscribe extends WCS_Cart_Renewal { public function maybe_cancel_existing_subscription( $order_id, $old_order_status, $new_order_status ) { if ( wcs_order_contains_subscription( $order_id ) && wcs_order_contains_resubscribe( $order_id ) ) { $order = wc_get_order( $order_id ); - $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id ), 'processing', 'completed' ) ); + $order_completed = in_array( $new_order_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ); $order_needed_payment = in_array( $old_order_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); foreach ( wcs_get_subscriptions_for_resubscribe_order( $order_id ) as $subscription ) { diff --git a/includes/class-wcs-query.php b/includes/class-wcs-query.php index 2717ce9..7074f87 100644 --- a/includes/class-wcs-query.php +++ b/includes/class-wcs-query.php @@ -20,6 +20,7 @@ class WCS_Query extends WC_Query { // Inserting your new tab/page into the My Account page. add_filter( 'woocommerce_account_menu_items', array( $this, 'add_menu_items' ) ); + add_filter( 'woocommerce_get_endpoint_url', array( $this, 'maybe_redirect_to_only_subscription' ), 10, 2 ); add_action( 'woocommerce_account_subscriptions_endpoint', array( $this, 'endpoint_content' ) ); } @@ -109,17 +110,43 @@ class WCS_Query extends WC_Query { * @return array */ public function add_menu_items( $menu_items ) { + if ( 1 == count( wcs_get_users_subscriptions() ) ) { + $label = __( 'My Subscription', 'woocommerce-subscriptions' ); + } else { + $label = __( 'Subscriptions', 'woocommerce-subscriptions' ); + } // Add our menu item after the Orders tab if it exists, otherwise just add it to the end if ( array_key_exists( 'orders', $menu_items ) ) { - $menu_items = wcs_array_insert_after( 'orders', $menu_items, 'subscriptions', __( 'Subscriptions', 'woocommerce-subscriptions' ) ); + $menu_items = wcs_array_insert_after( 'orders', $menu_items, 'subscriptions', $label ); } else { - $menu_items['subscriptions'] = __( 'Subscriptions', 'woocommerce-subscriptions' ); + $menu_items['subscriptions'] = $label; } return $menu_items; } + /** + * Changes the URL for the subscriptions endpoint when there's only one user subscription. + * + * @since 2.2.17 + * @param string $url + * @param string $endpoint + * @return string + */ + public function maybe_redirect_to_only_subscription( $url, $endpoint ) { + if ( 'subscriptions' == $endpoint ) { + $subscriptions = wcs_get_users_subscriptions(); + + if ( 1 == count( $subscriptions ) ) { + $subscription = reset( $subscriptions ); + $url = $subscription->get_view_order_url(); + } + } + + return $url; + } + /** * Endpoint HTML content. */ diff --git a/includes/class-wcs-remove-item.php b/includes/class-wcs-remove-item.php index 56b3281..c79233d 100644 --- a/includes/class-wcs-remove-item.php +++ b/includes/class-wcs-remove-item.php @@ -102,6 +102,8 @@ class WCS_Remove_Item { // translators: 1$: product name, 2$: product id $subscription->add_order_note( sprintf( _x( 'Customer added "%1$s" (Product ID: #%2$d) via the My Account page.', 'used in order note', 'woocommerce-subscriptions' ), wcs_get_line_item_name( $line_item ), $product_id ) ); + do_action( 'wcs_user_readded_item', $line_item, $subscription ); + } else { wc_add_notice( __( 'Your request to undo your previous action was unsuccessful.', 'woocommerce-subscriptions' ) ); } @@ -125,6 +127,8 @@ class WCS_Remove_Item { // translators: placeholders are 1$: item name, and, 2$: opening and, 3$: closing link tags wc_add_notice( sprintf( __( 'You have successfully removed "%1$s" from your subscription. %2$sUndo?%3$s', 'woocommerce-subscriptions' ), $line_item['name'], '', '' ) ); + + do_action( 'wcs_user_removed_item', $line_item, $subscription ); } } diff --git a/includes/class-wcs-select2.php b/includes/class-wcs-select2.php index a0ca10e..5381df7 100644 --- a/includes/class-wcs-select2.php +++ b/includes/class-wcs-select2.php @@ -87,7 +87,7 @@ class WCS_Select2 { $allowed_attributes = array_map( array( $this, 'get_property_name' ), array_keys( $this->attributes ) ); $allowed_attributes = array_fill_keys( $allowed_attributes, array() ); - echo wp_kses( $this->get_html(), array( 'input' => $allowed_attributes, 'select' => $allowed_attributes, 'option' => $allowed_attributes ) ); + echo wp_kses_allow_underscores( $this->get_html(), array( 'input' => $allowed_attributes, 'select' => $allowed_attributes, 'option' => $allowed_attributes ) ); } /** diff --git a/includes/class-wcs-user-change-status-handler.php b/includes/class-wcs-user-change-status-handler.php index 2161b50..47f75ab 100644 --- a/includes/class-wcs-user-change-status-handler.php +++ b/includes/class-wcs-user-change-status-handler.php @@ -54,26 +54,26 @@ class WCS_User_Change_Status_Handler { if ( ! $subscription->needs_payment() ) { $subscription->update_status( $new_status ); $subscription->add_order_note( _x( 'Subscription reactivated by the subscriber from their account page.', 'order note left on subscription after user action', 'woocommerce-subscriptions' ) ); - WC_Subscriptions::add_notice( _x( 'Your subscription has been reactivated.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); + wc_add_notice( _x( 'Your subscription has been reactivated.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); $changed = true; } else { - WC_Subscriptions::add_notice( __( 'You can not reactivate that subscription until paying to renew it. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'You can not reactivate that subscription until paying to renew it. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); } break; case 'on-hold' : if ( wcs_can_user_put_subscription_on_hold( $subscription ) ) { $subscription->update_status( $new_status ); $subscription->add_order_note( _x( 'Subscription put on hold by the subscriber from their account page.', 'order note left on subscription after user action', 'woocommerce-subscriptions' ) ); - WC_Subscriptions::add_notice( _x( 'Your subscription has been put on hold.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); + wc_add_notice( _x( 'Your subscription has been put on hold.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); $changed = true; } else { - WC_Subscriptions::add_notice( __( 'You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'You can not suspend that subscription - the suspension limit has been reached. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); } break; case 'cancelled' : $subscription->cancel_order(); $subscription->add_order_note( _x( 'Subscription cancelled by the subscriber from their account page.', 'order note left on subscription after user action', 'woocommerce-subscriptions' ) ); - WC_Subscriptions::add_notice( _x( 'Your subscription has been cancelled.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); + wc_add_notice( _x( 'Your subscription has been cancelled.', 'Notice displayed to user confirming their action.', 'woocommerce-subscriptions' ), 'success' ); $changed = true; break; } @@ -92,20 +92,20 @@ class WCS_User_Change_Status_Handler { $subscription = ( ! is_object( $subscription ) ) ? wcs_get_subscription( $subscription ) : $subscription; if ( ! wcs_is_subscription( $subscription ) ) { - WC_Subscriptions::add_notice( __( 'That subscription does not exist. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'That subscription does not exist. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); return false; } elseif ( ! empty( $wpnonce ) && wp_verify_nonce( $wpnonce, $subscription->get_id() . $subscription->get_status() ) === false ) { - WC_Subscriptions::add_notice( __( 'Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'Security error. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), 'error' ); return false; } elseif ( ! user_can( $user_id, 'edit_shop_subscription_status', $subscription->get_id() ) ) { - WC_Subscriptions::add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' ); + wc_add_notice( __( 'That doesn\'t appear to be one of your subscriptions.', 'woocommerce-subscriptions' ), 'error' ); return false; } elseif ( ! $subscription->can_be_updated_to( $new_status ) ) { // translators: placeholder is subscription's new status, translated - WC_Subscriptions::add_notice( sprintf( __( 'That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), wcs_get_subscription_status_name( $new_status ) ), 'error' ); + wc_add_notice( sprintf( __( 'That subscription can not be changed to %s. Please contact us if you need assistance.', 'woocommerce-subscriptions' ), wcs_get_subscription_status_name( $new_status ) ), 'error' ); return false; } diff --git a/includes/gateways/paypal/class-wcs-paypal.php b/includes/gateways/paypal/class-wcs-paypal.php index 3cf5530..05725ed 100644 --- a/includes/gateways/paypal/class-wcs-paypal.php +++ b/includes/gateways/paypal/class-wcs-paypal.php @@ -111,6 +111,12 @@ class WCS_PayPal { * @since 2.0 */ public static function get_option( $setting_key ) { + + // Post WC 3.3 PayPal's sandbox and live API credentials are stored separately. When requesting the API keys make sure we return the active keys - live or sandbox depending on the mode. + if ( ! WC_Subscriptions::is_woocommerce_pre( '3.3' ) && in_array( $setting_key, array( 'api_username', 'api_password', 'api_signature' ) ) && 'yes' === self::get_option( 'testmode' ) ) { + $setting_key = 'sandbox_' . $setting_key; + } + return ( isset( self::$paypal_settings[ $setting_key ] ) ) ? self::$paypal_settings[ $setting_key ] : ''; } @@ -253,14 +259,14 @@ class WCS_PayPal { } else { - wp_safe_redirect( WC()->cart->get_cart_url() ); + wp_safe_redirect( wc_get_cart_url() ); } } catch ( Exception $e ) { wc_add_notice( __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-subscriptions' ), 'error' ); - wp_redirect( WC()->cart->get_cart_url() ); + wp_redirect( wc_get_cart_url() ); } exit; diff --git a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php index d16feb9..662f3ad 100644 --- a/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php +++ b/includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php @@ -36,6 +36,9 @@ class WCS_PayPal_Admin { // Add the PayPal subscription information to the billing information add_action( 'woocommerce_admin_order_data_after_billing_address', __CLASS__ . '::profile_link' ); + + // Before WC updates the PayPal settings remove credentials error flag + add_action( 'load-woocommerce_page_wc-settings', __CLASS__ . '::maybe_update_credentials_error_flag', 9 ); } /** @@ -87,8 +90,6 @@ class WCS_PayPal_Admin { self::maybe_disable_invalid_profile_notice(); - self::maybe_update_credentials_error_flag(); - if ( ! in_array( get_woocommerce_currency(), apply_filters( 'woocommerce_paypal_supported_currencies', array( 'AUD', 'BRL', 'CAD', 'MXN', 'NZD', 'HKD', 'SGD', 'USD', 'EUR', 'JPY', 'TRY', 'NOK', 'CZK', 'DKK', 'HUF', 'ILS', 'MYR', 'PHP', 'PLN', 'SEK', 'CHF', 'TWD', 'THB', 'GBP', 'RMB' ) ) ) ) { $valid_for_use = false; } else { @@ -107,7 +108,7 @@ class WCS_PayPal_Admin { 'type' => 'warning', // translators: placeholders are opening and closing link tags. 1$-2$: to docs on woocommerce, 3$-4$ to gateway settings on the site 'text' => sprintf( esc_html__( 'PayPal is inactive for subscription transactions. Please %1$sset up the PayPal IPN%2$s and %3$senter your API credentials%4$s to enable PayPal for Subscriptions.', 'woocommerce-subscriptions' ), - '', + '', '', '', '' @@ -119,14 +120,13 @@ class WCS_PayPal_Admin { $notices[] = array( 'type' => 'warning', // translators: placeholders are opening and closing strong and link tags. 1$-2$: strong tags, 3$-8$ link to docs on woocommerce - 'text' => sprintf( esc_html__( '%1$sPayPal Reference Transactions are not enabled on your account%2$s, some subscription management features are not enabled. Please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %7$sLearn more %8$s', 'woocommerce-subscriptions' ), + 'text' => sprintf( esc_html__( '%1$sPayPal Reference Transactions are not enabled on your account%2$s, some subscription management features are not enabled. Please contact PayPal and request they %3$senable PayPal Reference Transactions%4$s on your account. %5$sCheck PayPal Account%6$s %3$sLearn more %7$s', 'woocommerce-subscriptions' ), '', '', - '', + '', '', '

', '', - '', '»' ), ); @@ -218,7 +218,7 @@ class WCS_PayPal_Admin { * * @since 2.0 */ - protected static function maybe_update_credentials_error_flag() { + public static function maybe_update_credentials_error_flag() { // Check if the API credentials are being saved - we can't do this on the 'woocommerce_update_options_payment_gateways_paypal' hook because it is triggered after 'admin_notices' if ( ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-settings' ) && isset( $_POST['woocommerce_paypal_api_username'] ) || isset( $_POST['woocommerce_paypal_api_password'] ) || isset( $_POST['woocommerce_paypal_api_signature'] ) ) { diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php index 99aed88..757a276 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php @@ -284,8 +284,8 @@ class WCS_PayPal_Reference_Transaction_API_Request { // calculate the total as PayPal would $calculated_total += $this->round( $order_subtotal + $order->get_cart_tax() ) + $this->round( $order->get_total_shipping() + $order->get_shipping_tax() ); - // offset the discrepency between the WooCommerce cart total and PayPal's calculated total by adjusting the order subtotal - if ( $total_amount !== $calculated_total ) { + // offset the discrepancy between the WooCommerce cart total and PayPal's calculated total by adjusting the order subtotal + if ( $this->price_format( $total_amount ) !== $this->price_format( $calculated_total ) ) { $order_subtotal = $order_subtotal - ( $calculated_total - $total_amount ); } @@ -334,12 +334,8 @@ class WCS_PayPal_Reference_Transaction_API_Request { // add individual order items foreach ( $order_items as $item ) { $this->add_line_item_parameters( $item, $item_count++, $use_deprecated_params ); - $calculated_total += $this->round( $item['AMT'] * $item['QTY'] ); } - // add shipping and tax to calculated total - $calculated_total += $this->round( $order->get_total_shipping() ) + $this->round( $order->get_total_tax() ); - $total_amount = $this->round( $order->get_total() ); // add order-level parameters @@ -589,7 +585,7 @@ class WCS_PayPal_Reference_Transaction_API_Request { // PayPal requires locale-specific number formats (e.g. USD is 123.45) // PayPal requires the decimal separator to be a period (.) - $this->parameters[ $key ] = number_format( $value, 2, '.', '' ); + $this->parameters[ $key ] = $this->price_format( $value ); } } @@ -642,7 +638,7 @@ class WCS_PayPal_Reference_Transaction_API_Request { $calculated_total += $this->round( $order->get_total_shipping() ) + $this->round( $order->get_total_tax() ); $total_amount = $this->round( $order->get_total() ); - if ( $total_amount !== $calculated_total ) { + if ( $this->price_format( $total_amount ) !== $this->price_format( $calculated_total ) ) { $skip_line_items = true; } } @@ -667,4 +663,16 @@ class WCS_PayPal_Reference_Transaction_API_Request { private function round( $number, $precision = 2 ) { return round( (float) $number, $precision ); } + + /** + * Format prices. + * + * @since 2.2.12 + * @param float|int $price + * @param int $decimals Optional. The number of decimal points. + * @return string + */ + private function price_format( $price, $decimals = 2 ) { + return number_format( $price, $decimals, '.', '' ); + } } diff --git a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php index b3f209b..bdf956e 100644 --- a/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php +++ b/includes/gateways/paypal/includes/class-wcs-paypal-standard-switcher.php @@ -245,7 +245,7 @@ class WCS_PayPal_Standard_Switcher { _deprecated_function( __METHOD__, '2.1', __CLASS__ . 'cancel_paypal_standard_after_switch( $order )' ); $order = wc_get_order( $order_id ); - $order_completed = in_array( $new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id ), 'processing', 'completed' ) ) && in_array( $old_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); + $order_completed = in_array( $new_status, array( apply_filters( 'woocommerce_payment_complete_order_status', 'processing', $order_id, $order ), 'processing', 'completed' ) ) && in_array( $old_status, apply_filters( 'woocommerce_valid_order_statuses_for_payment', array( 'pending', 'on-hold', 'failed' ), $order ) ); if ( $order_completed && wcs_order_contains_switch( $order_id ) ) { self::cancel_paypal_standard_after_switch( $order ); diff --git a/includes/wcs-cart-functions.php b/includes/wcs-cart-functions.php index 545dacf..1d4b01c 100644 --- a/includes/wcs-cart-functions.php +++ b/includes/wcs-cart-functions.php @@ -175,7 +175,7 @@ function wcs_cart_totals_shipping_method_price_label( $method, $cart ) { $price_label = ''; - if ( $method->cost > 0 ) { + if ( $method->cost != 0 ) { if ( WC()->cart->tax_display_cart == 'excl' ) { $price_label .= wcs_cart_price_string( $method->cost, $cart ); @@ -207,11 +207,14 @@ function wcs_cart_totals_taxes_total_html( $cart ) { } /** - * Display a recurring coupon's value + * Display a recurring coupon's value. + * + * @see wc_cart_totals_coupon_html() * * @access public - * @param string $coupon - * @return void + * + * @param string|WC_Coupon $coupon + * @param WC_Cart $cart */ function wcs_cart_totals_coupon_html( $coupon, $cart ) { if ( is_string( $coupon ) ) { @@ -235,10 +238,11 @@ function wcs_cart_totals_coupon_html( $coupon, $cart ) { // get rid of empty array elements $value = implode( ', ', array_filter( $value ) ); - // Apply WooCommerce core filter - $value = apply_filters( 'woocommerce_cart_totals_coupon_html', $value, $coupon ); + // Apply filters. + $html = apply_filters( 'wcs_cart_totals_coupon_html', $value, $coupon, $cart ); + $html = apply_filters( 'woocommerce_cart_totals_coupon_html', $html, $coupon, $discount_html ); - echo wp_kses_post( apply_filters( 'wcs_cart_totals_coupon_html', wcs_cart_price_string( $value, $cart ), $coupon, $cart ) ); + echo wp_kses( $html, array_replace_recursive( wp_kses_allowed_html( 'post' ), array( 'a' => array( 'data-coupon' => true ) ) ) ); } /** @@ -278,7 +282,7 @@ function wcs_cart_totals_order_total_html( $cart ) { * Return a formatted price string for a given cart object * * @access public - * @return void + * @return string */ function wcs_cart_price_string( $recurring_amount, $cart ) { diff --git a/includes/wcs-formatting-functions.php b/includes/wcs-formatting-functions.php index 324500f..ecf3bd6 100644 --- a/includes/wcs-formatting-functions.php +++ b/includes/wcs-formatting-functions.php @@ -236,3 +236,27 @@ function wcs_get_human_time_diff( $timestamp_gmt ) { return $date_to_display; } + +/** + * Works around the wp_kses() limitation of not accepting attribute names with underscores. + * + * @param string $content Content to filter through kses. + * @param array $allowed_html List of allowed HTML elements. + * @return string Filtered string of HTML. + * @since 2.2.17 + */ +function wp_kses_allow_underscores( $content, $allowed_html ) { + + /* Replace the underscore _ with a double hyphen -- in the attribute names */ + foreach ( $allowed_html as $tag => &$attributes ) { + $attribute_names = array_keys( $attributes ); + $attribute_values = array_values( $attributes ); + $attributes = array_combine( preg_replace( '/_/', '--', $attribute_names ), $attribute_values ); + } + + /* Replace the underscore _ with a double hyphen -- in the content as well. + The assumption is that such an attribute name would be followed by a = */ + $content = preg_replace( '/\b([-A-Za-z]+)_([-A-Za-z]+)=/', '$1--$2=', $content ); + $content = wp_kses( $content, $allowed_html ); // Now pass through wp_kses the attribute name with -- + return preg_replace( '/\b([-A-Za-z]+)--([-A-Za-z]+)=/', '$1_$2=', $content ); // Replace the _ back +} diff --git a/includes/wcs-order-functions.php b/includes/wcs-order-functions.php index 92f734a..a5c5cca 100644 --- a/includes/wcs-order-functions.php +++ b/includes/wcs-order-functions.php @@ -607,7 +607,7 @@ function wcs_get_order_item_name( $order_item, $include = array() ) { foreach ( $order_item['item_meta'] as $meta_key => $meta_value ) { - $meta_value = $meta_value[0]; + $meta_value = WC_Subscriptions::is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; // Skip hidden core fields if ( in_array( $meta_key, apply_filters( 'woocommerce_hidden_order_itemmeta', array( @@ -624,8 +624,8 @@ function wcs_get_order_item_name( $order_item, $include = array() ) { continue; } - // Skip serialised meta - if ( is_serialized( $meta_value ) ) { + // Skip serialised or array meta values + if ( is_serialized( $meta_value ) || is_array( $meta_value ) ) { continue; } @@ -660,7 +660,7 @@ function wcs_get_line_item_name( $line_item ) { foreach ( $line_item['item_meta'] as $meta_key => $meta_value ) { - $meta_value = $meta_value[0]; + $meta_value = WC_Subscriptions::is_woocommerce_pre( 3.0 ) ? $meta_value[0] : $meta_value; // Skip hidden core fields if ( in_array( $meta_key, apply_filters( 'woocommerce_hidden_order_itemmeta', array( @@ -677,8 +677,8 @@ function wcs_get_line_item_name( $line_item ) { continue; } - // Skip serialised meta - if ( is_serialized( $meta_value ) ) { + // Skip serialised or array meta values + if ( is_serialized( $meta_value ) || is_array( $meta_value ) ) { continue; } diff --git a/includes/wcs-time-functions.php b/includes/wcs-time-functions.php index 5042e91..b24c44f 100644 --- a/includes/wcs-time-functions.php +++ b/includes/wcs-time-functions.php @@ -34,7 +34,8 @@ function wcs_get_subscription_period_strings( $number = 1, $period = '' ) { 'month' => sprintf( _nx( 'month', '%s months', $number, 'Subscription billing period.', 'woocommerce-subscriptions' ), $number ), // translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") 'year' => sprintf( _nx( 'year', '%s years', $number, 'Subscription billing period.', 'woocommerce-subscriptions' ), $number ), - ) + ), + $number ); return ( ! empty( $period ) ) ? $translated_periods[ $period ] : $translated_periods; @@ -55,7 +56,8 @@ function wcs_get_subscription_trial_period_strings( $number = 1, $period = '' ) 'week' => sprintf( _n( '%s week', 'a %s-week', $number, 'woocommerce-subscriptions' ), $number ), 'month' => sprintf( _n( '%s month', 'a %s-month', $number, 'woocommerce-subscriptions' ), $number ), 'year' => sprintf( _n( '%s year', 'a %s-year', $number, 'woocommerce-subscriptions' ), $number ), - ) + ), + $number ); return ( ! empty( $period ) ) ? $translated_periods[ $period ] : $translated_periods; @@ -123,7 +125,7 @@ function wcs_get_subscription_ranges( $subscription_period = '' ) { $subscription_period = ''; } - $locale = get_locale(); + $locale = function_exists( 'get_user_locale' ) ? get_user_locale() : get_locale(); $subscription_ranges = WC_Subscriptions::$cache->cache_and_get( 'wcs-sub-ranges-' . $locale, 'wcs_get_non_cached_subscription_ranges', array(), 3 * HOUR_IN_SECONDS ); diff --git a/includes/wcs-user-functions.php b/includes/wcs-user-functions.php index 7b6fe32..0249f99 100644 --- a/includes/wcs-user-functions.php +++ b/includes/wcs-user-functions.php @@ -123,10 +123,12 @@ function wcs_get_new_user_role_names( $role_new ) { /** * Check if a user has a subscription, optionally to a specific product and/or with a certain status. * - * @param int (optional) The ID of a user in the store. If left empty, the current user's ID will be used. - * @param int (optional) The ID of a product in the store. If left empty, the function will see if the user has any subscription. - * @param mixed (optional) A valid subscription status string or array. If left empty, the function will see if the user has a subscription of any status. + * @param int $user_id (optional) The ID of a user in the store. If left empty, the current user's ID will be used. + * @param int $product_id (optional) The ID of a product in the store. If left empty, the function will see if the user has any subscription. + * @param mixed $status (optional) A valid subscription status string or array. If left empty, the function will see if the user has a subscription of any status. * @since 2.0 + * + * @return bool */ function wcs_user_has_subscription( $user_id = 0, $product_id = '', $status = 'any' ) { @@ -164,9 +166,10 @@ function wcs_user_has_subscription( $user_id = 0, $product_id = '', $status = 'a * * @param int $user_id (optional) The id of the user whose subscriptions you want. Defaults to the currently logged in user. * @since 2.0 + * + * @return WC_Subscription[] */ function wcs_get_users_subscriptions( $user_id = 0 ) { - if ( 0 === $user_id || empty( $user_id ) ) { $user_id = get_current_user_id(); } @@ -174,18 +177,7 @@ function wcs_get_users_subscriptions( $user_id = 0 ) { $subscriptions = apply_filters( 'wcs_pre_get_users_subscriptions', array(), $user_id ); if ( empty( $subscriptions ) && 0 !== $user_id && ! empty( $user_id ) ) { - - $post_ids = get_posts( array( - 'posts_per_page' => -1, - 'post_status' => 'any', - 'post_type' => 'shop_subscription', - 'orderby' => 'date', - 'order' => 'desc', - 'meta_key' => '_customer_user', - 'meta_value' => $user_id, - 'meta_compare' => '=', - 'fields' => 'ids', - ) ); + $post_ids = wcs_get_cached_user_subscription_ids( $user_id ); foreach ( $post_ids as $post_id ) { $subscription = wcs_get_subscription( $post_id ); @@ -199,6 +191,65 @@ function wcs_get_users_subscriptions( $user_id = 0 ) { return apply_filters( 'wcs_get_users_subscriptions', $subscriptions, $user_id ); } +/** + * Get subscription IDs for the given user. + * + * @author Jeremy Pry + * + * @param int $user_id The ID of the user whose subscriptions you want. + * + * @return array Array of Subscription IDs. + */ +function wcs_get_users_subscription_ids( $user_id ) { + $query = new WP_Query(); + + return $query->query( array( + 'post_type' => 'shop_subscription', + 'posts_per_page' => -1, + 'post_status' => 'any', + 'orderby' => 'date', + 'order' => 'desc', + 'fields' => 'ids', + 'no_found_rows' => true, + 'ignore_sticky_posts' => true, + 'meta_query' => array( + array( + 'key' => '_customer_user', + 'value' => $user_id, + ), + ), + ) ); +} + +/** + * Get subscription IDs for a user using caching. + * + * @author Jeremy Pry + * + * @param int $user_id The ID of the user whose subscriptions you want. + * + * @return array Array of subscription IDs. + */ +function wcs_get_cached_user_subscription_ids( $user_id = 0 ) { + $user_id = absint( $user_id ); + if ( 0 === $user_id ) { + $user_id = get_current_user_id(); + } + + // If the user ID is still zero, bail early. + if ( 0 === $user_id ) { + return apply_filters( 'wcs_get_cached_users_subscription_ids', array(), $user_id ); + } + + $subscription_ids = WC_Subscriptions::$cache->cache_and_get( + "wcs_user_subscriptions_{$user_id}", + 'wcs_get_users_subscription_ids', + array( $user_id ) + ); + + return apply_filters( 'wcs_get_cached_users_subscription_ids', $subscription_ids, $user_id ); +} + /** * Return a link for subscribers to change the status of their subscription, as specified with $status parameter * @@ -320,7 +371,7 @@ function wcs_get_all_user_actions_for_subscription( $subscription, $user_id ) { * @param array $allcaps * @param array $caps * @param array $args - * @return bool + * @return array */ function wcs_user_has_capability( $allcaps, $caps, $args ) { if ( isset( $caps[0] ) ) { diff --git a/languages/woocommerce-subscriptions.pot b/languages/woocommerce-subscriptions.pot index a65f7a8..1d9980a 100644 --- a/languages/woocommerce-subscriptions.pot +++ b/languages/woocommerce-subscriptions.pot @@ -1,15 +1,15 @@ -# Copyright (C) 2017 Prospress Inc. +# Copyright (C) 2018 Prospress Inc. # This file is distributed under the same license as the WooCommerce Subscriptions package. msgid "" msgstr "" -"Project-Id-Version: WooCommerce Subscriptions 2.2.15\n" +"Project-Id-Version: WooCommerce Subscriptions 2.2.17\n" "Report-Msgid-Bugs-To: " "https://github.com/Prospress/woocommerce-subscriptions/issues\n" -"POT-Creation-Date: 2017-11-07 04:27:49+00:00\n" +"POT-Creation-Date: 2018-01-29 04:39:30+00:00\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" -"PO-Revision-Date: 2017-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2018-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: Prospress Translations \n" "X-Generator: grunt-wp-i18n 0.5.4\n" @@ -28,7 +28,7 @@ msgid "Choose the subscription price, billing interval and period." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:211 -#: templates/admin/html-variation-price.php:42 +#: templates/admin/html-variation-price.php:44 #. translators: placeholder is a currency symbol / code msgid "Subscription price (%s)" msgstr "" @@ -44,8 +44,8 @@ msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:234 #: includes/admin/class-wc-subscriptions-admin.php:357 -#: templates/admin/html-variation-price.php:64 -msgid "Subscription length" +#: templates/admin/html-variation-price.php:66 +msgid "Expire after" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:237 @@ -56,7 +56,7 @@ msgid "" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:246 -#: templates/admin/html-variation-price.php:18 +#: templates/admin/html-variation-price.php:20 #. translators: %s is a currency symbol / code msgid "Sign-up fee (%s)" msgstr "" @@ -69,7 +69,7 @@ msgid "" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:260 -#: templates/admin/html-variation-price.php:23 +#: templates/admin/html-variation-price.php:25 msgid "Free trial" msgstr "" @@ -188,9 +188,9 @@ msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:989 #: includes/admin/class-wcs-admin-reports.php:51 #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:654 -#: includes/class-wcs-query.php:95 includes/class-wcs-query.php:115 -#: includes/class-wcs-query.php:117 templates/admin/status.php:9 -#: woocommerce-subscriptions.php:229 woocommerce-subscriptions.php:242 +#: includes/class-wcs-query.php:96 includes/class-wcs-query.php:116 +#: templates/admin/status.php:21 woocommerce-subscriptions.php:229 +#: woocommerce-subscriptions.php:242 msgid "Subscriptions" msgstr "" @@ -215,7 +215,7 @@ msgstr "" #: includes/class-wc-product-subscription.php:72 #: includes/class-wc-product-variable-subscription.php:63 #: includes/class-wc-subscriptions-product.php:96 -#: woocommerce-subscriptions.php:489 +#: woocommerce-subscriptions.php:490 msgid "Sign Up Now" msgstr "" @@ -311,11 +311,13 @@ msgid "Mixed Checkout" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1145 -msgid "Allow subscriptions and products to be purchased simultaneously." +msgid "Allow multiple subscriptions and products to be purchased simultaneously." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1149 -msgid "Allow subscriptions and products to be purchased in a single transaction." +msgid "" +"Allow a subscription product to be purchased with other products and " +"subscriptions in the same transaction." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1153 @@ -350,7 +352,7 @@ msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1200 #: includes/upgrades/templates/wcs-about-2-0.php:35 #: includes/upgrades/templates/wcs-about.php:34 -#: woocommerce-subscriptions.php:1028 +#: woocommerce-subscriptions.php:1029 msgid "Settings" msgstr "" @@ -377,39 +379,39 @@ msgid "The trial period can not exceed %s." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1412 -#: includes/admin/class-wc-subscriptions-admin.php:1440 -#: includes/admin/class-wc-subscriptions-admin.php:1493 +#: includes/admin/class-wc-subscriptions-admin.php:1448 +#: includes/admin/class-wc-subscriptions-admin.php:1501 #: includes/admin/reports/class-wcs-report-cache-manager.php:340 msgid "Yes" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1412 -#: includes/admin/class-wc-subscriptions-admin.php:1440 +#: includes/admin/class-wc-subscriptions-admin.php:1448 #: includes/admin/reports/class-wcs-report-cache-manager.php:340 msgid "No" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1476 +#: includes/admin/class-wc-subscriptions-admin.php:1484 msgid "Automatic Recurring Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1493 +#: includes/admin/class-wc-subscriptions-admin.php:1501 msgid "" "Supports automatic renewal payments with the WooCommerce Subscriptions " "extension." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1573 +#: includes/admin/class-wc-subscriptions-admin.php:1581 msgid "Subscription items can no longer be edited." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1577 +#: includes/admin/class-wc-subscriptions-admin.php:1585 msgid "" "This subscription is no longer editable because the payment gateway does " "not allow modification of recurring amounts." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1596 +#: includes/admin/class-wc-subscriptions-admin.php:1604 #. translators: $1-2: opening and closing tags of a link that takes to Woo #. marketplace / Stripe product page msgid "" @@ -418,18 +420,18 @@ msgid "" "the %1$sfree Stripe extension%2$s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1601 +#: includes/admin/class-wc-subscriptions-admin.php:1609 msgid "Recurring Payments" msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1609 +#: includes/admin/class-wc-subscriptions-admin.php:1617 #. translators: placeholders are opening and closing link tags msgid "" "Payment gateways which don't support automatic recurring payments can be " "used to process %smanual subscription renewal payments%s." msgstr "" -#: includes/admin/class-wc-subscriptions-admin.php:1616 +#: includes/admin/class-wc-subscriptions-admin.php:1624 #. translators: $1-$2: opening and closing tags. Link to documents->payment #. gateways, 3$-4$: opening and closing tags. Link to WooCommerce extensions #. shop page @@ -505,18 +507,18 @@ msgstr "" msgid "Create pending renewal order requested by admin action." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:200 +#: includes/admin/class-wcs-admin-post-types.php:201 msgid "Search for a product…" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:377 +#: includes/admin/class-wcs-admin-post-types.php:378 #. translators: placeholder is the number of subscriptions updated msgid "%s subscription status changed." msgid_plural "%s subscription statuses changed." msgstr[0] "" msgstr[1] "" -#: includes/admin/class-wcs-admin-post-types.php:384 +#: includes/admin/class-wcs-admin-post-types.php:385 #. translators: 1$: is the number of subscriptions not updated, 2$: is the #. error message msgid "%1$s subscription could not be updated: %2$s" @@ -524,7 +526,7 @@ msgid_plural "%1$s subscriptions could not be updated: %2$s" msgstr[0] "" msgstr[1] "" -#: includes/admin/class-wcs-admin-post-types.php:408 +#: includes/admin/class-wcs-admin-post-types.php:409 #: includes/admin/meta-boxes/views/html-related-orders-table.php:20 #: templates/myaccount/my-subscriptions.php:26 #: templates/myaccount/my-subscriptions.php:41 @@ -536,7 +538,7 @@ msgstr[1] "" msgid "Status" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:409 +#: includes/admin/class-wcs-admin-post-types.php:410 #: includes/admin/meta-boxes/class-wcs-meta-box-related-orders.php:61 #: templates/emails/cancelled-subscription.php:26 #: templates/emails/expired-subscription.php:26 @@ -548,152 +550,162 @@ msgstr "" msgid "Subscription" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:410 +#: includes/admin/class-wcs-admin-post-types.php:411 msgid "Items" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:411 +#: includes/admin/class-wcs-admin-post-types.php:412 msgid "Total" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:412 +#: includes/admin/class-wcs-admin-post-types.php:413 msgid "Start Date" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:413 +#: includes/admin/class-wcs-admin-post-types.php:414 msgid "Trial End" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:414 +#: includes/admin/class-wcs-admin-post-types.php:415 msgid "Next Payment" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:415 +#: includes/admin/class-wcs-admin-post-types.php:416 msgid "Last Order Date" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:416 +#: includes/admin/class-wcs-admin-post-types.php:417 msgid "End Date" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:457 -#: includes/wcs-user-functions.php:292 +#: includes/admin/class-wcs-admin-post-types.php:458 +#: includes/wcs-user-functions.php:343 msgid "Reactivate" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:458 -#: includes/wcs-user-functions.php:287 +#: includes/admin/class-wcs-admin-post-types.php:459 +#: includes/wcs-user-functions.php:338 msgid "Suspend" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:460 -#: includes/admin/class-wcs-admin-post-types.php:475 +#: includes/admin/class-wcs-admin-post-types.php:461 +#: includes/admin/class-wcs-admin-post-types.php:476 msgid "Trash" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:461 -#: includes/admin/class-wcs-admin-post-types.php:479 +#: includes/admin/class-wcs-admin-post-types.php:462 +#: includes/admin/class-wcs-admin-post-types.php:480 msgid "Delete Permanently" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:473 +#: includes/admin/class-wcs-admin-post-types.php:474 #: includes/class-wc-subscriptions-product.php:733 msgid "Restore this item from the Trash" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:473 +#: includes/admin/class-wcs-admin-post-types.php:474 #: includes/class-wc-subscriptions-product.php:734 msgid "Restore" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:475 +#: includes/admin/class-wcs-admin-post-types.php:476 msgid "Move this item to the Trash" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:479 +#: includes/admin/class-wcs-admin-post-types.php:480 msgid "Delete this item permanently" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:485 +#: includes/admin/class-wcs-admin-post-types.php:486 msgid "Cancel Now" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:518 +#: includes/admin/class-wcs-admin-post-types.php:519 #. translators: placeholder is customer's billing email msgid "Email: %s" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:523 +#: includes/admin/class-wcs-admin-post-types.php:524 #. translators: placeholder is customer's billing phone number msgid "Tel: %s" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:555 +#: includes/admin/class-wcs-admin-post-types.php:556 msgid "Show more details" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:571 +#: includes/admin/class-wcs-admin-post-types.php:572 msgid "%d item" msgid_plural "%d items" msgstr[0] "" msgstr[1] "" -#: includes/admin/class-wcs-admin-post-types.php:587 +#: includes/admin/class-wcs-admin-post-types.php:588 #: templates/myaccount/my-subscriptions.php:49 #. translators: placeholder is the display name of a payment gateway a #. subscription was paid by msgid "Via %s" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:601 +#: includes/admin/class-wcs-admin-post-types.php:602 msgid "Y/m/d g:i:s A" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:604 +#: includes/admin/class-wcs-admin-post-types.php:605 msgid "" "This date should be treated as an estimate only. The payment gateway for " "this subscription controls when payments are processed." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:877 -#: includes/admin/class-wcs-admin-post-types.php:880 -#: includes/admin/class-wcs-admin-post-types.php:883 +#: includes/admin/class-wcs-admin-post-types.php:878 +#: includes/admin/class-wcs-admin-post-types.php:881 +#: includes/admin/class-wcs-admin-post-types.php:884 msgid "Subscription updated." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:878 +#: includes/admin/class-wcs-admin-post-types.php:879 msgid "Custom field updated." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:879 +#: includes/admin/class-wcs-admin-post-types.php:880 msgid "Custom field deleted." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:884 +#: includes/admin/class-wcs-admin-post-types.php:885 msgid "Subscription saved." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:885 +#: includes/admin/class-wcs-admin-post-types.php:886 msgid "Subscription submitted." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:887 +#: includes/admin/class-wcs-admin-post-types.php:888 #. translators: php date string msgid "Subscription scheduled for: %1$s." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:888 +#: includes/admin/class-wcs-admin-post-types.php:889 msgid "Subscription draft updated." msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:924 +#: includes/admin/class-wcs-admin-post-types.php:925 msgid "Any Payment Method" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:925 +#: includes/admin/class-wcs-admin-post-types.php:926 msgid "None" msgstr "" +#: includes/admin/class-wcs-admin-post-types.php:1119 +#. translators: 1: user display name 2: user ID 3: user email +msgid "%1$s (#%2$s – %3$s)" +msgstr "" + +#: includes/admin/class-wcs-admin-post-types.php:1126 +#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:79 +msgid "Search for a customer…" +msgstr "" + #: includes/admin/class-wcs-admin-reports.php:54 msgid "Subscription Events by Date" msgstr "" @@ -731,10 +743,6 @@ msgstr "" msgid "View other subscriptions" msgstr "" -#: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:79 -msgid "Search for a customer…" -msgstr "" - #: includes/admin/meta-boxes/class-wcs-meta-box-subscription-data.php:87 msgid "Subscription status:" msgstr "" @@ -818,7 +826,7 @@ msgstr "" #: includes/admin/meta-boxes/views/html-related-orders-table.php:19 #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:515 #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:173 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:202 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:205 #: templates/myaccount/related-orders.php:23 #: templates/myaccount/related-orders.php:42 msgid "Date" @@ -1182,7 +1190,7 @@ msgstr "" #: includes/admin/reports/class-wcs-report-subscription-events-by-date.php:519 #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:177 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:206 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:209 msgid "Export CSV" msgstr "" @@ -1237,7 +1245,7 @@ msgid "" msgstr "" #: includes/admin/reports/class-wcs-report-subscription-payment-retry.php:102 -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:91 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:93 msgid "%s renewal orders" msgstr "" @@ -1291,35 +1299,35 @@ msgstr "" msgid "Recovered Renewal Revenue" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:86 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:88 msgid "%s renewal income in this period" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:96 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:98 msgid "%s average renewal amount" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:172 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:175 msgid "Next 12 Months" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:173 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:176 msgid "Next 30 Days" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:174 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:177 msgid "Next Month" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:175 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:178 msgid "Next 7 Days" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:240 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:243 msgid "Renewals count" msgstr "" -#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:249 +#: includes/admin/reports/class-wcs-report-upcoming-recurring-revenue.php:252 msgid "Renewals amount" msgstr "" @@ -1450,7 +1458,7 @@ msgid "Status set to %s." msgstr "" #: includes/class-wc-subscription.php:1148 -#: includes/class-wc-subscriptions-manager.php:2263 +#: includes/class-wc-subscriptions-manager.php:2279 #: includes/wcs-formatting-functions.php:228 #. translators: placeholder is human time diff (e.g. "3 weeks") msgid "In %s" @@ -1543,7 +1551,7 @@ msgid "The %s date must occur after the start date." msgstr "" #: includes/class-wc-subscription.php:2365 -#: includes/class-wc-subscriptions-checkout.php:313 +#: includes/class-wc-subscriptions-checkout.php:325 #: includes/wcs-order-functions.php:288 msgid "Backordered" msgstr "" @@ -1564,21 +1572,21 @@ msgstr "" msgid "Update the %1$s used for %2$sall%3$s of my active subscriptions" msgstr "" -#: includes/class-wc-subscriptions-cart.php:889 +#: includes/class-wc-subscriptions-cart.php:891 msgid "Please enter a valid postcode/ZIP." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1060 +#: includes/class-wc-subscriptions-cart.php:1062 msgid "" "That subscription product can not be added to your cart as it already " "contains a subscription renewal." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1148 +#: includes/class-wc-subscriptions-cart.php:1150 msgid "Invalid recurring shipping method." msgstr "" -#: includes/class-wc-subscriptions-cart.php:1914 +#: includes/class-wc-subscriptions-cart.php:1939 msgid "now" msgstr "" @@ -1650,18 +1658,18 @@ msgstr "" msgid "Payment method updated." msgstr "" -#: includes/class-wc-subscriptions-checkout.php:173 -#: includes/class-wc-subscriptions-checkout.php:344 +#: includes/class-wc-subscriptions-checkout.php:185 +#: includes/class-wc-subscriptions-checkout.php:356 #. translators: placeholder is an internal error number msgid "Error %d: Unable to create subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-checkout.php:190 +#: includes/class-wc-subscriptions-checkout.php:202 #. translators: placeholder is an internal error number msgid "Error %d: Unable to add tax to subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-checkout.php:202 +#: includes/class-wc-subscriptions-checkout.php:214 #. translators: placeholder is an internal error number msgid "Error %d: Unable to create order. Please try again." msgstr "" @@ -1740,91 +1748,91 @@ msgstr "" msgid "Renewal Discount" msgstr "" -#: includes/class-wc-subscriptions-manager.php:120 +#: includes/class-wc-subscriptions-manager.php:123 msgid "Error: Unable to create renewal order with note \"%s\"" msgstr "" -#: includes/class-wc-subscriptions-manager.php:165 +#: includes/class-wc-subscriptions-manager.php:168 #: includes/gateways/class-wc-subscriptions-payment-gateways.php:204 msgid "Subscription doesn't exist in scheduled action: %d" msgstr "" -#: includes/class-wc-subscriptions-manager.php:302 +#: includes/class-wc-subscriptions-manager.php:305 #. translators: $1: order number, $2: error message msgid "Failed to activate subscription status for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:330 +#: includes/class-wc-subscriptions-manager.php:333 #. translators: $1: order number, $2: error message msgid "Failed to update subscription status after order #%1$s was put on-hold: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:358 +#: includes/class-wc-subscriptions-manager.php:361 #. translators: $1: order number, $2: error message msgid "Failed to cancel subscription after order #%1$s was cancelled: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:386 +#: includes/class-wc-subscriptions-manager.php:389 #. translators: $1: order number, $2: error message msgid "Failed to set subscription as expired for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:412 +#: includes/class-wc-subscriptions-manager.php:415 msgid "Subscription sign up failed." msgstr "" -#: includes/class-wc-subscriptions-manager.php:422 +#: includes/class-wc-subscriptions-manager.php:425 #. translators: $1: order number, $2: error message msgid "Failed to process failed payment on subscription for order #%1$s: %2$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:491 +#: includes/class-wc-subscriptions-manager.php:494 msgid "Error: Unable to create subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:510 +#: includes/class-wc-subscriptions-manager.php:513 msgid "Error: Unable to add product to created subscription. Please try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:555 +#: includes/class-wc-subscriptions-manager.php:558 msgid "Pending subscription created." msgstr "" -#: includes/class-wc-subscriptions-manager.php:1803 +#: includes/class-wc-subscriptions-manager.php:1819 #. translators: all fields are full html nodes: 1$: month input, 2$: day input, #. 3$: year input, 4$: hour input, 5$: minute input. Change the order if you'd #. like msgid "%1$s%2$s, %3$s @ %4$s : %5$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1807 +#: includes/class-wc-subscriptions-manager.php:1823 #. translators: all fields are full html nodes: 1$: month input, 2$: day input, #. 3$: year input. Change the order if you'd like msgid "%1$s%2$s, %3$s" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1812 +#: includes/class-wc-subscriptions-manager.php:1828 msgid "Change" msgstr "" -#: includes/class-wc-subscriptions-manager.php:2145 +#: includes/class-wc-subscriptions-manager.php:2161 #. translators: placeholder is subscription ID msgid "Failed sign-up for subscription %s." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2236 +#: includes/class-wc-subscriptions-manager.php:2252 msgid "Invalid security token, please reload the page and try again." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2240 +#: includes/class-wc-subscriptions-manager.php:2256 msgid "Only store managers can edit payment dates." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2244 +#: includes/class-wc-subscriptions-manager.php:2260 msgid "Please enter all date fields." msgstr "" -#: includes/class-wc-subscriptions-manager.php:2269 +#: includes/class-wc-subscriptions-manager.php:2285 msgid "Date Changed" msgstr "" @@ -2072,7 +2080,7 @@ msgstr "" #: includes/class-wc-subscriptions-switcher.php:408 #: includes/class-wc-subscriptions-switcher.php:434 -#: includes/class-wc-subscriptions-switcher.php:2363 +#: includes/class-wc-subscriptions-switcher.php:2370 msgid "Upgrade or Downgrade" msgstr "" @@ -2111,7 +2119,7 @@ msgid "There was an error locating the switch details." msgstr "" #: includes/class-wc-subscriptions-switcher.php:1929 -#: includes/class-wc-subscriptions-switcher.php:2269 +#: includes/class-wc-subscriptions-switcher.php:2277 msgid "The original subscription item being switched cannot be found." msgstr "" @@ -2119,7 +2127,7 @@ msgstr "" msgid "The item on the switch order cannot be found." msgstr "" -#: includes/class-wc-subscriptions-switcher.php:2307 +#: includes/class-wc-subscriptions-switcher.php:2314 msgid "Failed to update the subscription shipping method." msgstr "" @@ -2200,7 +2208,7 @@ msgstr "" msgid "View and manage subscriptions" msgstr "" -#: includes/class-wcs-cached-data-manager.php:202 +#: includes/class-wcs-cached-data-manager.php:241 msgid "Weekly" msgstr "" @@ -2321,30 +2329,34 @@ msgstr "" msgid "%s ending in %s" msgstr "" -#: includes/class-wcs-remove-item.php:106 +#: includes/class-wcs-query.php:114 +msgid "My Subscription" +msgstr "" + +#: includes/class-wcs-remove-item.php:108 msgid "Your request to undo your previous action was unsuccessful." msgstr "" -#: includes/class-wcs-remove-item.php:127 +#: includes/class-wcs-remove-item.php:129 #. translators: placeholders are 1$: item name, and, 2$: opening and, 3$: #. closing link tags msgid "You have successfully removed \"%1$s\" from your subscription. %2$sUndo?%3$s" msgstr "" -#: includes/class-wcs-remove-item.php:161 +#: includes/class-wcs-remove-item.php:165 #: includes/class-wcs-user-change-status-handler.php:99 msgid "Security error. Please contact us if you need assistance." msgstr "" -#: includes/class-wcs-remove-item.php:165 +#: includes/class-wcs-remove-item.php:169 msgid "You cannot modify a subscription that does not belong to you." msgstr "" -#: includes/class-wcs-remove-item.php:169 +#: includes/class-wcs-remove-item.php:173 msgid "You cannot remove an item that does not exist. " msgstr "" -#: includes/class-wcs-remove-item.php:173 +#: includes/class-wcs-remove-item.php:177 msgid "" "The item was not removed because this Subscription's payment method does " "not support removing an item." @@ -2633,49 +2645,49 @@ msgid "" "alternate arrangements." msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:204 +#: includes/gateways/paypal/class-wcs-paypal.php:210 msgid "Unable to find order for PayPal billing agreement." msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:261 +#: includes/gateways/paypal/class-wcs-paypal.php:267 msgid "An error occurred, please try again or try an alternate form of payment." msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:368 +#: includes/gateways/paypal/class-wcs-paypal.php:374 #. translators: placeholders are PayPal API error code and PayPal API error #. message msgid "PayPal API error: (%d) %s" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:373 +#: includes/gateways/paypal/class-wcs-paypal.php:379 #. translators: placeholder is PayPal transaction status message msgid "PayPal Transaction Held: %s" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:385 +#: includes/gateways/paypal/class-wcs-paypal.php:391 #. translators: placeholder is PayPal transaction status message msgid "PayPal payment declined: %s" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:389 +#: includes/gateways/paypal/class-wcs-paypal.php:395 msgid "PayPal payment approved (ID: %s)" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:442 +#: includes/gateways/paypal/class-wcs-paypal.php:448 msgid "" "Are you sure you want to change the payment method from PayPal standard?\n" "\n" "This will suspend the subscription at PayPal." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:56 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:59 msgid "" "It is strongly recommended you do not change the Receiver Email " "address if you have active subscriptions with PayPal. Doing so can " "break existing subscriptions." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:109 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:110 #. translators: placeholders are opening and closing link tags. 1$-2$: to docs #. on woocommerce, 3$-4$ to gateway settings on the site msgid "" @@ -2684,14 +2696,14 @@ msgid "" "Subscriptions." msgstr "" -#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:122 +#: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:123 #. translators: placeholders are opening and closing strong and link tags. #. 1$-2$: strong tags, 3$-8$ link to docs on woocommerce msgid "" "%1$sPayPal Reference Transactions are not enabled on your account%2$s, some " "subscription management features are not enabled. Please contact PayPal and " "request they %3$senable PayPal Reference Transactions%4$s on your account. " -"%5$sCheck PayPal Account%6$s %7$sLearn more %8$s" +"%5$sCheck PayPal Account%6$s %3$sLearn more %7$s" msgstr "" #: includes/gateways/paypal/includes/admin/class-wcs-paypal-admin.php:140 @@ -2748,7 +2760,7 @@ msgstr "" msgid "%s - Order" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:511 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:507 msgid "SKU: %s" msgstr "" @@ -3569,11 +3581,11 @@ msgid_plural "Shipping %d" msgstr[0] "" msgstr[1] "" -#: includes/wcs-cart-functions.php:232 +#: includes/wcs-cart-functions.php:235 msgid "Free shipping coupon" msgstr "" -#: includes/wcs-cart-functions.php:336 +#: includes/wcs-cart-functions.php:340 #. translators: placeholder is a date msgid "First renewal: %s" msgstr "" @@ -3707,31 +3719,31 @@ msgstr "" msgid "Invalid data. No valid item id was passed in." msgstr "" -#: includes/wcs-time-functions.php:54 +#: includes/wcs-time-functions.php:55 msgid "%s day" msgid_plural "a %s-day" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:55 +#: includes/wcs-time-functions.php:56 msgid "%s week" msgid_plural "a %s-week" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:56 +#: includes/wcs-time-functions.php:57 msgid "%s month" msgid_plural "a %s-month" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:57 +#: includes/wcs-time-functions.php:58 msgid "%s year" msgid_plural "a %s-year" msgstr[0] "" msgstr[1] "" -#: includes/wcs-user-functions.php:299 +#: includes/wcs-user-functions.php:350 #: templates/single-product/add-to-cart/subscription.php:43 #: templates/single-product/add-to-cart/variable-subscription.php:29 msgid "Resubscribe" @@ -3785,22 +3797,31 @@ msgstr "" msgid "Shipping Tax:" msgstr "" -#: templates/admin/html-variation-price.php:29 +#: templates/admin/html-variation-price.php:31 msgid "Subscription trial period:" msgstr "" -#: templates/admin/html-variation-price.php:47 +#: templates/admin/html-variation-price.php:49 msgid "Billing interval:" msgstr "" -#: templates/admin/html-variation-price.php:54 +#: templates/admin/html-variation-price.php:56 msgid "Billing Period:" msgstr "" -#: templates/admin/status.php:10 +#: templates/admin/status.php:22 msgid "This section shows any information about Subscriptions." msgstr "" +#: templates/admin/status.php:74 +#. translators: %1$s is the file version, %2$s is the core version +msgid "version %1$s is out of date. The core version is %2$s" +msgstr "" + +#: templates/admin/status.php:87 +msgid "Learn how to update" +msgstr "" + #: templates/cart/cart-recurring-shipping.php:19 msgid "Recurring shipping options can be selected on checkout." msgstr "" @@ -3831,8 +3852,8 @@ msgstr "" msgid "Subtotal" msgstr "" -#: templates/checkout/recurring-totals.php:126 -#: templates/checkout/recurring-totals.php:127 +#: templates/checkout/recurring-totals.php:122 +#: templates/checkout/recurring-totals.php:123 msgid "Recurring Total" msgstr "" @@ -4006,7 +4027,7 @@ msgstr "" msgid "Subscription Totals" msgstr "" -#: templates/myaccount/view-subscription.php:110 +#: templates/myaccount/view-subscription.php:111 msgid "Are you sure you want remove this item from your subscription?" msgstr "" @@ -4071,47 +4092,47 @@ msgstr "" msgid "%sAdd a subscription product »%s" msgstr "" -#: woocommerce-subscriptions.php:409 +#: woocommerce-subscriptions.php:410 msgid "" "A subscription renewal has been removed from your cart. Multiple " "subscriptions can not be purchased at the same time." msgstr "" -#: woocommerce-subscriptions.php:415 +#: woocommerce-subscriptions.php:416 msgid "" "A subscription has been removed from your cart. Due to payment gateway " "restrictions, different subscription products can not be purchased at the " "same time." msgstr "" -#: woocommerce-subscriptions.php:421 +#: woocommerce-subscriptions.php:422 msgid "" "A subscription has been removed from your cart. Products and subscriptions " "can not be purchased at the same time." msgstr "" -#: woocommerce-subscriptions.php:558 woocommerce-subscriptions.php:575 +#: woocommerce-subscriptions.php:559 woocommerce-subscriptions.php:576 #. translators: placeholder is a number, this is for the teens #. translators: placeholder is a number, numbers ending in 4-9, 0 msgid "%sth" msgstr "" -#: woocommerce-subscriptions.php:563 +#: woocommerce-subscriptions.php:564 #. translators: placeholder is a number, numbers ending in 1 msgid "%sst" msgstr "" -#: woocommerce-subscriptions.php:567 +#: woocommerce-subscriptions.php:568 #. translators: placeholder is a number, numbers ending in 2 msgid "%snd" msgstr "" -#: woocommerce-subscriptions.php:571 +#: woocommerce-subscriptions.php:572 #. translators: placeholder is a number, numbers ending in 3 msgid "%srd" msgstr "" -#: woocommerce-subscriptions.php:601 +#: woocommerce-subscriptions.php:602 #. translators: 1$-2$: opening and closing tags, 3$-4$: link tags, #. takes to woocommerce plugin on wp.org, 5$-6$: opening and closing link tags, #. leads to plugins.php in admin @@ -4121,7 +4142,7 @@ msgid "" "%5$sinstall & activate WooCommerce »%6$s" msgstr "" -#: woocommerce-subscriptions.php:608 +#: woocommerce-subscriptions.php:609 #. translators: 1$-2$: opening and closing tags, 3$-4$: opening and #. closing link tags, leads to plugin admin msgid "" @@ -4130,11 +4151,11 @@ msgid "" "WooCommerce to version 2.4 or newer »%4$s" msgstr "" -#: woocommerce-subscriptions.php:634 +#: woocommerce-subscriptions.php:635 msgid "Variable Subscription" msgstr "" -#: woocommerce-subscriptions.php:821 +#: woocommerce-subscriptions.php:822 #. translators: 1$-2$: opening and closing tags, 3$-4$: opening and #. closing link tags. Leads to duplicate site article on docs msgid "" @@ -4144,19 +4165,19 @@ msgid "" "environment. %3$sLearn more »%4$s." msgstr "" -#: woocommerce-subscriptions.php:823 +#: woocommerce-subscriptions.php:824 msgid "Quit nagging me (but don't enable automatic payments)" msgstr "" -#: woocommerce-subscriptions.php:824 +#: woocommerce-subscriptions.php:825 msgid "Enable automatic payments" msgstr "" -#: woocommerce-subscriptions.php:1030 +#: woocommerce-subscriptions.php:1031 msgid "Support" msgstr "" -#: woocommerce-subscriptions.php:1135 +#: woocommerce-subscriptions.php:1116 #. translators: placeholders are opening and closing tags. Leads to docs on #. version 2 msgid "" @@ -4167,14 +4188,14 @@ msgid "" "2.0 »%s" msgstr "" -#: woocommerce-subscriptions.php:1150 +#: woocommerce-subscriptions.php:1131 msgid "" "Warning! You are running version %s of WooCommerce Subscriptions plugin " "code but your database has been upgraded to Subscriptions version 2.0. This " "will cause major problems on your store." msgstr "" -#: woocommerce-subscriptions.php:1151 +#: woocommerce-subscriptions.php:1132 msgid "" "Please upgrade the WooCommerce Subscriptions plugin to version 2.0 or newer " "immediately. If you need assistance, after upgrading to Subscriptions v2.0, " @@ -4221,8 +4242,8 @@ msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:247 #: templates/admin/deprecated/html-variation-price.php:31 #: templates/admin/deprecated/html-variation-price.php:86 -#: templates/admin/html-variation-price.php:19 -#: templates/admin/html-variation-price.php:45 +#: templates/admin/html-variation-price.php:21 +#: templates/admin/html-variation-price.php:47 msgctxt "example price" msgid "e.g. 9.90" msgstr "" @@ -4264,29 +4285,34 @@ msgid "suspensions per billing period." msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1411 -#: includes/admin/class-wc-subscriptions-admin.php:1439 +#: includes/admin/class-wc-subscriptions-admin.php:1447 msgctxt "label that indicates whether debugging is turned on for the plugin" msgid "WCS_DEBUG" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1417 -#: includes/admin/class-wc-subscriptions-admin.php:1445 +#: includes/admin/class-wc-subscriptions-admin.php:1453 msgctxt "Live or Staging, Label on WooCommerce -> System Status page" msgid "Subscriptions Mode" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1418 -#: includes/admin/class-wc-subscriptions-admin.php:1446 +#: includes/admin/class-wc-subscriptions-admin.php:1454 msgctxt "refers to staging site" msgid "Staging" msgstr "" #: includes/admin/class-wc-subscriptions-admin.php:1418 -#: includes/admin/class-wc-subscriptions-admin.php:1446 +#: includes/admin/class-wc-subscriptions-admin.php:1454 msgctxt "refers to live site" msgid "Live" msgstr "" +#: includes/admin/class-wc-subscriptions-admin.php:1424 +msgctxt "label for the system status page" +msgid "Subscriptions Template Theme Overrides" +msgstr "" + #: includes/admin/class-wcs-admin-meta-boxes.php:56 msgctxt "meta box title" msgid "Subscription Data" @@ -4297,54 +4323,54 @@ msgctxt "meta box title" msgid "Billing Schedule" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:244 +#: includes/admin/class-wcs-admin-post-types.php:245 msgctxt "an action on a subscription" msgid "Activate" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:245 +#: includes/admin/class-wcs-admin-post-types.php:246 msgctxt "an action on a subscription" msgid "Put on-hold" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:246 -#: includes/admin/class-wcs-admin-post-types.php:459 -#: includes/class-wc-subscriptions-manager.php:1813 -#: includes/wcs-user-functions.php:308 +#: includes/admin/class-wcs-admin-post-types.php:247 +#: includes/admin/class-wcs-admin-post-types.php:460 +#: includes/class-wc-subscriptions-manager.php:1829 +#: includes/wcs-user-functions.php:359 #: templates/myaccount/related-orders.php:67 msgctxt "an action on a subscription" msgid "Cancel" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:321 +#: includes/admin/class-wcs-admin-post-types.php:322 msgctxt "Used in order note. Reason why status changed." msgid "Subscription status changed by bulk edit:" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:417 +#: includes/admin/class-wcs-admin-post-types.php:418 msgctxt "number of orders linked to a subscription" msgid "Orders" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:513 +#: includes/admin/class-wcs-admin-post-types.php:514 msgctxt "meaning billing address" msgid "Billing:" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:551 +#: includes/admin/class-wcs-admin-post-types.php:552 #. translators: $1: is opening link, $2: is subscription order number, $3: is #. closing link tag, $4: is user's name msgctxt "Subscription title on admin table. (e.g.: #211 for John Doe)" msgid "%1$s#%2$s%3$s for %4$s" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:882 +#: includes/admin/class-wcs-admin-post-types.php:883 #. translators: placeholder is previous post title msgctxt "used in post updated messages" msgid "Subscription restored to revision from %s" msgstr "" -#: includes/admin/class-wcs-admin-post-types.php:887 +#: includes/admin/class-wcs-admin-post-types.php:888 msgctxt "used in \"Subscription scheduled for \"" msgid "M j, Y @ G:i" msgstr "" @@ -4392,7 +4418,7 @@ msgctxt "hash before order number" msgid "#%s" msgstr "" -#: includes/class-wcs-query.php:92 +#: includes/class-wcs-query.php:93 msgctxt "hash before order number" msgid "Subscription #%s" msgstr "" @@ -4519,9 +4545,9 @@ msgctxt "the page title of the change payment method form" msgid "Change Payment Method" msgstr "" -#: includes/class-wc-subscriptions-manager.php:84 -#: includes/class-wc-subscriptions-manager.php:1877 -#: includes/class-wc-subscriptions-manager.php:1895 +#: includes/class-wc-subscriptions-manager.php:87 +#: includes/class-wc-subscriptions-manager.php:1893 +#: includes/class-wc-subscriptions-manager.php:1911 msgctxt "used in order note as reason for why subscription status changed" msgid "Subscription renewal payment due:" msgstr "" @@ -4531,37 +4557,37 @@ msgctxt "used in order note as reason for why subscription status changed" msgid "Subscription renewal payment retry:" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1024 wcs-functions.php:209 +#: includes/class-wc-subscriptions-manager.php:1040 wcs-functions.php:209 msgctxt "Subscription status" msgid "Active" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1027 wcs-functions.php:211 +#: includes/class-wc-subscriptions-manager.php:1043 wcs-functions.php:211 msgctxt "Subscription status" msgid "Cancelled" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1030 wcs-functions.php:213 +#: includes/class-wc-subscriptions-manager.php:1046 wcs-functions.php:213 msgctxt "Subscription status" msgid "Expired" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1033 wcs-functions.php:208 +#: includes/class-wc-subscriptions-manager.php:1049 wcs-functions.php:208 msgctxt "Subscription status" msgid "Pending" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1036 +#: includes/class-wc-subscriptions-manager.php:1052 msgctxt "Subscription status" msgid "Failed" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1040 +#: includes/class-wc-subscriptions-manager.php:1056 msgctxt "Subscription status" msgid "On-hold" msgstr "" -#: includes/class-wc-subscriptions-switcher.php:2504 wcs-functions.php:212 +#: includes/class-wc-subscriptions-switcher.php:2511 wcs-functions.php:212 msgctxt "Subscription status" msgid "Switched" msgstr "" @@ -4576,7 +4602,7 @@ msgctxt "Subscription status" msgid "Pending Cancellation" msgstr "" -#: includes/class-wc-subscriptions-manager.php:1790 +#: includes/class-wc-subscriptions-manager.php:1806 #. translators: 1$: month number (e.g. "01"), 2$: month abbreviation (e.g. #. "Jan") msgctxt "used in a select box" @@ -4706,7 +4732,7 @@ msgid "%1$s %2$s(%3$s)%4$s" msgstr "" #: includes/class-wc-subscriptions-switcher.php:1942 -#: includes/class-wc-subscriptions-switcher.php:2280 +#: includes/class-wc-subscriptions-switcher.php:2288 #. translators: 1$: old item, 2$: new item when switching msgctxt "used in order notes" msgid "Customer switched from: %1$s to %2$s." @@ -4732,7 +4758,7 @@ msgstr "" #: includes/class-wc-subscriptions-synchroniser.php:237 #: templates/admin/deprecated/html-variation-synchronisation.php:36 -#: templates/admin/html-variation-synchronisation.php:34 +#: templates/admin/html-variation-synchronisation.php:36 msgctxt "input field placeholder for day field for annual subscriptions" msgid "Day" msgstr "" @@ -4762,7 +4788,7 @@ msgctxt "used in order note" msgid "Customer added \"%1$s\" (Product ID: #%2$d) via the My Account page." msgstr "" -#: includes/class-wcs-remove-item.php:124 +#: includes/class-wcs-remove-item.php:126 #. translators: 1$: product name, 2$: product id msgctxt "used in order note" msgid "Customer removed \"%1$s\" (Product ID: #%2$d) via the My Account page." @@ -4927,12 +4953,12 @@ msgctxt "default email subject for suspended emails sent to the admin" msgid "[%s] Subscription Suspended" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:344 +#: includes/gateways/paypal/class-wcs-paypal.php:350 #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:208 #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:315 #: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:326 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:353 -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:365 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:349 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:361 #: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:144 #: includes/gateways/paypal/includes/class-wcs-paypal-standard-request.php:147 #. translators: placeholder is for blog name @@ -4942,7 +4968,7 @@ msgctxt "" msgid "#" msgstr "" -#: includes/gateways/paypal/class-wcs-paypal.php:556 +#: includes/gateways/paypal/class-wcs-paypal.php:562 msgctxt "" "used in User Agent data sent to PayPal to help identify where a payment " "came from" @@ -4955,7 +4981,7 @@ msgctxt "data sent to paypal" msgid "Orders with %s" msgstr "" -#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:391 +#: includes/gateways/paypal/includes/class-wcs-paypal-reference-transaction-api-request.php:387 #. translators: 1$: new status (e.g. "Cancel"), 2$: blog name msgctxt "data sent to paypal" msgid "%1$s subscription event triggered at %2$s" @@ -5064,7 +5090,7 @@ msgid "" msgstr "" #: includes/upgrades/templates/wcs-about-2-0.php:36 -#: woocommerce-subscriptions.php:1029 +#: woocommerce-subscriptions.php:1030 msgctxt "short for documents" msgid "Docs" msgstr "" @@ -5109,7 +5135,7 @@ msgctxt "shipping method price" msgid "Free" msgstr "" -#: includes/wcs-cart-functions.php:267 +#: includes/wcs-cart-functions.php:271 #. translators: placeholder is price string, denotes tax included in cart/order #. total msgctxt "includes tax" @@ -5177,44 +5203,44 @@ msgid_plural "%s years" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:80 +#: includes/wcs-time-functions.php:82 msgctxt "Subscription length" msgid "Never expire" msgstr "" -#: includes/wcs-time-functions.php:85 +#: includes/wcs-time-functions.php:87 msgctxt "Subscription lengths. e.g. \"For 1 day...\"" msgid "1 day" msgstr "" -#: includes/wcs-time-functions.php:89 +#: includes/wcs-time-functions.php:91 msgctxt "Subscription lengths. e.g. \"For 1 week...\"" msgid "1 week" msgstr "" -#: includes/wcs-time-functions.php:93 +#: includes/wcs-time-functions.php:95 msgctxt "Subscription lengths. e.g. \"For 1 month...\"" msgid "1 month" msgstr "" -#: includes/wcs-time-functions.php:97 +#: includes/wcs-time-functions.php:99 msgctxt "Subscription lengths. e.g. \"For 1 year...\"" msgid "1 year" msgstr "" -#: includes/wcs-time-functions.php:147 +#: includes/wcs-time-functions.php:149 msgctxt "period interval (eg \"$10 _every_ 2 weeks\")" msgid "every" msgstr "" -#: includes/wcs-time-functions.php:151 +#: includes/wcs-time-functions.php:153 #. translators: period interval, placeholder is ordinal (eg "$10 every #. _2nd/3rd/4th_", etc) msgctxt "period interval with ordinal number (e.g. \"every 2nd\"" msgid "every %s" msgstr "" -#: includes/wcs-time-functions.php:175 +#: includes/wcs-time-functions.php:177 msgctxt "" "Used in the trial period dropdown. Number is in text field. 0, 2+ will need " "plural, 1 will need singular." @@ -5223,7 +5249,7 @@ msgid_plural "days" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:176 +#: includes/wcs-time-functions.php:178 msgctxt "" "Used in the trial period dropdown. Number is in text field. 0, 2+ will need " "plural, 1 will need singular." @@ -5232,7 +5258,7 @@ msgid_plural "weeks" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:177 +#: includes/wcs-time-functions.php:179 msgctxt "" "Used in the trial period dropdown. Number is in text field. 0, 2+ will need " "plural, 1 will need singular." @@ -5241,7 +5267,7 @@ msgid_plural "months" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:178 +#: includes/wcs-time-functions.php:180 msgctxt "" "Used in the trial period dropdown. Number is in text field. 0, 2+ will need " "plural, 1 will need singular." @@ -5250,7 +5276,7 @@ msgid_plural "years" msgstr[0] "" msgstr[1] "" -#: includes/wcs-time-functions.php:196 +#: includes/wcs-time-functions.php:198 msgctxt "no trial period" msgid "no" msgstr "" @@ -5268,7 +5294,7 @@ msgid "e.g. 3" msgstr "" #: templates/admin/deprecated/html-variation-price.php:118 -#: templates/admin/html-variation-price.php:25 +#: templates/admin/html-variation-price.php:27 #. translators: placeholder is trial period validation message if passed an #. invalid value (e.g. "Trial period can not exceed 4 weeks") msgctxt "Trial period dropdown's description in pricing fields" @@ -5278,7 +5304,7 @@ msgid "" "subscription. %s" msgstr "" -#: templates/admin/html-variation-price.php:65 +#: templates/admin/html-variation-price.php:67 msgctxt "Subscription Length dropdown's description in pricing fields" msgid "" "Automatically expire the subscription after this length of time. This " diff --git a/templates/admin/html-variation-price.php b/templates/admin/html-variation-price.php index 79f304e..a860283 100644 --- a/templates/admin/html-variation-price.php +++ b/templates/admin/html-variation-price.php @@ -2,6 +2,8 @@ /** * Outputs a subscription variation's pricing fields for WooCommerce 2.3+ * + * @version 2.2.12 + * * @var int $loop * @var WP_POST $variation * @var WC_Product_Subscription_Variation $variation_product @@ -61,7 +63,7 @@ if ( ! defined( 'ABSPATH' ) ) {