mirror of
https://github.com/pronamic/woocommerce-subscriptions.git
synced 2025-10-17 14:52:56 +00:00
Updates to 7.3.0
This commit is contained in:
@@ -1,5 +1,27 @@
|
||||
*** WooCommerce Subscriptions Changelog ***
|
||||
|
||||
2025-03-24 - version 7.3.0
|
||||
* Tweak: Adjust the warning that appears on the reports page when HPOS is enabled but Compatibility Mode is disabled (provide a direct link to the relevant settings).
|
||||
* Update: Improved subscription search performance for WP Post stores by removing unnecessary _order_key and _billing_email meta queries.
|
||||
* Update: Make it possible to dispatch the Cancelled Subscription email more than once (when initially set to pending-cancellation, and again when it reaches final cancellation).
|
||||
* Update: Reduced duplicate queries when fetching multiple subscription related orders types.
|
||||
* Update: Removed unnecessary get_time() calls to reduce redundant get_last_order() queries in the Subscriptions list table.
|
||||
* Update: Improved performance on the Orders list table when rendering the Subscription Relationship column.
|
||||
* Update: Improved performance of the Generate Related Order Cache tool found under WooCommerce > Status > Tools.
|
||||
* Fix: Do not schedule updates to the report data cache if reporting is not available (ie, if HPOS is enabled but Compatibility Mode is not).
|
||||
* Fix: Resolved deprecated dynamic property warnings in WCS_Email_Payment_Retry and WCS_Email_Customer_Payment_Retry.
|
||||
* Fix: Added support for previewing payment retry emails in WooCommerce email settings.
|
||||
* Fix: Updated subscription email item table template to align with WooCommerce 9.7 email improvements.
|
||||
* Fix: Prevent PHP warning on cart page shipping method updates by removing unused method: maybe_restore_shipping_methods.
|
||||
* Fix: Removed unnecessary setting of renewal order paid date on status transition, relying on WooCommerce core behavior instead.
|
||||
* Fix: Ensure the order_awaiting_payment session arg is restored when loading a renewal cart from the session to prevent duplicate orders.
|
||||
* Fix: Ensure custom placeholders (time_until_renewal, customers_first_name) are included in customer notification email previews.
|
||||
* Fix: For stores with HPOS + compatibility mode enabled, using the bulk delete related orders cache tool was not correctly deleting the meta from the WP Posts table.
|
||||
* Fix: Prevent empty strings being saved in related orders cache ID meta when backfilling order data to the WP Posts table.
|
||||
* Fix: Correctly load product names with HTML on the cart and checkout shipping rates.
|
||||
* Dev: Fix Node version mismatch between package.json and .nvmrc (both are now set to v16.17.1).
|
||||
* Dev: Update subscriptions-core to 8.1.0
|
||||
|
||||
2025-02-13 - version 7.2.1
|
||||
* Fix: Revert a change released in 7.2.0 which triggered the "woocommerce_cart_item_name" filter with the wrong number of parameters.
|
||||
* Dev: Update subscriptions-core to 8.0.1.
|
||||
|
@@ -57,10 +57,10 @@ class WCS_Admin_Reports {
|
||||
'<p><strong>%s</strong></p><p>%s</p>',
|
||||
_x( 'WooCommerce Subscriptions - Reports Not Available', 'heading used in an admin notice', 'woocommerce-subscriptions' ),
|
||||
sprintf(
|
||||
// translators: placeholders $1 and $2 are opening <a> tags linking to the WooCommerce documentation on HPOS and data synchronization. Placeholder $3 is a closing link (<a>) tag.
|
||||
__( 'Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please enable %2$stable synchronization%3$s if you wish to use subscription reports.', 'woocommerce-subscriptions' ),
|
||||
// translators: placeholders $1 and $2 are opening <a> tags linking to the WooCommerce documentation on HPOS, and to the Advanced Feature settings screen. Placeholder $3 is a closing link (<a>) tag.
|
||||
__( 'Subscription reports are incompatible with the %1$sWooCommerce data storage features%3$s enabled on your store. Please %2$senable compatibility mode%3$s if you wish to use subscription reports.', 'woocommerce-subscriptions' ),
|
||||
'<a href="https://woocommerce.com/document/high-performance-order-storage/">',
|
||||
'<a href="https://woocommerce.com/document/high-performance-order-storage/#synchronization">',
|
||||
'<a href="' . esc_url( get_admin_url( null, 'admin.php?page=wc-settings&tab=advanced§ion=features' ) ) . '">',
|
||||
'</a>'
|
||||
)
|
||||
)
|
||||
|
@@ -78,6 +78,11 @@ class WCS_Report_Cache_Manager {
|
||||
* @since 2.1
|
||||
*/
|
||||
public function __construct() {
|
||||
// Our reports integration does not work if A) HPOS is enabled and B) compatibility mode is disabled.
|
||||
// In these cases, there is no reason to cache report data/to update data that was already cached.
|
||||
if ( wcs_is_custom_order_tables_usage_enabled() && ! wcs_is_custom_order_tables_data_sync_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use the old hooks
|
||||
if ( wcs_is_woocommerce_pre( '3.0' ) ) {
|
||||
|
@@ -54,7 +54,7 @@ class WC_REST_Subscription_System_Status_Manager {
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public static function add_subscription_fields_to_response( $response ) {
|
||||
$count_by_status = array_filter( (array) WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status() );
|
||||
$count_by_status = WCS_Admin_System_Status::get_subscription_status_counts();
|
||||
|
||||
$response->data['subscriptions'] = array(
|
||||
'wcs_debug' => defined( 'WCS_DEBUG' ) ? WCS_DEBUG : false,
|
||||
|
@@ -15,6 +15,13 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
class WCS_Email_Customer_Payment_Retry extends WCS_Email_Customer_Renewal_Invoice {
|
||||
|
||||
/**
|
||||
* The retry object.
|
||||
*
|
||||
* @var WCS_Retry
|
||||
*/
|
||||
public $retry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@@ -18,6 +18,13 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
class WCS_Email_Payment_Retry extends WC_Email_Failed_Order {
|
||||
|
||||
/**
|
||||
* The retry object associated with the order.
|
||||
*
|
||||
* @var WCS_Retry
|
||||
*/
|
||||
public $retry;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
File diff suppressed because it is too large
Load Diff
2
vendor/autoload.php
vendored
2
vendor/autoload.php
vendored
@@ -22,4 +22,4 @@ if (PHP_VERSION_ID < 50600) {
|
||||
|
||||
require_once __DIR__ . '/composer/autoload_real.php';
|
||||
|
||||
return ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d::getLoader();
|
||||
return ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1::getLoader();
|
||||
|
27
vendor/composer/InstalledVersions.php
vendored
27
vendor/composer/InstalledVersions.php
vendored
@@ -32,6 +32,11 @@ class InstalledVersions
|
||||
*/
|
||||
private static $installed;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static $installedIsLocalDir;
|
||||
|
||||
/**
|
||||
* @var bool|null
|
||||
*/
|
||||
@@ -309,6 +314,12 @@ class InstalledVersions
|
||||
{
|
||||
self::$installed = $data;
|
||||
self::$installedByVendor = array();
|
||||
|
||||
// when using reload, we disable the duplicate protection to ensure that self::$installed data is
|
||||
// always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not,
|
||||
// so we have to assume it does not, and that may result in duplicate data being returned when listing
|
||||
// all installed packages for example
|
||||
self::$installedIsLocalDir = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -322,19 +333,27 @@ class InstalledVersions
|
||||
}
|
||||
|
||||
$installed = array();
|
||||
$copiedLocalDir = false;
|
||||
|
||||
if (self::$canGetVendors) {
|
||||
$selfDir = strtr(__DIR__, '\\', '/');
|
||||
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
|
||||
$vendorDir = strtr($vendorDir, '\\', '/');
|
||||
if (isset(self::$installedByVendor[$vendorDir])) {
|
||||
$installed[] = self::$installedByVendor[$vendorDir];
|
||||
} elseif (is_file($vendorDir.'/composer/installed.php')) {
|
||||
/** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */
|
||||
$required = require $vendorDir.'/composer/installed.php';
|
||||
$installed[] = self::$installedByVendor[$vendorDir] = $required;
|
||||
if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) {
|
||||
self::$installed = $installed[count($installed) - 1];
|
||||
self::$installedByVendor[$vendorDir] = $required;
|
||||
$installed[] = $required;
|
||||
if (self::$installed === null && $vendorDir.'/composer' === $selfDir) {
|
||||
self::$installed = $required;
|
||||
self::$installedIsLocalDir = true;
|
||||
}
|
||||
}
|
||||
if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) {
|
||||
$copiedLocalDir = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,7 +369,7 @@ class InstalledVersions
|
||||
}
|
||||
}
|
||||
|
||||
if (self::$installed !== array()) {
|
||||
if (self::$installed !== array() && !$copiedLocalDir) {
|
||||
$installed[] = self::$installed;
|
||||
}
|
||||
|
||||
|
8
vendor/composer/autoload_real.php
vendored
8
vendor/composer/autoload_real.php
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
// autoload_real.php @generated by Composer
|
||||
|
||||
class ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d
|
||||
class ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1
|
||||
{
|
||||
private static $loader;
|
||||
|
||||
@@ -24,12 +24,12 @@ class ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d
|
||||
|
||||
require __DIR__ . '/platform_check.php';
|
||||
|
||||
spl_autoload_register(array('ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d', 'loadClassLoader'), true, true);
|
||||
spl_autoload_register(array('ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1', 'loadClassLoader'), true, true);
|
||||
self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit0c80b12786c5f329cae617490ce0ac6d', 'loadClassLoader'));
|
||||
spl_autoload_unregister(array('ComposerAutoloaderInit2b7b846857cbbe9f2e962ff7f867dff1', 'loadClassLoader'));
|
||||
|
||||
require __DIR__ . '/autoload_static.php';
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::getInitializer($loader));
|
||||
call_user_func(\Composer\Autoload\ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::getInitializer($loader));
|
||||
|
||||
$loader->register(true);
|
||||
|
||||
|
8
vendor/composer/autoload_static.php
vendored
8
vendor/composer/autoload_static.php
vendored
@@ -4,7 +4,7 @@
|
||||
|
||||
namespace Composer\Autoload;
|
||||
|
||||
class ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d
|
||||
class ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1
|
||||
{
|
||||
public static $prefixLengthsPsr4 = array (
|
||||
'C' =>
|
||||
@@ -126,9 +126,9 @@ class ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d
|
||||
public static function getInitializer(ClassLoader $loader)
|
||||
{
|
||||
return \Closure::bind(function () use ($loader) {
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit0c80b12786c5f329cae617490ce0ac6d::$classMap;
|
||||
$loader->prefixLengthsPsr4 = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$prefixLengthsPsr4;
|
||||
$loader->prefixDirsPsr4 = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$prefixDirsPsr4;
|
||||
$loader->classMap = ComposerStaticInit2b7b846857cbbe9f2e962ff7f867dff1::$classMap;
|
||||
|
||||
}, null, ClassLoader::class);
|
||||
}
|
||||
|
14
vendor/composer/installed.json
vendored
14
vendor/composer/installed.json
vendored
@@ -151,17 +151,17 @@
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/subscriptions-core",
|
||||
"version": "8.0.1",
|
||||
"version_normalized": "8.0.1.0",
|
||||
"version": "8.1.0",
|
||||
"version_normalized": "8.1.0.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Automattic/woocommerce-subscriptions-core.git",
|
||||
"reference": "554c03a5e7591c448d495ee41ee12015f65cad5a"
|
||||
"reference": "e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/554c03a5e7591c448d495ee41ee12015f65cad5a",
|
||||
"reference": "554c03a5e7591c448d495ee41ee12015f65cad5a",
|
||||
"url": "https://api.github.com/repos/Automattic/woocommerce-subscriptions-core/zipball/e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c",
|
||||
"reference": "e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -174,7 +174,7 @@
|
||||
"woocommerce/woocommerce-sniffs": "0.1.0",
|
||||
"yoast/phpunit-polyfills": "1.1.0"
|
||||
},
|
||||
"time": "2025-02-13T10:49:47+00:00",
|
||||
"time": "2025-03-24T00:03:20+00:00",
|
||||
"type": "wordpress-plugin",
|
||||
"extra": {
|
||||
"phpcodesniffer-search-depth": 2
|
||||
@@ -204,7 +204,7 @@
|
||||
"description": "Sell products and services with recurring payments in your WooCommerce Store.",
|
||||
"homepage": "https://github.com/Automattic/woocommerce-subscriptions-core",
|
||||
"support": {
|
||||
"source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/8.0.1",
|
||||
"source": "https://github.com/Automattic/woocommerce-subscriptions-core/tree/8.1.0",
|
||||
"issues": "https://github.com/Automattic/woocommerce-subscriptions-core/issues"
|
||||
},
|
||||
"install-path": "../woocommerce/subscriptions-core"
|
||||
|
18
vendor/composer/installed.php
vendored
18
vendor/composer/installed.php
vendored
@@ -1,9 +1,9 @@
|
||||
<?php return array(
|
||||
'root' => array(
|
||||
'name' => 'woocommerce/woocommerce-subscriptions',
|
||||
'pretty_version' => 'dev-release/7.2.1',
|
||||
'version' => 'dev-release/7.2.1',
|
||||
'reference' => 'c1ca6ecf1cb1adeb0725e3d5ad543424e73b041e',
|
||||
'pretty_version' => 'dev-release/7.3.0',
|
||||
'version' => 'dev-release/7.3.0',
|
||||
'reference' => 'ef3998fdc41ca6a6013d950438fd9a34a3204a06',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
@@ -20,18 +20,18 @@
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'woocommerce/subscriptions-core' => array(
|
||||
'pretty_version' => '8.0.1',
|
||||
'version' => '8.0.1.0',
|
||||
'reference' => '554c03a5e7591c448d495ee41ee12015f65cad5a',
|
||||
'pretty_version' => '8.1.0',
|
||||
'version' => '8.1.0.0',
|
||||
'reference' => 'e12381a3ac3cde2ad2ff2e762a0e28c3bee02e5c',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../woocommerce/subscriptions-core',
|
||||
'aliases' => array(),
|
||||
'dev_requirement' => false,
|
||||
),
|
||||
'woocommerce/woocommerce-subscriptions' => array(
|
||||
'pretty_version' => 'dev-release/7.2.1',
|
||||
'version' => 'dev-release/7.2.1',
|
||||
'reference' => 'c1ca6ecf1cb1adeb0725e3d5ad543424e73b041e',
|
||||
'pretty_version' => 'dev-release/7.3.0',
|
||||
'version' => 'dev-release/7.3.0',
|
||||
'reference' => 'ef3998fdc41ca6a6013d950438fd9a34a3204a06',
|
||||
'type' => 'wordpress-plugin',
|
||||
'install_path' => __DIR__ . '/../../',
|
||||
'aliases' => array(),
|
||||
|
2
vendor/woocommerce/subscriptions-core/.nvmrc
vendored
2
vendor/woocommerce/subscriptions-core/.nvmrc
vendored
@@ -1 +1 @@
|
||||
lts/*
|
||||
16.17.1
|
||||
|
@@ -1,6 +1,15 @@
|
||||
jQuery( function ( $ ) {
|
||||
let observer = null;
|
||||
|
||||
if ( arePointersEnabled() ) {
|
||||
setTimeout( showSubscriptionPointers, 800 ); // give TinyMCE a chance to finish loading
|
||||
observer = new MutationObserver( showSubscriptionPointers );
|
||||
|
||||
observer.observe( document.getElementById( 'poststuff' ), {
|
||||
attributes: true,
|
||||
childList: true,
|
||||
characterData: false,
|
||||
subtree:true,
|
||||
} );
|
||||
}
|
||||
|
||||
$( 'select#product-type' ).on( 'change', function () {
|
||||
@@ -62,5 +71,9 @@ jQuery( function ( $ ) {
|
||||
pointer: 'wcs_pointer',
|
||||
action: 'dismiss-wp-pointer',
|
||||
} );
|
||||
|
||||
if ( observer ) {
|
||||
observer.disconnect();
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
@@ -1,5 +1,23 @@
|
||||
*** WooCommerce Subscriptions Core Changelog ***
|
||||
|
||||
= 8.1.0 - 2025-03-24 =
|
||||
* Update - Improved subscription search performance for WP Post stores by removing unnecessary _order_key and _billing_email meta queries.
|
||||
* Update - Make it possible to dispatch the Cancelled Subscription email more than once (when initially set to pending-cancellation, and again when it reaches final cancellation).
|
||||
* Update - Reduced duplicate queries when fetching multiple subscription related orders types.
|
||||
* Update - Removed unnecessary get_time() calls to reduce redundant get_last_order() queries in the Subscriptions list table.
|
||||
* Update - Improved performance on the Orders list table when rendering the Subscription Relationship column.
|
||||
* Update - Improved performance of the Generate Related Order Cache tool found under WooCommerce > Status > Tools.
|
||||
* Fix - Added support for previewing payment retry emails in WooCommerce email settings.
|
||||
* Fix - Updated subscription email item table template to align with WooCommerce 9.7 email improvements.
|
||||
* Fix - Prevent PHP warning on cart page shipping method updates by removing unused method: maybe_restore_shipping_methods.
|
||||
* Fix - Removed unnecessary setting of renewal order paid date on status transition, relying on WooCommerce core behavior instead.
|
||||
* Fix - Ensure the order_awaiting_payment session arg is restored when loading a renewal cart from the session to prevent duplicate orders.
|
||||
* Fix - Ensure custom placeholders (time_until_renewal, customers_first_name) are included in customer notification email previews.
|
||||
* Fix - For stores with HPOS + compatibility mode enabled, using the bulk delete related orders cache tool was not correctly deleting the meta from the WP Posts table.
|
||||
* Fix - Prevent empty strings being saved in related orders cache ID meta when backfilling order data to the WP Posts table.
|
||||
* Fix - Correctly load product names with HTML on the cart and checkout shipping rates.
|
||||
* Dev - Fix Node version mismatch between package.json and .nvmrc (both are now set to v16.17.1).
|
||||
|
||||
= 8.0.1 - 2025-02-13 =
|
||||
* Fix - Revert a change released in 7.2.0 which triggered the "woocommerce_cart_item_name" filter with the wrong number of parameters.
|
||||
|
||||
@@ -13,6 +31,7 @@
|
||||
* Fix - After enabling the Customer Notification feature or changing the reminder timer setting, ensure notification emails are scheduled for subscriptions with pending cancellation status.
|
||||
* Update - Include subscription items table in all customer notification emails.
|
||||
* Update - Subscription notes for unsent customer notification emails now only occurs if WCS_DEBUG is enabled.
|
||||
* Update - Improved performance of Subscriptions-related aspects of the WooCommerce System Status Report.
|
||||
* Dev - Introduces a new `woocommerce_subscription_valid_customer_notification_types` filter to modify which notification types are scheduled in Action Scheduler.
|
||||
|
||||
= 7.9.0 - 2025-01-10 =
|
||||
|
@@ -148,4 +148,22 @@ abstract class WCS_Related_Order_Store {
|
||||
throw new InvalidArgumentException( sprintf( __( 'Invalid relation type: %1$s. Order relationship type must be one of: %2$s.', 'woocommerce-subscriptions' ), $relation_type, implode( ', ', $this->get_relation_types() ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get related order IDs grouped by relation type.
|
||||
*
|
||||
* @param WC_Order $subscription The subscription to find related orders.
|
||||
* @param array $relation_type An array of relation types to fetch. Must be an array containing 'renewal', 'switch' or 'resubscribe' unless custom relationships are implemented.
|
||||
*
|
||||
* @return array An associative array where keys are relation types and values are arrays of related order IDs.
|
||||
*/
|
||||
public function get_related_order_ids_by_types( WC_Order $subscription, $relation_types ) {
|
||||
$related_orders = [];
|
||||
|
||||
foreach ( $relation_types as $relation_type ) {
|
||||
$related_orders[ $relation_type ] = $this->get_related_order_ids( $subscription, $relation_type );
|
||||
}
|
||||
|
||||
return $related_orders;
|
||||
}
|
||||
}
|
||||
|
@@ -684,16 +684,17 @@ class WCS_Admin_Post_Types {
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||
*/
|
||||
public static function get_date_column_content( $subscription, $column ) {
|
||||
|
||||
$date_type_map = array( 'last_payment_date' => 'last_order_date_created' );
|
||||
$date_type = array_key_exists( $column, $date_type_map ) ? $date_type_map[ $column ] : $column;
|
||||
$datetime = wcs_get_datetime_from( $subscription->get_time( $date_type ) );
|
||||
$date_timestamp = $subscription->get_time( $date_type );
|
||||
|
||||
if ( 0 == $subscription->get_time( $date_type, 'gmt' ) ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
$column_content = '-';
|
||||
} else {
|
||||
if ( 0 === $date_timestamp ) {
|
||||
return '-';
|
||||
}
|
||||
|
||||
$datetime = wcs_get_datetime_from( $date_timestamp );
|
||||
$accurate_date = $datetime->date_i18n( __( 'Y/m/d g:i:s A', 'woocommerce-subscriptions' ) );
|
||||
$fuzzy_human_date = $subscription->get_date_to_display( $date_type );
|
||||
$fuzzy_human_date = $subscription->format_date_to_display( $date_timestamp, $date_type );
|
||||
$column_content = sprintf(
|
||||
'<time class="%s" title="%s">%s</time>',
|
||||
esc_attr( $column ),
|
||||
@@ -702,18 +703,16 @@ class WCS_Admin_Post_Types {
|
||||
);
|
||||
|
||||
// Custom handling for `Next payment` date column.
|
||||
if ( 'next_payment_date' === $column ) {
|
||||
$subscription_is_active = $subscription->has_status( 'active' );
|
||||
|
||||
if ( 'next_payment_date' === $column && $subscription->has_status( 'active' ) ) {
|
||||
$tooltip_message = '';
|
||||
$tooltip_classes = 'woocommerce-help-tip';
|
||||
|
||||
if ( $subscription_is_active && $datetime->getTimestamp() < time() ) {
|
||||
if ( $datetime->getTimestamp() < time() ) {
|
||||
$tooltip_message .= __( '<b>Subscription payment overdue.</b></br>', 'woocommerce-subscriptions' );
|
||||
$tooltip_classes .= ' wcs-payment-overdue';
|
||||
}
|
||||
|
||||
if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && ! $subscription->is_manual() && $subscription_is_active ) {
|
||||
if ( $subscription->payment_method_supports( 'gateway_scheduled_payments' ) && ! $subscription->is_manual() ) {
|
||||
$tooltip_message .= __( 'This date should be treated as an estimate only. The payment gateway for this subscription controls when payments are processed.</br>', 'woocommerce-subscriptions' );
|
||||
$tooltip_classes .= ' wcs-offsite-renewal';
|
||||
}
|
||||
@@ -722,7 +721,6 @@ class WCS_Admin_Post_Types {
|
||||
$column_content .= '<div class="' . esc_attr( $tooltip_classes ) . '" data-tip="' . esc_attr( $tooltip_message ) . '"></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $column_content;
|
||||
}
|
||||
|
@@ -16,6 +16,35 @@ class WCS_Admin_System_Status {
|
||||
*/
|
||||
const WCS_PRODUCT_ID = 27147;
|
||||
|
||||
/**
|
||||
* Contains pre-determined SSR report data.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $report_data = [];
|
||||
|
||||
/**
|
||||
* Used to cache the result of the comparatively expensive queries executed by
|
||||
* the get_subscriptions_by_gateway() method.
|
||||
*
|
||||
* This cache is short-lived by design, as we don't necessarily want to cache this
|
||||
* across requests (in some troubleshooting/debug scenarios, that could be confusing
|
||||
* for the troubleshooter), which is why a transient or WP caching functions are not
|
||||
* used.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
private static $statuses_by_gateway = null;
|
||||
|
||||
/**
|
||||
* Used to cache the subscriptions-by-status counts.
|
||||
*
|
||||
* As with with self::$statuses_by_gateway, the cache is deliberately short-lived.
|
||||
*
|
||||
* @var null|array
|
||||
*/
|
||||
private static $subscription_status_counts = null;
|
||||
|
||||
/**
|
||||
* Attach callbacks
|
||||
*
|
||||
@@ -28,9 +57,21 @@ class WCS_Admin_System_Status {
|
||||
/**
|
||||
* Renders the Subscription information in the WC status page
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||
* @since 1.0.0 Migrated from WooCommerce Subscriptions v2.3.0
|
||||
* @since 7.2.0 Uses supplied report data if available.
|
||||
*
|
||||
* @param mixed $report Pre-determined SSR report data.
|
||||
*/
|
||||
public static function render_system_status_items() {
|
||||
public static function render_system_status_items( $report = null ) {
|
||||
/**
|
||||
* From WooCommerce 9.8.0, we will be supplied with SSR data fetched via a (programmatic)
|
||||
* REST API request. Using this when available can help prevent duplicated work.
|
||||
*
|
||||
* @see WC_REST_Subscription_System_Status_Manager::add_subscription_fields_to_response()
|
||||
*/
|
||||
if ( is_array( $report ) && is_array( $report['subscriptions'] ) && ! empty( $report['subscriptions'] ) ) {
|
||||
self::$report_data = $report['subscriptions'];
|
||||
}
|
||||
|
||||
$store_data = [];
|
||||
$subscriptions_data = [];
|
||||
@@ -118,10 +159,15 @@ class WCS_Admin_System_Status {
|
||||
* @param array $debug_data
|
||||
*/
|
||||
private static function set_live_site_url( &$debug_data ) {
|
||||
// Use pre-determined SSR data if possible.
|
||||
$site_url = isset( self::$report_data['live_url'] )
|
||||
? self::$report_data['live_url']
|
||||
: WCS_Staging::get_site_url_from_source( 'subscriptions_install' );
|
||||
|
||||
$debug_data['wcs_live_site_url'] = array(
|
||||
'name' => _x( 'Subscriptions Live URL', 'Live URL, Label on WooCommerce -> System Status page', 'woocommerce-subscriptions' ),
|
||||
'label' => 'Subscriptions Live URL',
|
||||
'note' => '<a href="' . esc_url( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ) . '">' . esc_html( WCS_Staging::get_site_url_from_source( 'subscriptions_install' ) ) . '</a>',
|
||||
'note' => '<a href="' . esc_url( $site_url ) . '">' . esc_html( $site_url ) . '</a>',
|
||||
'mark' => '',
|
||||
'mark_icon' => '',
|
||||
);
|
||||
@@ -222,7 +268,6 @@ class WCS_Admin_System_Status {
|
||||
* Add a breakdown of Subscriptions per status.
|
||||
*/
|
||||
private static function set_subscription_statuses( &$debug_data ) {
|
||||
|
||||
$debug_data['wcs_subscriptions_by_status'] = array(
|
||||
'name' => _x( 'Subscription Statuses', 'label for the system status page', 'woocommerce-subscriptions' ),
|
||||
'label' => 'Subscription Statuses',
|
||||
@@ -281,7 +326,11 @@ class WCS_Admin_System_Status {
|
||||
private static function set_subscriptions_by_payment_gateway( &$debug_data ) {
|
||||
$gateways = WC()->payment_gateways->get_available_payment_gateways();
|
||||
|
||||
foreach ( self::get_subscriptions_by_gateway() as $payment_method => $status_counts ) {
|
||||
$subscriptions_by_gateway = isset( self::$report_data['subscriptions_by_payment_gateway'] )
|
||||
? self::$report_data['subscriptions_by_payment_gateway']
|
||||
: self::get_subscriptions_by_gateway();
|
||||
|
||||
foreach ( $subscriptions_by_gateway as $payment_method => $status_counts ) {
|
||||
if ( isset( $gateways[ $payment_method ] ) ) {
|
||||
$payment_method_name = $gateways[ $payment_method ]->method_title;
|
||||
$payment_method_label = $gateways[ $payment_method ]->method_title;
|
||||
@@ -361,10 +410,17 @@ class WCS_Admin_System_Status {
|
||||
/**
|
||||
* Gets the store's subscription broken down by payment gateway and status.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v3.1.0
|
||||
* @since 1.0.0 Migrated from WooCommerce Subscriptions v3.1.0.
|
||||
* @since 7.2.0 Information is cached per request.
|
||||
*
|
||||
* @return array The subscription gateway and status data array( 'gateway_id' => array( 'status' => count ) );
|
||||
*/
|
||||
public static function get_subscriptions_by_gateway() {
|
||||
// Return cached result if possible.
|
||||
if ( isset( self::$statuses_by_gateway ) ) {
|
||||
return self::$statuses_by_gateway;
|
||||
}
|
||||
|
||||
global $wpdb;
|
||||
$subscription_gateway_data = [];
|
||||
$is_hpos_in_use = wcs_is_custom_order_tables_usage_enabled();
|
||||
@@ -408,6 +464,7 @@ class WCS_Admin_System_Status {
|
||||
$subscription_gateway_data[ $result['payment_method'] ][ $result[ $order_status_column_name ] ] = $result['count'];
|
||||
}
|
||||
|
||||
self::$statuses_by_gateway = $subscription_gateway_data;
|
||||
return $subscription_gateway_data;
|
||||
}
|
||||
|
||||
@@ -418,7 +475,9 @@ class WCS_Admin_System_Status {
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscription_statuses() {
|
||||
$subscriptions_by_status = WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status();
|
||||
// We don't look inside self::$report_data here, because the REST API report itself
|
||||
// also uses self::get_subscription_status_counts().
|
||||
$subscriptions_by_status = self::get_subscription_status_counts();
|
||||
$subscriptions_by_status_output = array();
|
||||
|
||||
foreach ( $subscriptions_by_status as $status => $count ) {
|
||||
@@ -429,4 +488,36 @@ class WCS_Admin_System_Status {
|
||||
|
||||
return $subscriptions_by_status_output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cached array of subscription statuses along with the corresponding number
|
||||
* of subscriptions for each (the values).
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* [
|
||||
* 'wc-active' => 100,
|
||||
* 'wc-cancelled' => 200,
|
||||
* '...' => 300,
|
||||
* ]
|
||||
*
|
||||
* @param bool $fresh If cached results should be discarded.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscription_status_counts( bool $fresh = false ): array {
|
||||
// Return cached result if possible.
|
||||
if ( ! $fresh && isset( self::$subscription_status_counts ) ) {
|
||||
return self::$subscription_status_counts;
|
||||
}
|
||||
|
||||
try {
|
||||
self::$subscription_status_counts = WC_Data_Store::load( 'subscription' )->get_subscriptions_count_by_status();
|
||||
} catch ( Exception $e ) {
|
||||
// If an exception was raised, don't cache the result.
|
||||
return [];
|
||||
}
|
||||
|
||||
return self::$subscription_status_counts;
|
||||
}
|
||||
}
|
||||
|
@@ -1295,18 +1295,29 @@ class WC_Subscription extends WC_Order {
|
||||
* @param string $date_type 'date_created', 'trial_end', 'next_payment', 'last_order_date_created', 'end' or 'end_of_prepaid_term'
|
||||
*/
|
||||
public function get_date_to_display( $date_type = 'next_payment' ) {
|
||||
|
||||
$date_type = wcs_normalise_date_type_key( $date_type, true );
|
||||
|
||||
$timestamp_gmt = $this->get_time( $date_type, 'gmt' );
|
||||
|
||||
return $this->format_date_to_display( $timestamp_gmt, $date_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats a subscription date timestamp for display.
|
||||
*
|
||||
* @param int $timestamp The subscription date in a timestamp format.
|
||||
* @param string $date_type The subscription date type to display. @see WC_Subscription::get_valid_date_types()
|
||||
*
|
||||
* @return string The formatted date to display.
|
||||
*/
|
||||
public function format_date_to_display( $timestamp_gmt, $date_type ) {
|
||||
$date_type = wcs_normalise_date_type_key( $date_type, true );
|
||||
|
||||
// Don't display next payment date when the subscription is inactive
|
||||
if ( 'next_payment' == $date_type && ! $this->has_status( 'active' ) ) {
|
||||
if ( 'next_payment' === $date_type && ! $this->has_status( 'active' ) ) {
|
||||
$timestamp_gmt = 0;
|
||||
}
|
||||
|
||||
if ( $timestamp_gmt > 0 ) {
|
||||
|
||||
$time_diff = $timestamp_gmt - current_time( 'timestamp', true );
|
||||
|
||||
if ( $time_diff > 0 && $time_diff < WEEK_IN_SECONDS ) {
|
||||
@@ -1316,7 +1327,7 @@ class WC_Subscription extends WC_Order {
|
||||
// translators: placeholder is human time diff (e.g. "3 weeks")
|
||||
$date_to_display = sprintf( __( '%s ago', 'woocommerce-subscriptions' ), human_time_diff( current_time( 'timestamp', true ), $timestamp_gmt ) );
|
||||
} else {
|
||||
$date_to_display = date_i18n( wc_date_format(), $this->get_time( $date_type, 'site' ) );
|
||||
$date_to_display = date_i18n( wc_date_format(), $timestamp_gmt + wc_timezone_offset() );
|
||||
}
|
||||
} else {
|
||||
switch ( $date_type ) {
|
||||
@@ -2074,25 +2085,31 @@ class WC_Subscription extends WC_Order {
|
||||
* @return array
|
||||
*/
|
||||
public function get_related_orders( $return_fields = 'ids', $order_types = array( 'parent', 'renewal', 'switch' ) ) {
|
||||
|
||||
$return_fields = ( 'ids' == $return_fields ) ? $return_fields : 'all';
|
||||
$return_fields = ( 'ids' === $return_fields ) ? $return_fields : 'all';
|
||||
$related_orders = [];
|
||||
|
||||
if ( 'all' === $order_types ) {
|
||||
wcs_deprecated_argument( __METHOD__, '2.3.0', sprintf( __( 'The "all" value for $order_type parameter is deprecated. It was a misnomer, as it did not return resubscribe orders. It was also inconsistent with order type values accepted by wcs_get_subscription_orders(). Use array( "parent", "renewal", "switch" ) to maintain previous behaviour, or "any" to receive all order types, including switch and resubscribe.', 'woocommerce-subscriptions' ), __CLASS__ ) );
|
||||
$order_types = array( 'parent', 'renewal', 'switch' );
|
||||
} elseif ( ! is_array( $order_types ) ) {
|
||||
// Accept either an array or string (to make it more convenient for singular types, like 'parent' or 'any')
|
||||
// Accept either an array or string (to make it more convenient for singular types, like 'parent' or 'any').
|
||||
$order_types = array( $order_types );
|
||||
}
|
||||
|
||||
$related_orders = array();
|
||||
foreach ( $order_types as $order_type ) {
|
||||
$related_orders_for_order_type = array();
|
||||
foreach ( $this->get_related_order_ids( $order_type ) as $order_id ) {
|
||||
if ( 'all' === $return_fields && $order = wc_get_order( $order_id ) ) {
|
||||
$related_orders_for_order_type[ $order_id ] = $order;
|
||||
} elseif ( 'ids' === $return_fields ) {
|
||||
foreach ( $this->get_related_order_ids( $order_types, 'grouped' ) as $order_type => $order_ids ) {
|
||||
$related_orders_for_order_type = [];
|
||||
|
||||
foreach ( $order_ids as $order_id ) {
|
||||
if ( 'ids' === $return_fields ) {
|
||||
$related_orders_for_order_type[ $order_id ] = $order_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle the "all" return type by fetching the order object.
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( $order ) {
|
||||
$related_orders_for_order_type[ $order_id ] = $order;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2107,25 +2124,42 @@ class WC_Subscription extends WC_Order {
|
||||
/**
|
||||
* Get the related order IDs for a subscription based on an order type.
|
||||
*
|
||||
* @param string $order_type Can include 'any', 'parent', 'renewal', 'resubscribe' and/or 'switch'. Defaults to 'any'.
|
||||
* @return array List of related order IDs.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.3.0
|
||||
* @since 7.2.1 - The $order_type parameter can now be an array of order types and the $return_type parameter was added.
|
||||
*
|
||||
* @param string|array $order_type Can include 'any', 'parent', 'renewal', 'resubscribe' and/or 'switch'. Defaults to 'any'.
|
||||
* @param string $return_type The format to return the related order IDs in. Can be 'flat' or 'grouped'. Defaults to 'flat'.
|
||||
*
|
||||
* @return array List of related order IDs.
|
||||
*/
|
||||
protected function get_related_order_ids( $order_type = 'any' ) {
|
||||
protected function get_related_order_ids( $order_type = 'any', $return_type = 'flat' ) {
|
||||
$order_types = is_array( $order_type ) ? $order_type : [ $order_type ];
|
||||
$related_order_ids = [];
|
||||
|
||||
$related_order_ids = array();
|
||||
|
||||
if ( in_array( $order_type, array( 'any', 'parent' ) ) && $this->get_parent_id() ) {
|
||||
$related_order_ids[ $this->get_parent_id() ] = $this->get_parent_id();
|
||||
// For backwards compatibility, replace 'any' with the actual order types.
|
||||
if ( in_array( 'any', $order_types, true ) ) {
|
||||
$order_types = array_diff( $order_types, [ 'any' ] ); // Remove 'any'.
|
||||
$order_types = array_unique( array_merge( $order_types, [ 'parent', 'renewal', 'resubscribe', 'switch' ] ) ); // Add the 'any' order types.
|
||||
}
|
||||
|
||||
if ( 'parent' !== $order_type ) {
|
||||
// Get the parent order ID first.
|
||||
if ( in_array( 'parent', $order_types, true ) ) {
|
||||
// Remove the parent order type from the list of order types.
|
||||
$order_types = array_diff( $order_types, [ 'parent' ] );
|
||||
$parent_id = $this->get_parent_id();
|
||||
|
||||
$relation_types = ( 'any' === $order_type ) ? array( 'renewal', 'resubscribe', 'switch' ) : array( $order_type );
|
||||
|
||||
foreach ( $relation_types as $relation_type ) {
|
||||
$related_order_ids = array_merge( $related_order_ids, WCS_Related_Order_Store::instance()->get_related_order_ids( $this, $relation_type ) );
|
||||
// Because the call requested the parent order, if there is no parent ID, we need to return an empty array.
|
||||
$related_order_ids['parent'] = $parent_id ? [ $parent_id ] : [];
|
||||
}
|
||||
|
||||
if ( ! empty( $order_types ) ) {
|
||||
// Get the related order IDs based on the remaining order types.
|
||||
$related_order_ids += WCS_Related_Order_Store::instance()->get_related_order_ids_by_types( $this, $order_types );
|
||||
}
|
||||
|
||||
if ( 'flat' === $return_type && ! empty( $related_order_ids ) ) {
|
||||
// Flatten the grouped order IDs into a single array.
|
||||
$related_order_ids = array_merge( ...array_values( $related_order_ids ) );
|
||||
}
|
||||
|
||||
return $related_order_ids;
|
||||
|
@@ -368,7 +368,6 @@ class WC_Subscriptions_Cart {
|
||||
}
|
||||
|
||||
$recurring_cart->fee_total = 0;
|
||||
self::maybe_restore_shipping_methods();
|
||||
$recurring_cart->calculate_totals();
|
||||
|
||||
// Store this groups cart details
|
||||
@@ -385,9 +384,6 @@ class WC_Subscriptions_Cart {
|
||||
// Reset flags when we're done processing recurring carts.
|
||||
self::$calculation_type = self::$recurring_cart_key = 'none';
|
||||
|
||||
// We need to reset the packages and totals stored in WC()->shipping too
|
||||
self::maybe_restore_shipping_methods();
|
||||
|
||||
// Only calculate the initial order cart shipping if we need to show shipping.
|
||||
if ( WC()->cart->show_shipping() ) {
|
||||
WC()->cart->calculate_shipping();
|
||||
@@ -954,68 +950,6 @@ class WC_Subscriptions_Cart {
|
||||
return $needs_payment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore shipping method, as well as cost and tax estimate when on the cart page.
|
||||
*
|
||||
* The WC_Shortcode_Cart actually calculates shipping when the "Calculate Shipping" form is submitted on the
|
||||
* cart page. Because of that, our own @see self::calculate_totals() method calculates incorrect values on
|
||||
* the cart page because it triggers the method multiple times for multiple different pricing structures.
|
||||
* This uses the same logic found in WC_Shortcode_Cart::output() to determine the correct estimate.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v1.4.10
|
||||
*/
|
||||
private static function maybe_restore_shipping_methods() {
|
||||
WC()->shipping->reset_shipping();
|
||||
|
||||
if ( ! empty( $_POST['calc_shipping'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) && function_exists( 'WC' ) ) {
|
||||
|
||||
try {
|
||||
$country = wc_clean( $_POST['calc_shipping_country'] );
|
||||
$state = isset( $_POST['calc_shipping_state'] ) ? wc_clean( $_POST['calc_shipping_state'] ) : '';
|
||||
$postcode = apply_filters( 'woocommerce_shipping_calculator_enable_postcode', true ) ? wc_clean( $_POST['calc_shipping_postcode'] ) : '';
|
||||
$city = apply_filters( 'woocommerce_shipping_calculator_enable_city', false ) ? wc_clean( $_POST['calc_shipping_city'] ) : '';
|
||||
|
||||
if ( $postcode && ! WC_Validation::is_postcode( $postcode, $country ) ) {
|
||||
throw new Exception( __( 'Please enter a valid postcode/ZIP.', 'woocommerce-subscriptions' ) );
|
||||
} elseif ( $postcode ) {
|
||||
$postcode = wc_format_postcode( $postcode, $country );
|
||||
}
|
||||
|
||||
if ( $country ) {
|
||||
WC()->customer->set_location( $country, $state, $postcode, $city );
|
||||
WC()->customer->set_shipping_location( $country, $state, $postcode, $city );
|
||||
} else {
|
||||
WC()->customer->set_to_base();
|
||||
WC()->customer->set_shipping_to_base();
|
||||
}
|
||||
|
||||
WC()->customer->calculated_shipping( true );
|
||||
|
||||
do_action( 'woocommerce_calculated_shipping' );
|
||||
|
||||
} catch ( Exception $e ) {
|
||||
if ( ! empty( $e ) ) {
|
||||
wc_add_notice( $e->getMessage(), 'error' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we had one time shipping in the carts, we may have wiped the WC chosen shippings. Restore them.
|
||||
self::maybe_restore_chosen_shipping_method();
|
||||
|
||||
if ( isset( $_POST['shipping_method'] ) && is_array( $_POST['shipping_method'] ) ) {
|
||||
|
||||
// Now make sure the correct shipping method is set
|
||||
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods', array() );
|
||||
|
||||
foreach ( $_POST['shipping_method'] as $i => $value ) {
|
||||
$chosen_shipping_methods[ $i ] = wc_clean( $value );
|
||||
}
|
||||
|
||||
WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure cart product prices correctly include/exclude taxes.
|
||||
*
|
||||
@@ -2353,8 +2287,11 @@ class WC_Subscriptions_Cart {
|
||||
* WC()->shipping->reset() on it, which will wipe the preferences saved. That can cause the chosen shipping method for the one
|
||||
* time shipping feature to be lost, and the first default to be applied instead. To counter that, we save the chosen shipping
|
||||
* method to a key that's not going to get wiped by WC's method, and then later restore it.
|
||||
*
|
||||
* @deprecated 7.3.0 - no longer in use internally
|
||||
*/
|
||||
public static function maybe_restore_chosen_shipping_method() {
|
||||
wcs_deprecated_function( __METHOD__, '7.3.0', 'The use of this function is no longer recommended and will be removed in a future version.' );
|
||||
$chosen_shipping_method_cache = WC()->session->get( 'wcs_shipping_methods', false );
|
||||
|
||||
if ( false !== $chosen_shipping_method_cache ) {
|
||||
|
@@ -16,7 +16,7 @@ class WC_Subscriptions_Core_Plugin {
|
||||
* The version of subscriptions-core library.
|
||||
* @var string
|
||||
*/
|
||||
protected $library_version = '8.0.1'; // WRCS: DEFINED_VERSION.
|
||||
protected $library_version = '8.1.0'; // WRCS: DEFINED_VERSION.
|
||||
|
||||
/**
|
||||
* The subscription scheduler instance.
|
||||
|
@@ -53,9 +53,6 @@ class WC_Subscriptions_Email_Notifications {
|
||||
// Add settings UI.
|
||||
add_filter( 'woocommerce_subscription_settings', [ __CLASS__, 'add_settings' ], 20 );
|
||||
|
||||
// Add admin notice.
|
||||
add_action( 'admin_notices', [ __CLASS__, 'maybe_add_admin_notice' ] );
|
||||
|
||||
// Bump settings update time whenever related options change.
|
||||
add_action( 'update_option_' . WC_Subscriptions_Admin::$option_prefix . self::$offset_setting_string, [ __CLASS__, 'set_notification_settings_update_time' ], 10, 3 );
|
||||
add_action( 'update_option_' . WC_Subscriptions_Admin::$option_prefix . self::$switch_setting_string, [ __CLASS__, 'set_notification_settings_update_time' ], 10, 3 );
|
||||
@@ -307,58 +304,4 @@ class WC_Subscriptions_Email_Notifications {
|
||||
WC_Subscriptions_Admin::insert_setting_after( $settings, WC_Subscriptions_Admin::$option_prefix . '_miscellaneous', $notification_settings, 'multiple_settings', 'sectionend' );
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe add an admin notice to inform the store manager about the existance of the notifications feature.
|
||||
*/
|
||||
public static function maybe_add_admin_notice() {
|
||||
|
||||
// If the notifications feature is enabled, don't show the notice.
|
||||
if ( self::notifications_globally_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent showing the notice on the Subscriptions settings page.
|
||||
if ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && 'subscriptions' === $_GET['tab'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$option_name = 'wcs_hide_customer_notifications_notice';
|
||||
$nonce = '_wcsnonce';
|
||||
$action = 'wcs_hide_customer_notifications_notice_action';
|
||||
|
||||
// First, check if the notice is being dismissed.
|
||||
$nonce_argument = sanitize_text_field( wp_unslash( $_GET[ $nonce ] ?? '' ) );
|
||||
if ( isset( $_GET[ $action ], $nonce_argument ) && wp_verify_nonce( $nonce_argument, $action ) ) {
|
||||
update_option( $option_name, 'yes' );
|
||||
wp_safe_redirect( remove_query_arg( [ $action, $nonce ] ) );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'yes' === get_option( $option_name ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$admin_notice = new WCS_Admin_Notice( 'notice', array(), wp_nonce_url( add_query_arg( $action, 'dismiss' ), $action, $nonce ) );
|
||||
$notice_title = __( 'WooCommerce Subscriptions: Introducing customer email notifications!', 'woocommerce-subscriptions' );
|
||||
$notice_content = __( 'You can now send email notifications for subscription renewals, expirations, and free trials. Go to the "Customer Notifications" settings section to configure when your customers receive these important updates.', 'woocommerce-subscriptions' );
|
||||
$html_content = sprintf( '<p class="main"><strong>%1$s</strong></p><p>%2$s</p>', $notice_title, $notice_content );
|
||||
$admin_notice->set_html_content( $html_content );
|
||||
$admin_notice->set_actions(
|
||||
array(
|
||||
array(
|
||||
'name' => __( 'Manage settings', 'woocommerce-subscriptions' ),
|
||||
'url' => admin_url( 'admin.php?page=wc-settings&tab=subscriptions' ),
|
||||
'class' => 'button button-primary',
|
||||
),
|
||||
array(
|
||||
'name' => __( 'Learn more', 'woocommerce-subscriptions' ),
|
||||
'url' => 'https://woocommerce.com/document/subscriptions/subscriptions-notifications/',
|
||||
'class' => 'button',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
$admin_notice->display();
|
||||
}
|
||||
}
|
||||
|
@@ -117,16 +117,13 @@ class WC_Subscriptions_Email {
|
||||
/**
|
||||
* Init the mailer and call for the cancelled email notification hook.
|
||||
*
|
||||
* @param $subscription WC Subscription
|
||||
* @param WC_Subscription $subscription The subscription being examined.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
public static function send_cancelled_email( $subscription ) {
|
||||
WC()->mailer();
|
||||
|
||||
if ( $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) && 'true' !== $subscription->get_cancelled_email_sent() ) {
|
||||
do_action( 'cancelled_subscription_notification', $subscription );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the mailer and call for the expired email notification hook.
|
||||
@@ -244,7 +241,10 @@ class WC_Subscriptions_Email {
|
||||
$order = wc_get_order( $order );
|
||||
}
|
||||
|
||||
if ( is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
return $items_table;
|
||||
}
|
||||
|
||||
$show_download_links_callback = ( isset( $args['show_download_links'] ) && $args['show_download_links'] ) ? '__return_true' : '__return_false';
|
||||
$show_purchase_note_callback = ( isset( $args['show_purchase_note'] ) && $args['show_purchase_note'] ) ? '__return_true' : '__return_false';
|
||||
|
||||
@@ -254,15 +254,10 @@ class WC_Subscriptions_Email {
|
||||
add_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback );
|
||||
add_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback );
|
||||
|
||||
if ( function_exists( 'wc_get_email_order_items' ) ) { // WC 3.0+
|
||||
$items_table = wc_get_email_order_items( $order, $args );
|
||||
} else {
|
||||
$items_table = $order->email_order_items_table( $args );
|
||||
}
|
||||
|
||||
remove_filter( 'woocommerce_order_is_download_permitted', $show_download_links_callback );
|
||||
remove_filter( 'woocommerce_order_is_paid', $show_purchase_note_callback );
|
||||
}
|
||||
|
||||
return $items_table;
|
||||
}
|
||||
@@ -277,13 +272,14 @@ class WC_Subscriptions_Email {
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1
|
||||
*/
|
||||
public static function order_details( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
$image_size = $email_improvements_enabled ? 48 : 32; // These image sizes are defaults for WC core emails. @see wc_get_email_order_items().
|
||||
$order_items_table_args = array(
|
||||
'show_download_links' => ( $sent_to_admin ) ? false : $order->is_download_permitted(),
|
||||
'show_sku' => $sent_to_admin,
|
||||
'show_purchase_note' => ( $sent_to_admin ) ? false : $order->has_status( apply_filters( 'woocommerce_order_is_paid_statuses', array( 'processing', 'completed' ) ) ),
|
||||
'show_image' => '',
|
||||
'image_size' => '',
|
||||
'show_image' => $email_improvements_enabled,
|
||||
'image_size' => array( $image_size, $image_size ),
|
||||
'plain_text' => $plain_text,
|
||||
);
|
||||
|
||||
|
@@ -451,7 +451,7 @@ class WC_Subscriptions_Order {
|
||||
*/
|
||||
public static function add_contains_subscription_column_content_orders_table( string $column_name, WC_Order $order ) {
|
||||
if ( 'subscription_relationship' === $column_name ) {
|
||||
self::render_contains_subscription_column_content( $order->get_id() );
|
||||
self::render_contains_subscription_column_content( $order );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2442,14 +2442,20 @@ class WC_Subscriptions_Order {
|
||||
*
|
||||
* @since 6.3.0
|
||||
*
|
||||
* @param integer $order_id The ID of the order in the current row.
|
||||
* @param WC_Order $order The order in the current row.
|
||||
*/
|
||||
private static function render_contains_subscription_column_content( int $order_id ) {
|
||||
if ( wcs_order_contains_subscription( $order_id, 'renewal' ) ) {
|
||||
private static function render_contains_subscription_column_content( $order ) {
|
||||
$order = ! is_object( $order ) ? wc_get_order( $order ) : $order;
|
||||
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( wcs_order_contains_renewal( $order ) ) {
|
||||
echo '<span class="subscription_renewal_order tips" data-tip="' . esc_attr__( 'Renewal Order', 'woocommerce-subscriptions' ) . '"></span>';
|
||||
} elseif ( wcs_order_contains_subscription( $order_id, 'resubscribe' ) ) {
|
||||
} elseif ( wcs_order_contains_resubscribe( $order ) ) {
|
||||
echo '<span class="subscription_resubscribe_order tips" data-tip="' . esc_attr__( 'Resubscribe Order', 'woocommerce-subscriptions' ) . '"></span>';
|
||||
} elseif ( wcs_order_contains_subscription( $order_id, 'parent' ) ) {
|
||||
} elseif ( apply_filters( 'woocommerce_subscriptions_orders_list_render_parent_order_relation', false, $order ) && wcs_order_contains_parent( $order ) ) {
|
||||
echo '<span class="subscription_parent_order tips" data-tip="' . esc_attr__( 'Parent Order', 'woocommerce-subscriptions' ) . '"></span>';
|
||||
} else {
|
||||
echo '<span class="normal_order">–</span>';
|
||||
|
@@ -96,27 +96,9 @@ class WC_Subscriptions_Renewal_Order {
|
||||
$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 ) {
|
||||
|
||||
if ( wcs_is_woocommerce_pre( '3.0' ) ) {
|
||||
$update_post_data = array(
|
||||
'ID' => $order_id,
|
||||
'post_date' => current_time( 'mysql', 0 ),
|
||||
'post_date_gmt' => current_time( 'mysql', 1 ),
|
||||
);
|
||||
|
||||
wp_update_post( $update_post_data );
|
||||
update_post_meta( $order_id, '_paid_date', current_time( 'mysql' ) );
|
||||
} else {
|
||||
|
||||
$current_time = current_time( 'timestamp', 1 );
|
||||
|
||||
// Prior to WC 3.0, we need to update the post date (i.e. the date created) to have a reliable representation of the paid date (both because it was in GMT and because it was always set). That's not needed in WC 3.0, but some plugins and store owners still rely on it being updated, so we want to make it possible to update it with 3.0 also.
|
||||
if ( apply_filters( 'wcs_renewal_order_payment_update_date_created', false, $order, $subscriptions ) ) {
|
||||
$order->set_date_created( $current_time );
|
||||
}
|
||||
|
||||
// In WC 3.0, only the paid date prop represents the paid date, the post date isn't used anymore, also the paid date is stored and referenced as a MySQL date string in site timezone and a GMT timestamp
|
||||
$order->set_date_paid( $current_time );
|
||||
$order->set_date_created( time() );
|
||||
$order->save();
|
||||
}
|
||||
}
|
||||
|
@@ -113,6 +113,7 @@ class WCS_Cart_Renewal {
|
||||
// Make sure renewal meta data persists between sessions
|
||||
add_filter( 'woocommerce_get_cart_item_from_session', array( &$this, 'get_cart_item_from_session' ), 10, 3 );
|
||||
add_action( 'woocommerce_cart_loaded_from_session', array( &$this, 'cart_items_loaded_from_session' ), 10 );
|
||||
add_action( 'woocommerce_cart_loaded_from_session', array( $this, 'restore_order_awaiting_payment' ), 10 );
|
||||
|
||||
// Make sure fees are added to the cart
|
||||
add_action( 'woocommerce_cart_calculate_fees', array( &$this, 'maybe_add_fees' ), 10, 1 );
|
||||
@@ -248,14 +249,28 @@ class WCS_Cart_Renewal {
|
||||
* @internal Core checkout uses order_awaiting_payment, Blocks checkout uses store_api_draft_order. Both validate the
|
||||
* cart hash to ensure the order matches the cart.
|
||||
*
|
||||
* @param int $order_id The order ID that is awaiting payment, or 0 to unset it.
|
||||
* @param int|WC_Order $order_id The order that is awaiting payment, or 0 to unset it.
|
||||
*/
|
||||
protected function set_order_awaiting_payment( $order_id ) {
|
||||
$order = null;
|
||||
|
||||
if ( is_a( $order_id, 'WC_Abstract_Order' ) ) {
|
||||
$order = $order_id;
|
||||
$order_id = $order->get_id();
|
||||
} elseif ( ! empty( $order_id ) ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
}
|
||||
|
||||
// Only ever set the order awaiting payment to 0 or an Order ID - not a subscription.
|
||||
if ( $order && ! wcs_is_order( $order ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WC()->session->set( 'order_awaiting_payment', $order_id );
|
||||
WC()->session->set( 'store_api_draft_order', $order_id );
|
||||
|
||||
if ( $order_id ) {
|
||||
$this->set_cart_hash( $order_id );
|
||||
$this->set_cart_hash( $order );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1654,6 +1669,40 @@ class WCS_Cart_Renewal {
|
||||
return $has_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the order awaiting payment session args if the cart contains a subscription-related order.
|
||||
*
|
||||
* It's possible the that order_awaiting_payment and store_api_draft_order session args are not set if those session args are lost due
|
||||
* to session destruction.
|
||||
*
|
||||
* This function checks the cart that is being loaded from the session and if the cart contains a subscription-related order and if the
|
||||
* current user has permission to pay for it. If so, it restores the order awaiting payment session args.
|
||||
*
|
||||
* @param WC_Cart $cart The cart object.
|
||||
*/
|
||||
public function restore_order_awaiting_payment( $cart ) {
|
||||
if ( ! is_a( $cart, WC_Cart::class ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $cart->get_cart() as $cart_item ) {
|
||||
$order = $this->get_order( $cart_item );
|
||||
|
||||
if ( ! $order ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the current user has permission to pay for the order, restore the order awaiting payment session arg.
|
||||
if ( wcs_is_order( $order ) && $this->validate_current_user( $order ) ) {
|
||||
$this->set_order_awaiting_payment( $order );
|
||||
}
|
||||
|
||||
// Once we found an order, exit even if the user doesn't have permission to pay for it.
|
||||
return;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* Deprecated */
|
||||
|
||||
/**
|
||||
|
@@ -872,6 +872,11 @@ class WCS_Orders_Table_Subscription_Data_Store extends \Automattic\WooCommerce\I
|
||||
global $wpdb;
|
||||
|
||||
$wpdb->delete( self::get_meta_table_name(), [ 'meta_key' => $meta_key ], [ '%s' ] ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
|
||||
|
||||
// If custom order tables is enabled and data syncing is enabled, delete the meta from the custom order tables.
|
||||
if ( wcs_is_custom_order_tables_usage_enabled() && wcs_is_custom_order_tables_data_sync_enabled() ) {
|
||||
$this->get_cpt_data_store_instance()->delete_all_metadata_by_key( $meta_key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -46,6 +46,22 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
*/
|
||||
private static $override_ignored_props = false;
|
||||
|
||||
/**
|
||||
* A list of subscription IDs that are requesting multiple related order caches to be read.
|
||||
*
|
||||
* This is used by @see get_related_order_ids_by_types() to enable fetching multiple related order caches without reading the subscriptions meta query multiple times.
|
||||
*
|
||||
* @var array $batch_processing_subscriptions An array of subscription IDs.
|
||||
*/
|
||||
private static $batch_processing_related_orders = [];
|
||||
|
||||
/**
|
||||
* A cache of subscription meta data. Used when fetching multiple related order caches for a subscription to avoid multiple database queries.
|
||||
*
|
||||
* @var array $subscription_meta_cache An array of subscription meta data.
|
||||
*/
|
||||
private static $subscription_meta_cache = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@@ -290,7 +306,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
}
|
||||
}
|
||||
|
||||
$subscription_data_store = WC_Data_Store::load( 'subscription' );
|
||||
$subscription_data_store = $subscription->get_data_store();
|
||||
$current_metadata = $this->get_related_order_metadata( $subscription, $relation_type );
|
||||
$new_metadata = array(
|
||||
'key' => $this->get_cache_meta_key( $relation_type ),
|
||||
@@ -302,16 +318,24 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
$this->update_modified_date_for_related_order_cache( $subscription, $related_order_ids, $current_metadata );
|
||||
}
|
||||
|
||||
// Check if HPOS and data syncing is enabled then manually backfill the related orders cache values to WP Posts table.
|
||||
$this->maybe_backfill_related_order_cache( $subscription, $relation_type, $new_metadata );
|
||||
|
||||
// If there is metadata for this key, update it, otherwise add it.
|
||||
if ( $current_metadata ) {
|
||||
$new_metadata['id'] = $current_metadata->meta_id;
|
||||
return $subscription_data_store->update_meta( $subscription, (object) $new_metadata );
|
||||
$return = $subscription_data_store->update_meta( $subscription, (object) $new_metadata );
|
||||
} else {
|
||||
return $subscription_data_store->add_meta( $subscription, (object) $new_metadata );
|
||||
$return = $subscription_data_store->add_meta( $subscription, (object) $new_metadata );
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger update actions after modifying the subscription's related order cache metadata.
|
||||
*
|
||||
* This ensures that functions fired after a subscription update, such as webhooks and those in the DataSynchronizer,
|
||||
* which sync CPT post data to HPOS tables, are executed.
|
||||
*/
|
||||
do_action( 'woocommerce_update_order', $subscription->get_id(), $subscription );
|
||||
do_action( 'woocommerce_update_subscription', $subscription->get_id(), $subscription );
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -328,8 +352,12 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
* @param WC_Subscription $subscription The subscription object to backfill.
|
||||
* @param string $relation_type The related order relationship type. Can be 'renewal', 'switch' or 'resubscribe'.
|
||||
* @param array $metadata The metadata to set update/add in the CPT data store. Should be an array with 'key' and 'value' keys.
|
||||
*
|
||||
* @deprecated 7.3.0 - Backfilling is already handled by the Order/Subscriptions Data Store.
|
||||
*/
|
||||
protected function maybe_backfill_related_order_cache( $subscription, $relation_type, $metadata ) {
|
||||
wcs_deprecated_function( __METHOD__, '7.3.0' );
|
||||
|
||||
if ( ! wcs_is_custom_order_tables_usage_enabled() || ! wcs_is_custom_order_tables_data_sync_enabled() || empty( $metadata['key'] ) ) {
|
||||
return;
|
||||
}
|
||||
@@ -373,7 +401,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
$metadata = $this->get_related_order_metadata( $subscription, $possible_relation_type );
|
||||
|
||||
if ( $metadata ) {
|
||||
WC_Data_Store::load( 'subscription' )->delete_meta( $subscription, (object) [ 'id' => $metadata->meta_id ] );
|
||||
$subscription->get_data_store()->delete_meta( $subscription, (object) [ 'id' => $metadata->meta_id ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -539,7 +567,7 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
$ids = wcs_get_orders_with_meta_query(
|
||||
[
|
||||
'limit' => $limit,
|
||||
'fields' => 'ids',
|
||||
'return' => 'ids',
|
||||
'orderby' => 'ID',
|
||||
'order' => 'ASC',
|
||||
'type' => 'shop_subscription',
|
||||
@@ -617,12 +645,11 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
public function update_items_cache( $subscription_id ) {
|
||||
$subscription = wcs_get_subscription( $subscription_id );
|
||||
|
||||
if ( $subscription ) {
|
||||
foreach ( $this->get_relation_types() as $relation_type ) {
|
||||
// Getting the related IDs also sets the cache when it's not already set
|
||||
$this->get_related_order_ids( $subscription, $relation_type );
|
||||
}
|
||||
if ( ! $subscription ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->get_related_order_ids_by_types( $subscription, $this->get_relation_types() );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -643,22 +670,9 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
*/
|
||||
protected function get_related_order_metadata( WC_Subscription $subscription, $relation_type, $data_store = null ) {
|
||||
$cache_meta_key = $this->get_cache_meta_key( $relation_type );
|
||||
$data_store = empty( $data_store ) ? WC_Data_Store::load( 'subscription' ) : $data_store;
|
||||
$data_store = $data_store ?? $subscription->get_data_store();
|
||||
|
||||
/**
|
||||
* Bypass the related order cache keys being ignored when fetching subscription meta.
|
||||
*
|
||||
* By default the related order cache keys are ignored via $this->add_related_order_cache_props(). In order to fetch the subscription's
|
||||
* meta with those keys, we need to bypass that function.
|
||||
*
|
||||
* We use a static variable because it is possible to have multiple instances of this class in memory, and we want to make sure we bypass
|
||||
* the function in all instances.
|
||||
*/
|
||||
self::$override_ignored_props = true;
|
||||
$subscription_meta = $data_store->read_meta( $subscription );
|
||||
self::$override_ignored_props = false;
|
||||
|
||||
foreach ( $subscription_meta as $meta ) {
|
||||
foreach ( $this->get_subscription_meta( $subscription, $data_store ) as $meta ) {
|
||||
if ( isset( $meta->meta_key ) && $cache_meta_key === $meta->meta_key ) {
|
||||
return $meta;
|
||||
}
|
||||
@@ -690,4 +704,124 @@ class WCS_Related_Order_Store_Cached_CPT extends WCS_Related_Order_Store_CPT imp
|
||||
$subscription->save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subscription's meta data.
|
||||
*
|
||||
* @param WC_Subscription $subscription The subscription to get the meta for.
|
||||
* @param mixed $data_store The data store to use to get the meta. Defaults to the current subscription's data store.
|
||||
*
|
||||
* @return array The subscription's meta data.
|
||||
*/
|
||||
private function get_subscription_meta( WC_Subscription $subscription, $data_store ) {
|
||||
$subscription_id = $subscription->get_id();
|
||||
$cache_key = $this->get_batch_processing_cache_key( $subscription, $data_store );
|
||||
$is_batch_processing = $this->is_batch_processing( $cache_key );
|
||||
|
||||
// If we are in batch processing mode, and there are cached results return the cached meta data.
|
||||
if ( $is_batch_processing && isset( self::$subscription_meta_cache[ $cache_key ] ) ) {
|
||||
return self::$subscription_meta_cache[ $cache_key ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Bypass the related order cache keys being ignored when fetching subscription meta.
|
||||
*
|
||||
* By default the related order cache keys are ignored via $this->add_related_order_cache_props(). In order to fetch the subscription's
|
||||
* meta with those keys, we need to bypass that function.
|
||||
*
|
||||
* We use a static variable because it is possible to have multiple instances of this class in memory, and we want to make sure we bypass
|
||||
* the function in all instances.
|
||||
*/
|
||||
self::$override_ignored_props = true;
|
||||
$subscription_meta = $data_store->read_meta( $subscription );
|
||||
self::$override_ignored_props = false;
|
||||
|
||||
// If we are in batch processing mode, cache the meta data so it can be returned for subsequent calls.
|
||||
if ( $is_batch_processing ) {
|
||||
self::$subscription_meta_cache[ $cache_key ] = $subscription_meta;
|
||||
}
|
||||
|
||||
return $subscription_meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the related order IDs for a subscription by multiple relation types.
|
||||
*
|
||||
* This function is a more efficient way to get related order IDs for multiple relation types at once.
|
||||
* It will only query the database once for all cache data, and then return the related order IDs for each relation type.
|
||||
*
|
||||
* The alternative of calling the get_related_order_ids() function for each relation type will result in a full subscription meta read for each relation type.
|
||||
*
|
||||
* @param WC_Order $subscription The subscription to get related order IDs for.
|
||||
* @param array $related_order_types The related order types to get IDs for. Must be an array of supported relation types.
|
||||
*
|
||||
* @return array An array of related order IDs for each relation type.
|
||||
*/
|
||||
public function get_related_order_ids_by_types( WC_Order $subscription, $related_order_types ) {
|
||||
$subscription_id = $subscription->get_id();
|
||||
$related_order_ids = [];
|
||||
|
||||
// Declare batch processing mode for this subscription.
|
||||
$cache_key = $this->start_batch_processing_mode( $subscription );
|
||||
|
||||
foreach ( $related_order_types as $relation_type ) {
|
||||
$related_order_ids[ $relation_type ] = $this->get_related_order_ids( $subscription, $relation_type );
|
||||
}
|
||||
|
||||
$this->stop_batch_processing_mode( $cache_key );
|
||||
|
||||
return $related_order_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts batch processing mode for a subscription.
|
||||
*
|
||||
* @param WC_Subscription $subscription The subscription to start batch processing mode for.
|
||||
* @return string The cache key for the subscription.
|
||||
*/
|
||||
private function start_batch_processing_mode( $subscription ) {
|
||||
$cache_key = $this->get_batch_processing_cache_key( $subscription );
|
||||
|
||||
self::$batch_processing_related_orders[ $cache_key ] = true;
|
||||
return $cache_key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stops batch processing mode for a subscription.
|
||||
*
|
||||
* Destroys the cache and removes the cache key.
|
||||
*
|
||||
* @param string $cache_key The batch processing cache key.
|
||||
*/
|
||||
private function stop_batch_processing_mode( $cache_key ) {
|
||||
unset( self::$batch_processing_related_orders[ $cache_key ] );
|
||||
unset( self::$subscription_meta_cache[ $cache_key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if batch processing mode is active for a subscription.
|
||||
*
|
||||
* @param string $cache_key The batch processing cache key.
|
||||
* @return bool True if batch processing mode is active, false otherwise.
|
||||
*/
|
||||
private function is_batch_processing( $cache_key ) {
|
||||
return isset( self::$batch_processing_related_orders[ $cache_key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the batch processing cache key for a subscription.
|
||||
*
|
||||
* The cache key is a unique combination of the subscription ID and the data store class name.
|
||||
*
|
||||
* @param WC_Subscription $subscription The subscription to get the cache key for.
|
||||
* @param bool|object $data_store The data store which will be used to read the subscription meta. Defaults to the current subscription's data store.
|
||||
*
|
||||
* @return string The cache key for the subscription.
|
||||
*/
|
||||
private function get_batch_processing_cache_key( $subscription, $data_store = null ) {
|
||||
// If no data store is provided, use the subscription object's data store or load the default data store if no subscription data store is found.
|
||||
$data_store = $data_store ?? $subscription->get_data_store() ?? WC_Data_Store::load( 'subscriptions' );
|
||||
$data_store_class = is_a( $data_store, 'WC_Data_Store' ) ? $data_store->get_current_class_name() : '';
|
||||
return $data_store_class . '-' . $subscription->get_id();
|
||||
}
|
||||
}
|
||||
|
@@ -77,6 +77,13 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
'_subscription_switch_order_ids_cache' => 'switch_order_ids_cache',
|
||||
);
|
||||
|
||||
/**
|
||||
* The data store instance for the custom order tables.
|
||||
*
|
||||
* @var WCS_Orders_Table_Subscription_Data_Store
|
||||
*/
|
||||
protected $orders_table_data_store;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
@@ -535,12 +542,16 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
|
||||
$subscription_ids = array();
|
||||
|
||||
$search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_subscription_search_fields', array(
|
||||
'_order_key',
|
||||
$search_fields = array_map(
|
||||
'wc_clean',
|
||||
apply_filters(
|
||||
'woocommerce_shop_subscription_search_fields',
|
||||
[
|
||||
'_billing_address_index',
|
||||
'_shipping_address_index',
|
||||
'_billing_email',
|
||||
) ) );
|
||||
]
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_numeric( $term ) ) {
|
||||
$subscription_ids[] = absint( $term );
|
||||
@@ -611,6 +622,11 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
$meta_value = null; // Delete any values.
|
||||
$delete_all = true;
|
||||
delete_metadata( 'post', $id, $meta_key, $meta_value, $delete_all );
|
||||
|
||||
// If custom order tables is not enabled, but Data Syncing is enabled, delete the meta from the custom order tables.
|
||||
if ( ! wcs_is_custom_order_tables_usage_enabled() && wcs_is_custom_order_tables_data_sync_enabled() ) {
|
||||
$this->get_cot_data_store_instance()->delete_all_metadata_by_key( $meta_key );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -711,8 +727,11 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
*/
|
||||
public function set_renewal_order_ids_cache( $subscription, $renewal_order_ids ) {
|
||||
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'renewal' );
|
||||
|
||||
if ( '' !== $renewal_order_ids ) {
|
||||
update_post_meta( $subscription->get_id(), '_subscription_renewal_order_ids_cache', $renewal_order_ids );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually sets the list of subscription's resubscribe order IDs stored in cache.
|
||||
@@ -725,8 +744,11 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
*/
|
||||
public function set_resubscribe_order_ids_cache( $subscription, $resubscribe_order_ids ) {
|
||||
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'resubscribe' );
|
||||
|
||||
if ( '' !== $resubscribe_order_ids ) {
|
||||
update_post_meta( $subscription->get_id(), '_subscription_resubscribe_order_ids_cache', $resubscribe_order_ids );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manually sets the list of subscription's switch order IDs stored in cache.
|
||||
@@ -739,8 +761,11 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
*/
|
||||
public function set_switch_order_ids_cache( $subscription, $switch_order_ids ) {
|
||||
$this->cleanup_backfill_related_order_cache_duplicates( $subscription, 'switch' );
|
||||
|
||||
if ( '' !== $switch_order_ids ) {
|
||||
update_post_meta( $subscription->get_id(), '_subscription_switch_order_ids_cache', $switch_order_ids );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a subscription's related order cache - including any duplicates.
|
||||
@@ -763,4 +788,17 @@ class WCS_Subscription_Data_Store_CPT extends WC_Order_Data_Store_CPT implements
|
||||
delete_post_meta( $subscription->get_id(), "_subscription_{$relationship_type}_order_ids_cache" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data store instance for Order Tables data store.
|
||||
*
|
||||
* @return WCS_Orders_Table_Subscription_Data_Store
|
||||
*/
|
||||
public function get_cot_data_store_instance() {
|
||||
if ( ! isset( $this->orders_table_data_store ) ) {
|
||||
$this->orders_table_data_store = new WCS_Orders_Table_Subscription_Data_Store();
|
||||
}
|
||||
|
||||
return $this->orders_table_data_store;
|
||||
}
|
||||
}
|
||||
|
@@ -49,8 +49,14 @@ class WC_Subscriptions_Email_Preview {
|
||||
case 'WCS_Email_Customer_Notification_Auto_Renewal':
|
||||
$email->set_object( $this->get_dummy_subscription() );
|
||||
break;
|
||||
case 'WCS_Email_Customer_Payment_Retry':
|
||||
case 'WCS_Email_Payment_Retry':
|
||||
$email->retry = $this->get_dummy_retry( $email->object );
|
||||
break;
|
||||
}
|
||||
|
||||
$this->add_placeholders( $email );
|
||||
|
||||
add_filter( 'woocommerce_mail_content', [ $this, 'clean_up_filters' ] );
|
||||
|
||||
return $email;
|
||||
@@ -139,13 +145,55 @@ class WC_Subscriptions_Email_Preview {
|
||||
return apply_filters( 'woocommerce_subscriptions_email_preview_dummy_address', $address, $this->email_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a dummy retry for use when previewing failed subscription payment retry emails.
|
||||
*
|
||||
* @param WC_Order $order The order object to create a dummy retry for.
|
||||
* @return WCS_Retry The dummy retry object.
|
||||
*/
|
||||
private function get_dummy_retry( $order ) {
|
||||
|
||||
if ( ! class_exists( 'WCS_Retry_Manager' ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$order_id = is_a( $order, 'WC_Order' ) ? $order->get_id() : 12345;
|
||||
$retry_rule = WCS_Retry_Manager::rules()->get_rule( 1, $order_id );
|
||||
|
||||
if ( is_a( $retry_rule, 'WCS_Retry_Rule' ) ) {
|
||||
$interval = $retry_rule->get_retry_interval();
|
||||
$raw_retry_rule = $retry_rule->get_raw_data();
|
||||
} else {
|
||||
// If the retry rule is not found, use a default interval of 12 hours and an empty raw rule.
|
||||
$interval = 12 * HOUR_IN_SECONDS;
|
||||
$raw_retry_rule = [];
|
||||
}
|
||||
|
||||
return new WCS_Retry(
|
||||
[
|
||||
'status' => 'pending',
|
||||
'order_id' => $order_id,
|
||||
'date_gmt' => gmdate( 'Y-m-d H:i:s', time() + $interval ),
|
||||
'rule_raw' => $raw_retry_rule,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the email being previewed is a subscription email.
|
||||
*
|
||||
* @return bool
|
||||
* Subscription emails include:
|
||||
* - WC_Subscriptions_Email::$email_classes - core subscription emails.
|
||||
* - WC_Subscriptions_Email_Notifications::$email_classes - subscription notification emails (pre-renewal emails).
|
||||
* - WCS_Email_Customer_Payment_Retry - customer payment retry emails.
|
||||
* - WCS_Email_Payment_Retry - admin payment retry emails.
|
||||
*
|
||||
* @return bool Whether the email being previewed is a subscription email.
|
||||
*/
|
||||
private function is_subscription_email() {
|
||||
return isset( WC_Subscriptions_Email::$email_classes[ $this->email_type ] ) || isset( WC_Subscriptions_Email_Notifications::$email_classes[ $this->email_type ] );
|
||||
return isset( WC_Subscriptions_Email::$email_classes[ $this->email_type ] )
|
||||
|| isset( WC_Subscriptions_Email_Notifications::$email_classes[ $this->email_type ] )
|
||||
|| in_array( $this->email_type, [ 'WCS_Email_Customer_Payment_Retry', 'WCS_Email_Payment_Retry' ], true );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,4 +252,52 @@ class WC_Subscriptions_Email_Preview {
|
||||
|
||||
return $can_renew_early;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom placeholders for subscription emails.
|
||||
*
|
||||
* @param WC_Email $email The email object.
|
||||
*/
|
||||
private function add_placeholders( $email ) {
|
||||
if ( ! isset( $email->placeholders ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$placeholders = [];
|
||||
|
||||
switch ( $this->email_type ) {
|
||||
case 'WCS_Email_Customer_Notification_Subscription_Expiration':
|
||||
case 'WCS_Email_Customer_Notification_Manual_Trial_Expiration':
|
||||
case 'WCS_Email_Customer_Notification_Auto_Trial_Expiration':
|
||||
case 'WCS_Email_Customer_Notification_Manual_Renewal':
|
||||
case 'WCS_Email_Customer_Notification_Auto_Renewal':
|
||||
// Pull the real values from the email object (Order or Subscription) if available.
|
||||
if ( is_a( $email->object, 'WC_Subscription' ) ) {
|
||||
$time_until_renewal = $email->get_time_until_date( $email->object, 'next_payment' );
|
||||
$customer_first_name = $email->object->get_billing_first_name();
|
||||
} else {
|
||||
$time_until_renewal = human_time_diff( time(), time() + WEEK_IN_SECONDS );
|
||||
$customer_first_name = 'John';
|
||||
}
|
||||
|
||||
$placeholders['{time_until_renewal}'] = $time_until_renewal;
|
||||
$placeholders['{customers_first_name}'] = $customer_first_name;
|
||||
break;
|
||||
case 'WCS_Email_Customer_Payment_Retry':
|
||||
case 'WCS_Email_Payment_Retry':
|
||||
$retry_time = is_a( $email->retry, 'WCS_Retry' )
|
||||
? $email->retry->get_time()
|
||||
: time() + ( 12 * HOUR_IN_SECONDS );
|
||||
|
||||
$placeholders['{retry_time}'] = wcs_get_human_time_diff( $retry_time );
|
||||
break;
|
||||
}
|
||||
|
||||
// Merge placeholders without overriding existing ones, and only adding those in the email.
|
||||
$email->placeholders = wp_parse_args(
|
||||
$placeholders,
|
||||
$email->placeholders
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -37,6 +37,7 @@ class WCS_Email_Cancelled_Subscription extends WC_Email {
|
||||
add_action( 'cancelled_subscription_notification', array( $this, 'trigger' ) );
|
||||
|
||||
parent::__construct();
|
||||
$this->add_always_send_field();
|
||||
|
||||
$this->recipient = $this->get_option( 'recipient' );
|
||||
|
||||
@@ -45,6 +46,22 @@ class WCS_Email_Cancelled_Subscription extends WC_Email {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For the cancellation email, we add an extra setting to let the merchant decide if
|
||||
* they should *always* received cancellation emails (the default being to send them
|
||||
* only once, when they are first set to Pending Cancellation or Cancelled).
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_always_send_field() {
|
||||
$this->form_fields['always_send'] = [
|
||||
'title' => __( 'Always Send', 'woocommerce-subscriptions' ),
|
||||
'type' => 'checkbox',
|
||||
'label' => __( 'Send this email whenever a subscription is updated to "Pending Cancellation" or "Cancelled".', 'woocommerce-subscriptions' ),
|
||||
'default' => 'no',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default e-mail subject.
|
||||
*
|
||||
@@ -79,7 +96,13 @@ class WCS_Email_Cancelled_Subscription extends WC_Email {
|
||||
$subscription = wcs_get_subscription_from_key( $subscription );
|
||||
}
|
||||
|
||||
if ( ! $this->is_enabled() || ! $this->get_recipient() ) {
|
||||
if ( ! $this->is_enabled() || ! $this->get_recipient() || ! $subscription->has_status( array( 'pending-cancel', 'cancelled' ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Unless the merchant has requested that these emails should always be sent, avoid sending them twice for the same subscription
|
||||
// (which would otherwise happen once when the subscription is sent to 'pending-cancel', and again when it finally cancels).
|
||||
if ( 'yes' !== $this->get_option( 'always_send' ) && 'true' === $subscription->get_cancelled_email_sent() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@@ -108,7 +108,7 @@ function wcs_cart_totals_shipping_html() {
|
||||
<?php wcs_cart_print_shipping_input( $recurring_cart_package_key, $shipping_method ); ?>
|
||||
<?php do_action( 'woocommerce_after_shipping_rate', $shipping_method, $recurring_cart_package_key ); ?>
|
||||
<?php if ( ! empty( $show_package_details ) ) : ?>
|
||||
<?php echo '<p class="woocommerce-shipping-contents"><small>' . esc_html( $package_details ) . '</small></p>'; ?>
|
||||
<?php echo '<p class="woocommerce-shipping-contents"><small>' . wp_kses_post( $package_details ) . '</small></p>'; ?>
|
||||
<?php endif; ?>
|
||||
<?php if ( $recurring_rates_match_initial_rates ) : ?>
|
||||
<?php wcs_cart_print_inherit_shipping_flag( $recurring_cart_package_key ); ?>
|
||||
|
@@ -68,21 +68,69 @@ function wcs_get_subscriptions_for_order( $order, $args = array() ) {
|
||||
|
||||
$all_relation_types = WCS_Related_Order_Store::instance()->get_relation_types();
|
||||
$relation_types = $get_all ? $all_relation_types : array_intersect( $all_relation_types, $args['order_type'] );
|
||||
|
||||
foreach ( $relation_types as $relation_type ) {
|
||||
|
||||
$subscription_ids = WCS_Related_Order_Store::instance()->get_related_subscription_ids( $order, $relation_type );
|
||||
$subscription_ids = wcs_get_subscription_ids_for_order( $order, $relation_types );
|
||||
|
||||
foreach ( $subscription_ids as $subscription_id ) {
|
||||
if ( wcs_is_subscription( $subscription_id ) ) {
|
||||
$subscriptions[ $subscription_id ] = wcs_get_subscription( $subscription_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $subscriptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subscription IDs for an order.
|
||||
*
|
||||
* @param WC_Order $order The order to get the subscription IDs for.
|
||||
* @param string|array $order_types The order types to get the subscription IDs for. Defaults to 'any' which will return all subscription IDs linked to the order.
|
||||
*
|
||||
* @return array The subscription IDs.
|
||||
*/
|
||||
function wcs_get_subscription_ids_for_order( $order, $order_types = [ 'any' ] ) {
|
||||
$subscription_ids = [];
|
||||
|
||||
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
$order = wc_get_order( $order );
|
||||
}
|
||||
|
||||
if ( ! wcs_is_order( $order ) ) {
|
||||
return $subscription_ids;
|
||||
}
|
||||
|
||||
if ( ! is_array( $order_types ) ) {
|
||||
$order_types = [ $order_types ];
|
||||
}
|
||||
|
||||
$get_all = in_array( 'any', $order_types, true );
|
||||
$relation_types = WCS_Related_Order_Store::instance()->get_relation_types();
|
||||
$valid_order_types = $get_all ? $relation_types : array_intersect( $relation_types, $order_types );
|
||||
|
||||
foreach ( $valid_order_types as $order_type ) {
|
||||
$subscription_ids = array_merge( $subscription_ids, WCS_Related_Order_Store::instance()->get_related_subscription_ids( $order, $order_type ) );
|
||||
}
|
||||
|
||||
if ( $get_all || in_array( 'parent', $order_types, true ) ) {
|
||||
$subscription_ids_for_parent_order = wc_get_orders(
|
||||
[
|
||||
'parent' => $order->get_id(),
|
||||
'type' => 'shop_subscription',
|
||||
'status' => 'any',
|
||||
'limit' => -1,
|
||||
'return' => 'ids',
|
||||
]
|
||||
);
|
||||
|
||||
if ( is_array( $subscription_ids_for_parent_order ) ) {
|
||||
$subscription_ids = array_merge( $subscription_ids, $subscription_ids_for_parent_order );
|
||||
}
|
||||
}
|
||||
|
||||
rsort( $subscription_ids );
|
||||
|
||||
return $subscription_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the billing, shipping or all addresses from one order or subscription to another.
|
||||
*
|
||||
@@ -365,10 +413,7 @@ function wcs_order_contains_subscription( $order, $order_type = array( 'parent',
|
||||
$contains_subscription = false;
|
||||
$get_all = in_array( 'any', $order_type, true );
|
||||
|
||||
if ( ( in_array( 'parent', $order_type, true ) || $get_all ) && count( wcs_get_subscriptions_for_order( $order->get_id(), array( 'order_type' => 'parent' ) ) ) > 0 ) {
|
||||
$contains_subscription = true;
|
||||
|
||||
} elseif ( ( in_array( 'renewal', $order_type, true ) || $get_all ) && wcs_order_contains_renewal( $order ) ) {
|
||||
if ( ( in_array( 'renewal', $order_type, true ) || $get_all ) && wcs_order_contains_renewal( $order ) ) {
|
||||
$contains_subscription = true;
|
||||
|
||||
} elseif ( ( in_array( 'resubscribe', $order_type, true ) || $get_all ) && wcs_order_contains_resubscribe( $order ) ) {
|
||||
@@ -377,6 +422,8 @@ function wcs_order_contains_subscription( $order, $order_type = array( 'parent',
|
||||
} elseif ( ( in_array( 'switch', $order_type, true ) || $get_all ) && wcs_order_contains_switch( $order ) ) {
|
||||
$contains_subscription = true;
|
||||
|
||||
} elseif ( ( in_array( 'parent', $order_type, true ) || $get_all ) && wcs_order_contains_parent( $order ) ) {
|
||||
$contains_subscription = true;
|
||||
}
|
||||
|
||||
return $contains_subscription;
|
||||
@@ -1055,3 +1102,41 @@ function wcs_set_recurring_item_total( &$item ) {
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an order is a Subscriptions parent/initial order.
|
||||
*
|
||||
* @param WC_Order|int $order The WC_Order object or ID of a WC_Order order.
|
||||
*
|
||||
* @return bool Whether the order contains a parent.
|
||||
*/
|
||||
function wcs_order_contains_parent( $order ) {
|
||||
$order = ! is_object( $order ) ? wc_get_order( $order ) : $order;
|
||||
|
||||
if ( ! $order || ! wcs_is_order( $order ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the order ID is the parent of a subscription.
|
||||
$is_parent_order = wc_get_orders(
|
||||
[
|
||||
'parent' => $order->get_id(),
|
||||
'type' => 'shop_subscription',
|
||||
'status' => 'any',
|
||||
'limit' => 1,
|
||||
'return' => 'ids',
|
||||
]
|
||||
);
|
||||
|
||||
/**
|
||||
* Allow third-parties to filter whether this order should be considered a parent order.
|
||||
*
|
||||
* @since 7.3.0
|
||||
*
|
||||
* @param bool $is_parent_order True if parent meta was found on the order, otherwise false.
|
||||
* @param WC_Order $order The WC_Order object.
|
||||
*
|
||||
* @return bool True if the order contains a parent, otherwise false.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_subscriptions_is_parent_order', ! empty( $is_parent_order ), $order );
|
||||
}
|
||||
|
@@ -56,20 +56,18 @@ function wcs_create_renewal_order( $subscription ) {
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
function wcs_order_contains_renewal( $order ) {
|
||||
$is_renewal_order = false;
|
||||
|
||||
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
$order = wc_get_order( $order );
|
||||
}
|
||||
|
||||
$related_subscriptions = wcs_get_subscriptions_for_renewal_order( $order );
|
||||
|
||||
if ( wcs_is_order( $order ) && ! empty( $related_subscriptions ) ) {
|
||||
$is_renewal = true;
|
||||
} else {
|
||||
$is_renewal = false;
|
||||
if ( $order ) {
|
||||
$related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'renewal' );
|
||||
$is_renewal_order = ! empty( $related_subscription_ids );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscriptions_is_renewal_order', $is_renewal, $order );
|
||||
return apply_filters( 'woocommerce_subscriptions_is_renewal_order', $is_renewal_order, $order );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -21,17 +21,15 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
function wcs_order_contains_resubscribe( $order ) {
|
||||
$is_resubscribe_order = false;
|
||||
|
||||
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
$order = wc_get_order( $order );
|
||||
}
|
||||
|
||||
$related_subscriptions = wcs_get_subscriptions_for_resubscribe_order( $order );
|
||||
|
||||
if ( wcs_is_order( $order ) && ! empty( $related_subscriptions ) ) {
|
||||
$is_resubscribe_order = true;
|
||||
} else {
|
||||
$is_resubscribe_order = false;
|
||||
if ( $order ) {
|
||||
$related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'resubscribe' );
|
||||
$is_resubscribe_order = ! empty( $related_subscription_ids );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscriptions_is_resubscribe_order', $is_resubscribe_order, $order );
|
||||
|
@@ -19,24 +19,15 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.0
|
||||
*/
|
||||
function wcs_order_contains_switch( $order ) {
|
||||
$is_switch_order = false;
|
||||
|
||||
if ( ! is_a( $order, 'WC_Abstract_Order' ) ) {
|
||||
$order = wc_get_order( $order );
|
||||
}
|
||||
|
||||
if ( ! wcs_is_order( $order ) || wcs_order_contains_renewal( $order ) ) {
|
||||
|
||||
$is_switch_order = false;
|
||||
|
||||
} else {
|
||||
|
||||
$switched_subscriptions = wcs_get_subscriptions_for_switch_order( $order );
|
||||
|
||||
if ( ! empty( $switched_subscriptions ) ) {
|
||||
$is_switch_order = true;
|
||||
} else {
|
||||
$is_switch_order = false;
|
||||
}
|
||||
if ( $order ) {
|
||||
$related_subscription_ids = wcs_get_subscription_ids_for_order( $order, 'switch' );
|
||||
$is_switch_order = ! empty( $related_subscription_ids );
|
||||
}
|
||||
|
||||
return apply_filters( 'woocommerce_subscriptions_is_switch_order', $is_switch_order, $order );
|
||||
|
@@ -35,7 +35,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $show_package_details ) : ?>
|
||||
<?php echo '<p class="woocommerce-shipping-contents"><small>' . esc_html( $package_details ) . '</small></p>'; ?>
|
||||
<?php echo '<p class="woocommerce-shipping-contents"><small>' . wp_kses_post( $package_details ) . '</small></p>'; ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -2,35 +2,52 @@
|
||||
/**
|
||||
* Admin new renewal order email
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* Based on the WooCommerce core admin-new-order.php template.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php /* translators: $1: customer's billing first name and last name */ ?>
|
||||
<p><?php printf( esc_html_x( 'You have received a subscription renewal order from %1$s. Their order is as follows:', 'Used in admin email: new renewal order', 'woocommerce-subscriptions' ), esc_html( $order->get_formatted_billing_full_name() ) ); ?></p>
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @hooked WC_Subscriptions_Email::order_details() Shows the order details table.
|
||||
* @hooked WC_Subscriptions_Email::order_download_details() Shows the order downloads table.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1.0
|
||||
*/
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::order_meta() Shows order meta data.
|
||||
*/
|
||||
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::customer_details() Shows customer details
|
||||
* @hooked WC_Emails::email_address() Shows email address
|
||||
*/
|
||||
do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/**
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -1,27 +1,52 @@
|
||||
<?php
|
||||
/**
|
||||
* Admin new switch order email
|
||||
* Admin new switch order email.
|
||||
*
|
||||
* Based on the WooCommerce core admin-new-order.php template.
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
$switched_count = count( $subscriptions );
|
||||
|
||||
/* translators: $1: customer's first name and last name, $2: how many subscriptions customer switched */ ?>
|
||||
<p><?php echo esc_html( sprintf( _nx( 'Customer %1$s has switched their subscription. The details of their new subscription are as follows:', 'Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:', $switched_count, 'Used in switch notification admin email', 'woocommerce-subscriptions' ), $order->get_formatted_billing_full_name(), $switched_count ) );?></p>
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
?>
|
||||
<p>
|
||||
<?php
|
||||
if ( 1 === $switched_count ) {
|
||||
/* translators: $1: customer's first name and last name */
|
||||
echo esc_html( sprintf( _x( 'Customer %1$s has switched their subscription. The details of their new subscription are as follows:', 'Used in switch notification admin email', 'woocommerce-subscriptions' ), $order->get_formatted_billing_full_name() ) );
|
||||
} else {
|
||||
/* translators: $1: customer's first name and last name, $2: how many subscriptions customer switched */
|
||||
echo esc_html( sprintf( _x( 'Customer %1$s has switched %2$d of their subscriptions. The details of their new subscriptions are as follows:', 'Used in switch notification admin email', 'woocommerce-subscriptions' ), $order->get_formatted_billing_full_name(), $switched_count ) );
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<h2><?php esc_html_e( 'Switch Order Details', 'woocommerce-subscriptions' ); ?></h2>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @hooked WC_Subscriptions_Email::order_details() Shows the order details table.
|
||||
* @hooked WC_Subscriptions_Email::order_download_details() Shows the order downloads table.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1.0
|
||||
*/
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::order_meta() Shows order meta data.
|
||||
*/
|
||||
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
|
||||
?>
|
||||
|
||||
@@ -32,13 +57,19 @@ foreach ( $subscriptions as $subscription ) {
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent_to_admin, $plain_text, $email );
|
||||
}
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::customer_details() Shows customer details
|
||||
* @hooked WC_Emails::email_address() Shows email address
|
||||
*/
|
||||
do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/**
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<div class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -5,23 +5,24 @@
|
||||
* Email sent to admins when an attempt to automatically process a subscription renewal payment has failed
|
||||
* and a retry rule has been applied to retry the payment in the future.
|
||||
*
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails/Plain
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php /* translators: %1$s: an order number, %2$s: the customer's full name, %3$s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' */ ?>
|
||||
<p><?php echo esc_html( sprintf( _x( 'The automatic recurring payment for order #%d from %s has failed. The payment will be retried %3$s.', 'In customer renewal invoice email', 'woocommerce-subscriptions' ), $order->get_order_number(), $order->get_formatted_billing_full_name(), wcs_get_human_time_diff( $retry->get_time() ) ) ); ?></p>
|
||||
<p><?php echo esc_html( sprintf( _x( 'The automatic recurring payment for order #%1$d from %2$s has failed. The payment will be retried %3$s.', 'In customer renewal invoice email', 'woocommerce-subscriptions' ), $order->get_order_number(), $order->get_formatted_billing_full_name(), wcs_get_human_time_diff( $retry->get_time() ) ) ); ?></p>
|
||||
<p><?php esc_html_e( 'The renewal order is as follows:', 'woocommerce-subscriptions' ); ?></p>
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<?php
|
||||
|
||||
@@ -46,7 +47,9 @@ do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -2,18 +2,36 @@
|
||||
/**
|
||||
* Cancelled Subscription email
|
||||
*
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php /* translators: $1: customer's billing first name and last name */ ?>
|
||||
<p><?php printf( esc_html__( 'A subscription belonging to %1$s has been cancelled. Their subscription\'s details are as follows:', 'woocommerce-subscriptions' ), esc_html( $subscription->get_formatted_billing_full_name() ) );?></p>
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<p>
|
||||
<?php
|
||||
if ( 'pending-cancel' === $subscription->get_status() ) {
|
||||
printf(
|
||||
/* translators: $1$s customer's billing first name and last name %2$s: date on which the subscription ends. */
|
||||
esc_html__( 'A subscription belonging to %1$s is now pending cancellation, and will end on %2$s. Their subscription\'s details are as follows:', 'woocommerce-subscriptions' ),
|
||||
esc_html( $subscription->get_formatted_billing_full_name() ),
|
||||
esc_html( date_i18n( wc_date_format(), $subscription->get_time( 'end', 'site' ) ) )
|
||||
);
|
||||
} else {
|
||||
printf(
|
||||
/* translators: $1$s customer's billing first name and last name. */
|
||||
esc_html__( 'A subscription belonging to %1$s has been cancelled. Their subscription\'s details are as follows:', 'woocommerce-subscriptions' ),
|
||||
esc_html( $subscription->get_formatted_billing_full_name() )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" border="1">
|
||||
<thead>
|
||||
@@ -59,7 +77,9 @@ do_action( 'woocommerce_email_customer_details', $subscription, $sent_to_admin,
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,33 +2,53 @@
|
||||
/**
|
||||
* Customer completed renewal order email
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* Based on the WooCommerce core customer-completed-order.php template.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
<p><?php esc_html_e( 'We have finished processing your subscription renewal order.', 'woocommerce-subscriptions' ); ?></p>
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* @hooked WC_Subscriptions_Email::order_details() Shows the order details table.
|
||||
* @hooked WC_Subscriptions_Email::order_download_details() Shows the order downloads table.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1.0
|
||||
*/
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::order_meta() Shows order meta data.
|
||||
*/
|
||||
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::customer_details() Shows customer details
|
||||
* @hooked WC_Emails::email_address() Shows email address
|
||||
*/
|
||||
do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/**
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,24 +2,37 @@
|
||||
/**
|
||||
* Customer completed subscription change email
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* Based on the WooCommerce core customer-completed-order.php template.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
<p><?php esc_html_e( 'You have successfully changed your subscription items. Your new order and subscription details are shown below for your reference:', 'woocommerce-subscriptions' ); ?></p>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
<?php
|
||||
/**
|
||||
* @hooked WC_Subscriptions_Email::order_details() Shows the order details table.
|
||||
* @hooked WC_Subscriptions_Email::order_download_details() Shows the order downloads table.
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.1.0
|
||||
*/
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::order_meta() Shows order meta data.
|
||||
*/
|
||||
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
|
||||
?>
|
||||
|
||||
@@ -30,13 +43,19 @@ foreach ( $subscriptions as $subscription ) {
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent_to_admin, $plain_text, $email );
|
||||
}
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::customer_details() Shows customer details
|
||||
* @hooked WC_Emails::email_address() Shows email address
|
||||
*/
|
||||
do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
/**
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -3,11 +3,12 @@
|
||||
* Customer Notification: Notify the customer that an automated renewal their subscription is about to happen.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 7.2.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header.
|
||||
@@ -16,6 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<p>
|
||||
<?php
|
||||
echo esc_html(
|
||||
@@ -27,8 +29,6 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
@@ -46,6 +46,7 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
?>
|
||||
</p>
|
||||
<?php
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
|
||||
// Show subscription details.
|
||||
\WC_Subscriptions_Email::subscription_details( $subscription, $order, $sent_to_admin, $plain_text, true );
|
||||
@@ -84,7 +85,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,19 +3,20 @@
|
||||
* Customer Notification: Free trial of an automatically renewed subscription is about to expire email.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 7.2.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header.
|
||||
*
|
||||
* @since 6.9.0
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<p>
|
||||
<?php
|
||||
echo esc_html(
|
||||
@@ -27,8 +28,6 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
@@ -45,7 +44,6 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<?php
|
||||
|
||||
@@ -60,6 +58,7 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
?>
|
||||
</p>
|
||||
<?php
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
|
||||
// Show subscription details.
|
||||
\WC_Subscriptions_Email::subscription_details( $subscription, $order, $sent_to_admin, $plain_text, true );
|
||||
@@ -71,7 +70,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,11 +3,11 @@
|
||||
* Customer Notification: Subscription is about to expire email.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 7.2.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header.
|
||||
@@ -15,8 +15,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
* @since 6.9.0
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<p>
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
@@ -57,7 +56,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,11 +3,12 @@
|
||||
* Customer Notification: Manual renewal needed.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 7.2.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header.
|
||||
@@ -16,7 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
|
||||
<p>
|
||||
<?php echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<?php
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
@@ -99,7 +100,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,19 +3,20 @@
|
||||
* Customer Notification: Free trial of a manually renewed subscription is about to expire email.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 7.2.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/**
|
||||
* @hooked WC_Emails::email_header() Output the email header.
|
||||
*
|
||||
* @since 6.9.0
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : ''; ?>
|
||||
<p>
|
||||
<?php
|
||||
echo esc_html(
|
||||
@@ -27,8 +28,6 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
@@ -45,10 +44,8 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
<?php
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
|
||||
// Show subscription details.
|
||||
\WC_Subscriptions_Email::subscription_details( $subscription, $order, $sent_to_admin, $plain_text );
|
||||
@@ -60,7 +57,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $subscription, $sent
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -3,21 +3,24 @@
|
||||
* Customer on-hold renewal order email.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v3.0.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
/*
|
||||
* @hooked WC_Emails::email_header() Output the email header
|
||||
*/
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
/* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
<p><?php esc_html_e( 'Thanks for your renewal order. It’s on-hold until we confirm that payment has been received. In the meantime, here’s a reminder of your order:', 'woocommerce-subscriptions' ); ?></p>
|
||||
|
||||
<?php
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
|
||||
/*
|
||||
* @hooked WC_Subscriptions_Email::order_download_details() Shows the order details table.
|
||||
@@ -40,7 +43,9 @@ do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -2,17 +2,18 @@
|
||||
/**
|
||||
* Customer payment retry email
|
||||
*
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
|
||||
/* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
<?php /* translators: %s: lowercase human time diff in the form returned by wcs_get_human_time_diff(), e.g. 'in 12 hours' */ ?>
|
||||
<p><?php printf( esc_html_x( 'The automatic payment to renew your subscription has failed. We will retry the payment %s.', 'In customer renewal invoice email', 'woocommerce-subscriptions' ), esc_html( wcs_get_human_time_diff( $retry->get_time() ) ) ); ?></p>
|
||||
@@ -20,6 +21,8 @@ do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
<?php /* translators: %1$s %2$s: link markup to checkout payment url, note: no full stop due to url at the end */ ?>
|
||||
<p><?php echo wp_kses( sprintf( _x( 'To reactivate the subscription now, you can also log in and pay for the renewal from your account page: %1$sPay Now »%2$s', 'In customer renewal invoice email', 'woocommerce-subscriptions' ), '<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">', '</a>' ), array( 'a' => array( 'href' => true ) ) ); ?></p>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<?php
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
@@ -27,7 +30,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_adm
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<div class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,23 +2,25 @@
|
||||
/**
|
||||
* Customer processing renewal order email
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
|
||||
/* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
<?php /* translators: %s: Order number */ ?>
|
||||
<p><?php printf( esc_html__( 'Just to let you know — we\'ve received your subscription renewal order #%s, and it is now being processed:', 'woocommerce-subscriptions' ), esc_html( $order->get_order_number() ) ); ?></p>
|
||||
|
||||
<?php
|
||||
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, $email );
|
||||
@@ -29,7 +31,9 @@ do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,39 +2,68 @@
|
||||
/**
|
||||
* Customer renewal invoice email
|
||||
*
|
||||
* @author Brent Shepherd
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
<?php /* translators: %s: Customer first name */ ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
|
||||
/* translators: %s: Customer first name */ ?>
|
||||
<p><?php printf( esc_html__( 'Hi %s,', 'woocommerce-subscriptions' ), esc_html( $order->get_billing_first_name() ) ); ?></p>
|
||||
|
||||
<?php if ( $order->has_status( 'pending' ) ) : ?>
|
||||
<p><?php echo wp_kses(
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
// translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end
|
||||
_x( 'An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s', 'In customer renewal invoice email', 'woocommerce-subscriptions' ),
|
||||
// translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end.
|
||||
_x(
|
||||
'An order has been created for you to renew your subscription on %1$s. To pay for this invoice please use the following link: %2$s',
|
||||
'In customer renewal invoice email',
|
||||
'woocommerce-subscriptions'
|
||||
),
|
||||
esc_html( get_bloginfo( 'name' ) ),
|
||||
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">' . esc_html__( 'Pay Now »', 'woocommerce-subscriptions' ) . '</a>'
|
||||
), array( 'a' => array( 'href' => true ) ) ); ?>
|
||||
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">'
|
||||
. esc_html__( 'Pay Now »', 'woocommerce-subscriptions' ) .
|
||||
'</a>'
|
||||
),
|
||||
[
|
||||
'a' => [ 'href' => true ],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php elseif ( $order->has_status( 'failed' ) ) : ?>
|
||||
<p><?php echo wp_kses(
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
sprintf(
|
||||
// translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end
|
||||
_x( 'The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s', 'In customer renewal invoice email', 'woocommerce-subscriptions' ),
|
||||
// translators: %1$s: name of the blog, %2$s: link to checkout payment url, note: no full stop due to url at the end.
|
||||
_x(
|
||||
'The automatic payment to renew your subscription with %1$s has failed. To reactivate the subscription, please log in and pay for the renewal from your account page: %2$s',
|
||||
'In customer renewal invoice email',
|
||||
'woocommerce-subscriptions'
|
||||
),
|
||||
esc_html( get_bloginfo( 'name' ) ),
|
||||
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">' . esc_html__( 'Pay Now »', 'woocommerce-subscriptions' ) . '</a>'
|
||||
), array( 'a' => array( 'href' => true ) ) ); ?>
|
||||
'<a href="' . esc_url( $order->get_checkout_payment_url() ) . '">'
|
||||
. esc_html__( 'Pay Now »', 'woocommerce-subscriptions' ) .
|
||||
'</a>'
|
||||
),
|
||||
[
|
||||
'a' => [ 'href' => true ],
|
||||
]
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<?php
|
||||
do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
@@ -42,7 +71,9 @@ do_action( 'woocommerce_subscriptions_email_order_details', $order, $sent_to_adm
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<div class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</div>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,35 +2,66 @@
|
||||
/**
|
||||
* Order/Subscription details table shown in emails.
|
||||
*
|
||||
* @author Prospress
|
||||
* Based on the WooCommerce core email-order-details.php template.
|
||||
*
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v3.0.0
|
||||
* @version 7.3.0
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
$text_align = is_rtl() ? 'right' : 'left';
|
||||
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
$heading_class = $email_improvements_enabled ? 'email-order-detail-heading' : '';
|
||||
$order_table_class = $email_improvements_enabled ? 'email-order-details' : '';
|
||||
$order_total_text_align = $email_improvements_enabled ? 'right' : 'left';
|
||||
|
||||
if ( $email_improvements_enabled ) {
|
||||
add_filter( 'woocommerce_order_shipping_to_display_shipped_via', '__return_false' );
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_before_' . $order_type . '_table', $order, $sent_to_admin, $plain_text, $email );
|
||||
|
||||
if ( 'cancelled_subscription' != $email->id ) {
|
||||
echo '<h2>';
|
||||
if ( 'cancelled_subscription' !== $email->id ) {
|
||||
echo '<h2 class="' . esc_attr( $heading_class ) . '">';
|
||||
|
||||
$link_element_url = ( $sent_to_admin ) ? wcs_get_edit_post_link( wcs_get_objects_property( $order, 'id' ) ) : $order->get_view_order_url();
|
||||
$id_heading = sprintf(
|
||||
/* translators: %s: Order or subscription ID. */
|
||||
( 'order' === $order_type ) ? __( 'Order #%s', 'woocommerce-subscriptions' ) : __( 'Subscription #%s', 'woocommerce-subscriptions' ),
|
||||
$order->get_order_number()
|
||||
);
|
||||
|
||||
if ( 'order' == $order_type ) {
|
||||
// translators: $1-$2: opening and closing <a> tags $3: order's order number $4: date of order in <time> element
|
||||
printf( esc_html_x( '%1$sOrder #%3$s%2$s (%4$s)', 'Used in email notification', 'woocommerce-subscriptions' ), '<a href="' . esc_url( $link_element_url ) . '">', '</a>', esc_html( $order->get_order_number() ), sprintf( '<time datetime="%s">%s</time>', esc_attr( wcs_get_objects_property( $order, 'date_created' )->format( 'c' ) ), esc_html( wcs_format_datetime( wcs_get_objects_property( $order, 'date_created' ) ) ) ) );
|
||||
if ( $email_improvements_enabled ) {
|
||||
$heading = ( 'order' === $order_type ) ? __( 'Order summary', 'woocommerce-subscriptions' ) : __( 'Subscription summary', 'woocommerce-subscriptions' );
|
||||
echo wp_kses_post( $heading );
|
||||
echo '<span>';
|
||||
} else {
|
||||
// translators: $1-$3: opening and closing <a> tags $2: subscription's order number
|
||||
printf( esc_html_x( 'Subscription %1$s#%2$s%3$s', 'Used in email notification', 'woocommerce-subscriptions' ), '<a href="' . esc_url( $link_element_url ) . '">', esc_html( $order->get_order_number() ), '</a>' );
|
||||
// Prior to the email improvements, the sub_heading was wrapped in square brackets.
|
||||
$id_heading = '[' . $id_heading . ']';
|
||||
}
|
||||
|
||||
echo wp_kses_post(
|
||||
sprintf(
|
||||
'%s%s%s (<time datetime="%s">%s</time>)',
|
||||
'<a class="link" href="' . esc_url( ( $sent_to_admin ) ? wcs_get_edit_post_link( $order->get_id() ) : $order->get_view_order_url() ) . '">',
|
||||
$id_heading,
|
||||
'</a>',
|
||||
$order->get_date_created()->format( 'c' ),
|
||||
wcs_format_datetime( $order->get_date_created() )
|
||||
)
|
||||
);
|
||||
|
||||
if ( $email_improvements_enabled ) {
|
||||
echo '</span>';
|
||||
}
|
||||
|
||||
echo '</h2>';
|
||||
}
|
||||
?>
|
||||
<div style="margin-bottom: 40px;">
|
||||
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" border="1">
|
||||
<div style="margin-bottom: <?php echo $email_improvements_enabled ? '24px' : '40px'; ?>;">
|
||||
<table class="td font-family <?php echo esc_attr( $order_table_class ); ?>" cellspacing="0" cellpadding="6" style="width: 100%;" border="1">
|
||||
<?php if ( ! $email_improvements_enabled ) { ?>
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="td" scope="col" style="text-align:<?php echo esc_attr( $text_align ); ?>;"><?php echo esc_html_x( 'Product', 'table headings in notification email', 'woocommerce-subscriptions' ); ?></th>
|
||||
@@ -38,30 +69,53 @@ if ( 'cancelled_subscription' != $email->id ) {
|
||||
<th class="td" scope="col" style="text-align:<?php echo esc_attr( $text_align ); ?>;"><?php echo esc_html_x( 'Price', 'table headings in notification email', 'woocommerce-subscriptions' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<?php } ?>
|
||||
<tbody>
|
||||
<?php echo wp_kses_post( WC_Subscriptions_Email::email_order_items_table( $order, $order_items_table_args ) ); ?>
|
||||
</tbody>
|
||||
<tfoot>
|
||||
<?php
|
||||
if ( $totals = $order->get_order_item_totals() ) {
|
||||
$item_totals = $order->get_order_item_totals();
|
||||
$item_totals_count = count( $item_totals );
|
||||
|
||||
if ( $item_totals ) {
|
||||
$i = 0;
|
||||
foreach ( $totals as $total ) {
|
||||
foreach ( $item_totals as $total ) {
|
||||
$i++;
|
||||
$last_class = ( $i === $item_totals_count ) ? ' order-totals-last' : '';
|
||||
?>
|
||||
<tr>
|
||||
<th class="td" scope="row" colspan="2" style="text-align:<?php echo esc_attr( $text_align ); ?>; <?php if ( 1 == $i ) { echo 'border-top-width: 4px;'; } ?>"><?php echo esc_html( $total['label'] ); ?></th>
|
||||
<td class="td" style="text-align:<?php echo esc_attr( $text_align ); ?>; <?php if ( 1 == $i ) { echo 'border-top-width: 4px;'; } ?>"><?php echo wp_kses_post( $total['value'] ); ?></td>
|
||||
<tr class="order-totals order-totals-<?php echo esc_attr( $total['type'] ?? 'unknown' ); ?><?php echo esc_attr( $last_class ); ?>">
|
||||
<th class="td text-align-left" scope="row" colspan="2" style="<?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>">
|
||||
<?php
|
||||
echo wp_kses_post( $total['label'] ) . ' ';
|
||||
if ( $email_improvements_enabled ) {
|
||||
echo isset( $total['meta'] ) ? wp_kses_post( $total['meta'] ) : '';
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<td class="td text-align-<?php echo esc_attr( $order_total_text_align ); ?>" style="<?php echo ( 1 === $i ) ? 'border-top-width: 4px;' : ''; ?>"><?php echo wp_kses_post( $total['value'] ); ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
if ( $order->get_customer_note() ) {
|
||||
if ( $email_improvements_enabled ) {
|
||||
?>
|
||||
<tr>
|
||||
<th class="td" scope="row" colspan="2" style="text-align:<?php echo esc_attr( $text_align ); ?>;"><?php esc_html_e( 'Note:', 'woocommerce-subscriptions' ); ?></th>
|
||||
<td class="td" style="text-align:<?php echo esc_attr( $text_align ); ?>;"><?php echo wp_kses_post( wptexturize( $order->get_customer_note() ) ); ?></td>
|
||||
<tr class="order-customer-note">
|
||||
<td class="td text-align-left" colspan="3">
|
||||
<b><?php esc_html_e( 'Customer note', 'woocommerce-subscriptions' ); ?></b><br>
|
||||
<?php echo wp_kses( nl2br( wptexturize( $order->get_customer_note() ) ), array( 'br' => array() ) ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<tr>
|
||||
<th class="td text-align-left" scope="row" colspan="2"><?php esc_html_e( 'Note:', 'woocommerce-subscriptions' ); ?></th>
|
||||
<td class="td text-align-left"><?php echo wp_kses( nl2br( wptexturize( $order->get_customer_note() ) ), array() ); ?></td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
</tfoot>
|
||||
|
@@ -2,19 +2,22 @@
|
||||
/**
|
||||
* Cancelled Subscription email
|
||||
*
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
<?php /* translators: $1: customer's billing first name and last name */ ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
|
||||
/* translators: $1: customer's billing first name and last name */ ?>
|
||||
<p><?php printf( esc_html__( 'A subscription belonging to %1$s has expired. Their subscription\'s details are as follows:', 'woocommerce-subscriptions' ), esc_html( $subscription->get_formatted_billing_full_name() ) ); ?></p>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -60,7 +63,9 @@ do_action( 'woocommerce_email_customer_details', $subscription, $sent_to_admin,
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -2,19 +2,22 @@
|
||||
/**
|
||||
* Cancelled Subscription email
|
||||
*
|
||||
* @author Prospress
|
||||
* @package WooCommerce_Subscriptions/Templates/Emails
|
||||
* @version 1.0.0 - Migrated from WooCommerce Subscriptions v2.6.0
|
||||
* @version 7.3.0 - Updated for WC core email improvements.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email ); ?>
|
||||
$email_improvements_enabled = wcs_is_wc_feature_enabled( 'email_improvements' );
|
||||
|
||||
<?php /* translators: $1: customer's billing first name and last name */ ?>
|
||||
do_action( 'woocommerce_email_header', $email_heading, $email );
|
||||
|
||||
echo $email_improvements_enabled ? '<div class="email-introduction">' : '';
|
||||
|
||||
/* translators: $1: customer's billing first name and last name */ ?>
|
||||
<p><?php printf( esc_html__( 'A subscription belonging to %1$s has been suspended by the user. Their subscription\'s details are as follows:', 'woocommerce-subscriptions' ), esc_html( $subscription->get_formatted_billing_full_name() ) ); ?></p>
|
||||
|
||||
<?php echo $email_improvements_enabled ? '</div>' : ''; ?>
|
||||
|
||||
<table class="td" cellspacing="0" cellpadding="6" style="width: 100%; font-family: 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif;" border="1">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -59,7 +62,9 @@ do_action( 'woocommerce_email_customer_details', $subscription, $sent_to_admin,
|
||||
* Show user-defined additional content - this is set in each email's settings.
|
||||
*/
|
||||
if ( $additional_content ) {
|
||||
echo $email_improvements_enabled ? '<table border="0" cellpadding="0" cellspacing="0" width="100%"><tr><td class="email-additional-content">' : '';
|
||||
echo wp_kses_post( wpautop( wptexturize( $additional_content ) ) );
|
||||
echo $email_improvements_enabled ? '</td></tr></table>' : '';
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_email_footer', $email );
|
||||
|
@@ -342,7 +342,7 @@ function wcs_get_date_meta_key( $date_type ) {
|
||||
* deprecated date type key.
|
||||
*
|
||||
* @since 1.0.0 - Migrated from WooCommerce Subscriptions v2.2.0
|
||||
* @param string $date_type_key String referring to a valid date type, can be: 'date_created', 'trial_end', 'next_payment', 'last_order_date_created' or 'end', or any other value returned by @see this->get_valid_date_types()
|
||||
* @param string $date_type_key String referring to a valid date type, can be: 'date_created', 'trial_end', 'next_payment', 'last_order_date_created' or 'end', or any other value returned by @see WC_Subscription::get_valid_date_types()
|
||||
* @return string
|
||||
*/
|
||||
function wcs_normalise_date_type_key( $date_type_key, $display_deprecated_notice = false ) {
|
||||
|
@@ -6,5 +6,5 @@
|
||||
* Author: Automattic
|
||||
* Author URI: https://woocommerce.com/
|
||||
* Requires WP: 5.6
|
||||
* Version: 8.0.1
|
||||
* Version: 8.1.0
|
||||
*/
|
||||
|
@@ -5,11 +5,11 @@
|
||||
* Description: Sell products and services with recurring payments in your WooCommerce Store.
|
||||
* Author: WooCommerce
|
||||
* Author URI: https://woocommerce.com/
|
||||
* Version: 7.2.1
|
||||
* Version: 7.3.0
|
||||
* Requires Plugins: woocommerce
|
||||
*
|
||||
* WC requires at least: 8.7.1
|
||||
* WC tested up to: 9.7
|
||||
* WC tested up to: 9.8.0
|
||||
* Woo: 27147:6115e6d7e297b623a169fdcf5728b224
|
||||
*
|
||||
* Copyright 2019 WooCommerce
|
||||
@@ -78,7 +78,7 @@ class WC_Subscriptions {
|
||||
public static $plugin_file = __FILE__;
|
||||
|
||||
/** @var string */
|
||||
public static $version = '7.2.1'; // WRCS: DEFINED_VERSION.
|
||||
public static $version = '7.3.0'; // WRCS: DEFINED_VERSION.
|
||||
|
||||
/** @var string */
|
||||
public static $wc_minimum_supported_version = '7.7';
|
||||
|
Reference in New Issue
Block a user