Below is a differential between the unpatched vulnerable code and the patched update, for reference.
--- a/the-events-calendar/common/src/Common/Admin/Help_Hub/Hub.php
+++ b/the-events-calendar/common/src/Common/Admin/Help_Hub/Hub.php
@@ -428,8 +428,10 @@
* @return void
*/
public function register_iframe_hooks() {
- add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_help_page_iframe_assets' ] );
- add_action( 'wp_enqueue_scripts', [ __CLASS__, 'dequeue_theme_styles' ] );
+ add_action( 'tec_help_hub_iframe_header', [ $this, 'enqueue_help_page_iframe_assets' ] );
+ add_filter( 'emoji_svg_url', '__return_false' );
+ remove_action( 'wp_print_styles', 'print_emoji_styles' );
+ remove_action( 'wp_head', 'print_emoji_styles' );
}
/**
@@ -443,18 +445,18 @@
tribe_asset(
Tribe__Main::instance(),
- 'help-hub-iframe-style',
+ 'tec-help-hub-iframe-style',
'help-hub-iframe.css',
- null,
- 'wp_enqueue_scripts'
+ [],
+ [],
);
tribe_asset(
Tribe__Main::instance(),
- 'help-hub-iframe-js',
+ 'tec-help-hub-iframe-js',
'admin/help-hub-iframe.js',
- null,
- 'wp_enqueue_scripts',
+ [],
+ [],
[
'localize' => [
'name' => 'helpHubSettings',
@@ -465,6 +467,10 @@
],
]
);
+
+ tribe_asset_enqueue( 'tec-help-hub-iframe-style' );
+ tribe_asset_enqueue( 'tec-help-hub-iframe-js' );
+ tribe_asset_enqueue( 'tribe-common-full-style' );
}
/**
--- a/the-events-calendar/common/src/Tribe/Main.php
+++ b/the-events-calendar/common/src/Tribe/Main.php
@@ -20,7 +20,7 @@
const OPTIONNAME = 'tribe_events_calendar_options';
const OPTIONNAMENETWORK = 'tribe_events_calendar_network_options';
const FEED_URL = 'https://theeventscalendar.com/feed/';
- const VERSION = '6.4.1';
+ const VERSION = '6.4.2';
protected $plugin_context;
protected $plugin_context_class;
@@ -485,6 +485,18 @@
add_filter( 'body_class', [ $this, 'add_js_class' ] );
add_action( 'wp_footer', [ $this, 'toggle_js_class' ] );
+
+ add_action( 'init', [ $this, 'load_action_scheduler' ], - 99999 );
+ }
+
+ /**
+ * Load the Action Scheduler library.
+ *
+ * @since TDB
+ */
+ public function load_action_scheduler(): void {
+ // Load the Action Scheduler library.
+ require_once $this->plugin_path . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
}
/**
--- a/the-events-calendar/common/src/Tribe/PUE/Checker.php
+++ b/the-events-calendar/common/src/Tribe/PUE/Checker.php
@@ -8,6 +8,8 @@
* @todo switch all plugins over to use the PUE utilities here in Commons
*/
+use TECCommonStellarWPUplinkConfig;
+
use function TECCommonStellarWPUplinkget_resource;
// Don't load directly.
@@ -220,21 +222,50 @@
$this->set_options( $options );
$this->hooks();
$this->set_key_status_name();
+ $this->init( $slug );
// So we can reference our "registered" instances later.
self::$instances[ $slug ] ??= $this;
}
/**
+ * Initializes the PUE checker and fires the appropriate action if not already initialized.
+ *
+ * This method ensures that the `tec_pue_checker_init` action is fired only once per unique slug.
+ *
+ * @since 6.4.2
+ *
+ * @param string $slug The unique slug for the plugin being initialized.
+ */
+ public function init( $slug ) {
+ if ( isset( self::$instances[ $slug ] ) ) {
+ return;
+ }
+
+ /**
+ * Fires when initializing the PUE checker.
+ *
+ * @since 6.4.2
+ *
+ * @param Tribe__PUE__Checker $checker An instance of the PUE Checker being initialized.
+ */
+ do_action( 'tec_pue_checker_init', $this );
+ }
+
+ /**
* Gets whether the license key is valid or not.
*
* @since 4.14.9
* @since 6.4.1 Added uplink resource check.
+ * @since 6.4.2 Added check for valid plugin.
*/
public function is_key_valid() {
- $uplink_resource = get_resource( $this->get_slug() );
+ $uplink_resource = $this->get_uplink_resource( $this->get_slug() );
if ( $uplink_resource ) {
- return $uplink_resource->has_valid_license();
+ $uplink_status = $uplink_resource->has_valid_license();
+ $this->update_any_license_valid_transient( $this->get_slug(), tribe_is_truthy( $uplink_status ) );
+
+ return $uplink_status;
}
// @todo remove transient in a major feature release where we release all plugins.
@@ -244,58 +275,100 @@
$status = get_option( $this->pue_key_status_option_name, 'invalid' );
}
+ $this->update_any_license_valid_transient( $this->get_slug(), 'valid' === $status );
+
return 'valid' === $status;
}
/**
+ * Helper function to check the transient structure and if any plugin is valid.
+ *
+ * @since 6.4.2
+ *
+ * @param array|null $transient_value The current transient value.
+ *
+ * @return bool True if a valid license is found, otherwise false.
+ */
+ protected static function transient_contains_valid_license( ?array $transient_value ): bool {
+ if ( ! is_array( $transient_value ) || ! isset( $transient_value['plugins'] ) ) {
+ return false;
+ }
+
+ return in_array( true, $transient_value['plugins'] );
+ }
+
+ /**
+ * Updates the license status in the global transient.
+ *
+ * @since 6.4.2
+ *
+ * @param string $plugin_slug The slug of the plugin being updated.
+ * @param bool $status The license status.
+ */
+ protected static function update_any_license_valid_transient( string $plugin_slug, bool $status ): void {
+ $transient_value = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY ) ?: [ 'plugins' => [] ];
+
+ // If the transient value is false or a string, initialize it as an empty array with the 'plugins' key.
+ if ( ! is_array( $transient_value ) ) {
+ $transient_value = [ 'plugins' => [] ];
+ }
+
+ $transient_value['plugins'][ $plugin_slug ] = $status;
+
+ set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $transient_value, HOUR_IN_SECONDS );
+ }
+
+ /**
* Iterate on all the registered PUE Product Licenses we have and find if any are valid.
* Will revalidate the licenses if none are found to be valid.
*
- * @todo In scenarios where a user goes from a Free license to an active license the transient may give a false positive.
- *
* @since 6.3.2
+ * @since 6.4.2 Refactored logic to account for the transient structure.
*
* @return bool
*/
public static function is_any_license_valid(): bool {
- $valid_slug = 'valid';
- $has_valid = false;
-
- // Check our transient.
$transient_value = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY );
- if ( ! empty( $transient_value ) ) {
- return $transient_value === $valid_slug;
+
+ if ( ! is_array( $transient_value ) ) {
+ $transient_value = [];
}
- // Check our local transient/cache first.
- foreach ( self::$instances as $checker ) {
- if ( $checker->is_key_valid() ) {
- set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $valid_slug, HOUR_IN_SECONDS );
- $has_valid = true;
- break;
- }
+ // Check if the transient has a valid license.
+ if ( self::transient_contains_valid_license( $transient_value ) ) {
+ return true;
}
- if ( ! $has_valid ) {
- // Revalidate if we haven't found a valid license yet.
- foreach ( self::$instances as $checker ) {
- $license = get_option( $checker->get_license_option_key() );
- $response = $checker->validate_key( $license );
- // Is it valid?
- if ( ! empty( $response['status'] ) ) {
- set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, $valid_slug, HOUR_IN_SECONDS );
- $has_valid = true;
- break;
- }
- }
+ // Ensure instances exist.
+ if ( empty( self::$instances ) ) {
+ set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, [ 'plugins' => [] ], HOUR_IN_SECONDS );
+
+ return false;
}
- // We found no valid licenses above.
- if ( ! $has_valid ) {
- set_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY, 'invalid', HOUR_IN_SECONDS );
+ // Revalidate licenses.
+ foreach ( self::$instances as $plugin_slug => $checker ) {
+ // First, check if the key is already valid.
+ if ( $checker->is_key_valid() ) {
+ self::update_any_license_valid_transient( $plugin_slug, true );
+
+ return true;
+ }
+
+ // If not valid, attempt to revalidate the license.
+ $license = get_option( $checker->get_license_option_key() );
+ $response = $checker->validate_key( $license );
+
+ if ( ! empty( $response['status'] ) ) {
+ self::update_any_license_valid_transient( $plugin_slug, true );
+
+ return true;
+ } else {
+ self::update_any_license_valid_transient( $plugin_slug, false );
+ }
}
- return get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY ) === $valid_slug;
+ return false;
}
/**
@@ -341,6 +414,7 @@
* Sets the key status based on the key validation check results.
*
* @since 4.14.9
+ * @since 6.4.2 Clear `self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY` when a key is checked.
*
* @param int $valid 0 for invalid, 1 or 2 for valid.
*/
@@ -352,6 +426,9 @@
// We set a transient in addition to an option for compatibility reasons.
// @todo remove transient in a major feature release where we release all plugins.
set_transient( $this->pue_key_status_transient_name, $status, $this->check_period * HOUR_IN_SECONDS );
+
+ // Update the global license transient.
+ self::update_any_license_valid_transient( $this->get_slug(), tribe_is_truthy( $valid ) );
}
/**
@@ -369,7 +446,7 @@
/**
* Install the hooks required to run periodic update checks and inject update info
* into WP data structures.
- * Also other hooks related to the automatic updates (such as checking agains API and what not (@from Darren)
+ * Also other hooks related to the automatic updates (such as checking against API and what not (@from Darren)
*/
public function hooks() {
// Override requests for plugin information.
@@ -397,6 +474,9 @@
// Package name.
add_filter( 'upgrader_pre_download', [ Tribe__PUE__Package_Handler::instance(), 'filter_upgrader_pre_download' ], 5, 3 );
+
+ add_action( 'admin_init', [ $this, 'monitor_uplink_actions' ], 1000 );
+ add_action( 'tec_pue_checker_init', [ __CLASS__, 'monitor_active_plugins' ] );
}
@@ -1014,7 +1094,7 @@
*/
public function get_key( $type = 'any', $return_type = 'key' ) {
- $resource = get_resource( $this->get_slug() );
+ $resource = $this->get_uplink_resource( $this->get_slug() );
$license_key = $resource ? $resource->get_license_key( $type ) : false;
if ( $license_key ) {
return $license_key;
@@ -1105,7 +1185,7 @@
$response = [];
$response['status'] = 0;
- $uplink_resource = get_resource( $this->get_slug() );
+ $uplink_resource = $this->get_uplink_resource( $this->get_slug() );
if ( $uplink_resource ) {
$key = $uplink_resource->get_license_key();
@@ -1641,6 +1721,8 @@
$all_plugins = get_plugins();
if ( array_key_exists( $this->get_plugin_file(), $all_plugins ) && array_key_exists( 'Version', $all_plugins[ $this->get_plugin_file() ] ) ) {
return $all_plugins[ $this->get_plugin_file() ]['Version'];
+ } else {
+ return '';
}
}
}
@@ -2088,5 +2170,65 @@
return true;
}
+
+ /**
+ * Hooks into the Uplink plugin's 'connected' action for the current plugin.
+ *
+ * This method registers a callback for the 'stellarwp/uplink/{slug}/connected' action.
+ * When the action is triggered, it updates the license validity transient for the plugin.
+ *
+ * @since 6.4.2
+ *
+ * @return void
+ */
+ public static function monitor_uplink_actions(): void {
+ // Hook into the existing 'connected' action for the specific plugin slug.
+ add_action(
+ 'stellarwp/uplink/' . Config::get_hook_prefix() . '/connected',
+ function ( $plugin ) {
+ self::update_any_license_valid_transient( $plugin->get_slug(), true );
+ },
+ );
+ }
+
+ /**
+ * Monitor active plugins and validate the transient for the given slug.
+ *
+ * @param Tribe__PUE__Checker $checker An instance of the PUE Checker.
+ */
+ public static function monitor_active_plugins( Tribe__PUE__Checker $checker ): void {
+ $current_plugin_list = array_unique( array_merge( array_keys( self::$instances ), [ $checker->get_slug() ] ) );
+
+ // Retrieve or initialize transient data.
+ $transient_data = get_transient( self::IS_ANY_LICENSE_VALID_TRANSIENT_KEY ) ?: [ 'plugins' => [] ];
+ $transient_data['plugins'] = is_array( $transient_data['plugins'] ) ? $transient_data['plugins'] : [];
+
+ // Check if the missing plugins are valid, which adds the transients automatically.
+ foreach ( $current_plugin_list as $plugin_slug ) {
+ if ( ! isset( $transient_data['plugins'][ $plugin_slug ] ) ) {
+ $transient_data['plugins'][ $plugin_slug ] = $checker->is_key_valid();
+ }
+ }
+
+ }
+
+ /**
+ * Retrieves the uplink resource for the given slug, if available.
+ *
+ * Ensures the `get_resource()` function exists before calling it.
+ *
+ * @param string $slug The slug of the resource to retrieve.
+ *
+ * @return mixed The resource object if available, or `null` if the function does not exist or fails to retrieve the resource.
+ */
+ public function get_uplink_resource( string $slug ) {
+ try {
+ $resource = get_resource( $slug );
+ } catch ( Throwable $e ) {
+ return null;
+ }
+
+ return $resource;
+ }
}
}
--- a/the-events-calendar/common/src/Tribe/PUE/Notices.php
+++ b/the-events-calendar/common/src/Tribe/PUE/Notices.php
@@ -11,8 +11,36 @@
const EXPIRED_KEY = 'expired_key';
const STORE_KEY = 'tribe_pue_key_notices';
+ /**
+ * List of registered plugin names for use in notifications.
+ *
+ * Holds an array of plugin names that are registered during
+ * a request. Only registered plugins will appear in notifications.
+ *
+ * @var string[]
+ */
protected $registered = [];
+
+ /**
+ * Notices previously saved in the database.
+ *
+ * Holds the saved notices retrieved from the database,
+ * typically via the `get_option` function. It serves as a reference for
+ * comparing or merging with current notices.
+ *
+ * @var array<string, array<string, bool>>
+ */
protected $saved_notices = [];
+
+ /**
+ * Notices to be displayed or processed during the current request.
+ *
+ * Contains the current set of notices, which may include
+ * notices added during the current request. It is merged with
+ * `$saved_notices` to ensure consistency.
+ *
+ * @var array<string, array<string, bool>>
+ */
protected $notices = [];
protected $plugin_names = [
@@ -85,32 +113,88 @@
}
/**
- * Restores plugins added on previous requests to the relevant notification
- * groups.
+ * Restores and sanitizes plugin notices to ensure data integrity and prevent memory issues.
+ *
+ * Retrieves saved notices from the database, validates and sanitizes them,
+ * and sets them as the current request's notices.
+ *
+ * @since 6.4.2 Switched from `array_merge_recursive` to `wp_parse_args` to fix data duplication issues. Added additional sanitation and memory safeguards to handle large data sets effectively.
+ *
+ * @return void
*/
protected function populate() {
- $this->saved_notices = (array) get_option( self::STORE_KEY, [] );
-
- if ( empty( $this->saved_notices ) ) {
- return;
- }
+ $this->saved_notices = $this->sanitize_notices( (array) get_option( self::STORE_KEY, [] ) );
- $this->notices = array_merge_recursive( $this->notices, $this->saved_notices );
+ // Init the notices as the saved notices.
+ $this->notices = $this->saved_notices;
+ }
- // Cleanup
- foreach ( $this->notices as $key => &$plugin_lists ) {
- // Purge any elements that are not arrays
- if ( ! is_array( $plugin_lists ) ) {
- unset( $this->notices[ $key ] );
+ /**
+ * Recursively sanitizes notices to prevent nesting and ensure data integrity.
+ *
+ * @param array $notices The array of notices to sanitize.
+ *
+ * @since 6.4.2
+ *
+ * @return array Sanitized notices.
+ */
+ protected function sanitize_notices( array $notices ): array {
+ foreach ( $notices as $key => &$plugin_list ) {
+ // Ensure the value is an array; otherwise, reset it.
+ if ( ! is_array( $plugin_list ) ) {
+ $plugin_list = [];
continue;
}
+
+ foreach ( $plugin_list as $plugin => $data ) {
+ // Flatten deeply nested arrays and set the value to `true`.
+ $plugin_list[ $plugin ] = true;
+ }
}
+
+ // Remove numeric keys to ensure the notices array only contains valid string keys.
+ $notices = array_filter( $notices, fn( $key ) => ! is_numeric( $key ), ARRAY_FILTER_USE_KEY );
+
+ return $this->setup_notice_structure( $notices );
+ }
+
+ /**
+ * Ensures the required notice keys exist in the notices array and initializes them as arrays.
+ *
+ * This method guarantees that the notice structure includes specific predefined keys
+ * (e.g., `invalid_key`, `upgrade_key`, `expired_key`). If a required key is missing,
+ * it will be added with an empty array as its value. If a key exists but is not an array,
+ * it will be converted to an array.
+ *
+ * @since 6.4.2
+ *
+ * @param array $notices The array of notices to check and modify.
+ * Keys are expected to be predefined constants.
+ *
+ * @return array The updated notices array with required keys initialized.
+ */
+ protected function setup_notice_structure( array $notices ): array {
+ $required_keys = [
+ self::INVALID_KEY,
+ self::UPGRADE_KEY,
+ self::EXPIRED_KEY,
+ ];
+
+ foreach ( $required_keys as $key ) {
+ $notices[ $key ] = isset( $notices[ $key ] ) ? (array) $notices[ $key ] : [];
+ }
+
+ return $notices;
}
/**
* Saves any license key notices already added.
+ *
+ * @since 6.4.2 Sanitize notices prior to storing them.
*/
public function save_notices() {
+ $this->notices = $this->sanitize_notices( (array) $this->notices );
+
update_option( self::STORE_KEY, $this->notices );
/**
--- a/the-events-calendar/common/src/Tribe/PUE/Utility.php
+++ b/the-events-calendar/common/src/Tribe/PUE/Utility.php
@@ -41,6 +41,42 @@
* @var bool
*/
public $api_upgrade;
+ /**
+ * @var bool
+ */
+ public $api_invalid;
+ /**
+ * @var string
+ */
+ public $api_invalid_message;
+ /**
+ * @var string
+ */
+ public $api_inline_invalid_message;
+
+ /**
+ * A list of fields that will be copied from the Plugin Info object to this.
+ *
+ * @since 6.4.2
+ *
+ * @var string[]
+ */
+ private static array $copy_fields = [
+ 'id',
+ 'slug',
+ 'version',
+ 'homepage',
+ 'download_url',
+ 'upgrade_notice',
+ 'sections',
+ 'plugin',
+ 'api_expired',
+ 'api_upgrade',
+ 'api_invalid',
+ 'api_invalid_message',
+ 'api_inline_invalid_message',
+ 'custom_update',
+ ];
/**
* Create a new instance of Tribe__PUE__Utility from its JSON-encoded representation.
@@ -65,30 +101,16 @@
* Create a new instance of Tribe__PUE__Utility based on an instance of Tribe__PUE__Plugin_Info.
* Basically, this just copies a subset of fields from one object to another.
*
+ * @since 6.4.2 Refactored to extract the copy fields to a static property.
+ *
* @param Tribe__PUE__Plugin_Info $info
*
* @return Tribe__PUE__Utility
*/
public static function from_plugin_info( $info ) {
$update = new Tribe__PUE__Utility();
- $copyFields = [
- 'id',
- 'slug',
- 'version',
- 'homepage',
- 'download_url',
- 'upgrade_notice',
- 'sections',
- 'plugin',
- 'api_expired',
- 'api_upgrade',
- 'api_invalid',
- 'api_invalid_message',
- 'api_inline_invalid_message',
- 'custom_update',
- ];
- foreach ( $copyFields as $field ) {
+ foreach ( self::$copy_fields as $field ) {
if ( ! isset( $info->$field ) ) {
continue;
}
--- a/the-events-calendar/common/src/admin-views/help-hub/support/iframe-content.php
+++ b/the-events-calendar/common/src/admin-views/help-hub/support/iframe-content.php
@@ -19,10 +19,20 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php esc_html_e( 'Iframe Content', 'tribe-common' ); ?></title>
<?php
- wp_head();
+ /**
+ * Fires in the <head> section of the Help Hub iframe template.
+ *
+ * This action allows developers to hook into the iframe's header and add additional styles, scripts,
+ * or metadata specific to the Help Hub iframe content.
+ *
+ * @since 6.4.2
+ */
+ do_action( 'tec_help_hub_iframe_header' );
+ wp_print_styles();
+ wp_print_scripts();
?>
</head>
-<body <?php body_class(); ?> data-opted-in="<?php echo esc_attr( $opted_in ); ?>">
+<body id="help-hub-page" data-opted-in="<?php echo esc_attr( $opted_in ); ?>">
<!-- Docsbot section-->
<div class="docsbot-widget-background"></div>
@@ -55,10 +65,6 @@
<a target="_parent" href="<?php echo esc_url( $help_hub::get_telemetry_opt_in_link() ); ?>" class="button button-secondary"><?php esc_html_e( 'Manage my data sharing consent', 'tribe-common' ); ?></a>
</div>
</div>
-
-
-<?php
-wp_footer();
-?>
+<?php wp_print_footer_scripts(); ?>
</body>
</html>
--- a/the-events-calendar/common/vendor/autoload.php
+++ b/the-events-calendar/common/vendor/autoload.php
@@ -22,4 +22,4 @@
require_once __DIR__ . '/composer/autoload_real.php';
-return ComposerAutoloaderInit3a8885ed84fad9342daf3f204a3c48aa::getLoader();
+return ComposerAutoloaderInita552a38d268739c81a09042f37ae6405::getLoader();
--- a/the-events-calendar/common/vendor/composer/InstalledVersions.php
+++ b/the-events-calendar/common/vendor/composer/InstalledVersions.php
@@ -322,6 +322,7 @@
}
$installed = array();
+ $copiedLocalDir = false;
if (self::$canGetVendors) {
foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) {
@@ -330,9 +331,11 @@
} 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 (strtr($vendorDir.'/composer', '\', '/') === strtr(__DIR__, '\', '/')) {
+ self::$installed = $required;
+ $copiedLocalDir = true;
}
}
}
@@ -350,7 +353,7 @@
}
}
- if (self::$installed !== array()) {
+ if (self::$installed !== array() && !$copiedLocalDir) {
$installed[] = self::$installed;
}
--- a/the-events-calendar/common/vendor/composer/autoload_real.php
+++ b/the-events-calendar/common/vendor/composer/autoload_real.php
@@ -2,7 +2,7 @@
// autoload_real.php @generated by Composer
-class ComposerAutoloaderInit3a8885ed84fad9342daf3f204a3c48aa
+class ComposerAutoloaderInita552a38d268739c81a09042f37ae6405
{
private static $loader;
@@ -24,12 +24,12 @@
require __DIR__ . '/platform_check.php';
- spl_autoload_register(array('ComposerAutoloaderInit3a8885ed84fad9342daf3f204a3c48aa', 'loadClassLoader'), true, true);
+ spl_autoload_register(array('ComposerAutoloaderInita552a38d268739c81a09042f37ae6405', 'loadClassLoader'), true, true);
self::$loader = $loader = new ComposerAutoloadClassLoader(dirname(__DIR__));
- spl_autoload_unregister(array('ComposerAutoloaderInit3a8885ed84fad9342daf3f204a3c48aa', 'loadClassLoader'));
+ spl_autoload_unregister(array('ComposerAutoloaderInita552a38d268739c81a09042f37ae6405', 'loadClassLoader'));
require __DIR__ . '/autoload_static.php';
- call_user_func(ComposerAutoloadComposerStaticInit3a8885ed84fad9342daf3f204a3c48aa::getInitializer($loader));
+ call_user_func(ComposerAutoloadComposerStaticInita552a38d268739c81a09042f37ae6405::getInitializer($loader));
$loader->register(true);
--- a/the-events-calendar/common/vendor/composer/autoload_static.php
+++ b/the-events-calendar/common/vendor/composer/autoload_static.php
@@ -4,7 +4,7 @@
namespace ComposerAutoload;
-class ComposerStaticInit3a8885ed84fad9342daf3f204a3c48aa
+class ComposerStaticInita552a38d268739c81a09042f37ae6405
{
public static $prefixLengthsPsr4 = array (
'T' =>
@@ -37,9 +37,9 @@
public static function getInitializer(ClassLoader $loader)
{
return Closure::bind(function () use ($loader) {
- $loader->prefixLengthsPsr4 = ComposerStaticInit3a8885ed84fad9342daf3f204a3c48aa::$prefixLengthsPsr4;
- $loader->prefixDirsPsr4 = ComposerStaticInit3a8885ed84fad9342daf3f204a3c48aa::$prefixDirsPsr4;
- $loader->classMap = ComposerStaticInit3a8885ed84fad9342daf3f204a3c48aa::$classMap;
+ $loader->prefixLengthsPsr4 = ComposerStaticInita552a38d268739c81a09042f37ae6405::$prefixLengthsPsr4;
+ $loader->prefixDirsPsr4 = ComposerStaticInita552a38d268739c81a09042f37ae6405::$prefixDirsPsr4;
+ $loader->classMap = ComposerStaticInita552a38d268739c81a09042f37ae6405::$classMap;
}, null, ClassLoader::class);
}
--- a/the-events-calendar/common/vendor/composer/installed.php
+++ b/the-events-calendar/common/vendor/composer/installed.php
@@ -3,7 +3,7 @@
'name' => 'the-events-calendar/tribe-common',
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'd60b606481d179dd17d205505df33d10fb2bec47',
+ 'reference' => 'ca5bb4cd747086542cc566626e07c34f5bb582e8',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
@@ -156,11 +156,20 @@
'the-events-calendar/tribe-common' => array(
'pretty_version' => 'dev-master',
'version' => 'dev-master',
- 'reference' => 'd60b606481d179dd17d205505df33d10fb2bec47',
+ 'reference' => 'ca5bb4cd747086542cc566626e07c34f5bb582e8',
'type' => 'wordpress-plugin',
'install_path' => __DIR__ . '/../../',
'aliases' => array(),
'dev_requirement' => false,
),
+ 'woocommerce/action-scheduler' => array(
+ 'pretty_version' => '3.8.1',
+ 'version' => '3.8.1.0',
+ 'reference' => 'e331b534d7de10402d7545a0de50177b874c0779',
+ 'type' => 'wordpress-plugin',
+ 'install_path' => __DIR__ . '/../woocommerce/action-scheduler',
+ 'aliases' => array(),
+ 'dev_requirement' => false,
+ ),
),
);
--- a/the-events-calendar/common/vendor/woocommerce/action-scheduler/action-scheduler.php
+++ b/the-events-calendar/common/vendor/woocommerce/action-scheduler/action-scheduler.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Plugin Name: Action Scheduler
+ * Plugin URI: https://actionscheduler.org
+ * Description: A robust scheduling library for use in WordPress plugins.
+ * Author: Automattic
+ * Author URI: https://automattic.com/
+ * Version: 3.8.1
+ * License: GPLv3
+ * Requires at least: 6.2
+ * Tested up to: 6.5
+ * Requires PHP: 5.6
+ *
+ * Copyright 2019 Automattic, Inc. (https://automattic.com/contact/)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * @package ActionScheduler
+ */
+
+if ( ! function_exists( 'action_scheduler_register_3_dot_8_dot_1' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION.
+
+ if ( ! class_exists( 'ActionScheduler_Versions', false ) ) {
+ require_once __DIR__ . '/classes/ActionScheduler_Versions.php';
+ add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
+ }
+
+ add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_8_dot_1', 0, 0 ); // WRCS: DEFINED_VERSION.
+
+ // phpcs:disable Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace
+ /**
+ * Registers this version of Action Scheduler.
+ */
+ function action_scheduler_register_3_dot_8_dot_1() { // WRCS: DEFINED_VERSION.
+ $versions = ActionScheduler_Versions::instance();
+ $versions->register( '3.8.1', 'action_scheduler_initialize_3_dot_8_dot_1' ); // WRCS: DEFINED_VERSION.
+ }
+
+ // phpcs:disable Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace
+ /**
+ * Initializes this version of Action Scheduler.
+ */
+ function action_scheduler_initialize_3_dot_8_dot_1() { // WRCS: DEFINED_VERSION.
+ // A final safety check is required even here, because historic versions of Action Scheduler
+ // followed a different pattern (in some unusual cases, we could reach this point and the
+ // ActionScheduler class is already defined—so we need to guard against that).
+ if ( ! class_exists( 'ActionScheduler', false ) ) {
+ require_once __DIR__ . '/classes/abstracts/ActionScheduler.php';
+ ActionScheduler::init( __FILE__ );
+ }
+ }
+
+ // Support usage in themes - load this version if no plugin has loaded a version yet.
+ if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) {
+ action_scheduler_initialize_3_dot_8_dot_1(); // WRCS: DEFINED_VERSION.
+ do_action( 'action_scheduler_pre_theme_init' );
+ ActionScheduler_Versions::initialize_latest_version();
+ }
+}
--- a/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_ActionClaim.php
+++ b/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_ActionClaim.php
@@ -0,0 +1,23 @@
+<?php
+
+/**
+ * Class ActionScheduler_ActionClaim
+ */
+class ActionScheduler_ActionClaim {
+ private $id = '';
+ private $action_ids = array();
+
+ public function __construct( $id, array $action_ids ) {
+ $this->id = $id;
+ $this->action_ids = $action_ids;
+ }
+
+ public function get_id() {
+ return $this->id;
+ }
+
+ public function get_actions() {
+ return $this->action_ids;
+ }
+}
+
No newline at end of file
--- a/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_ActionFactory.php
+++ b/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_ActionFactory.php
@@ -0,0 +1,376 @@
+<?php
+
+/**
+ * Class ActionScheduler_ActionFactory
+ */
+class ActionScheduler_ActionFactory {
+
+ /**
+ * Return stored actions for given params.
+ *
+ * @param string $status The action's status in the data store.
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass to callbacks when the hook is triggered.
+ * @param ActionScheduler_Schedule $schedule The action's schedule.
+ * @param string $group A group to put the action in.
+ * phpcs:ignore Squiz.Commenting.FunctionComment.ExtraParamComment
+ * @param int $priority The action priority.
+ *
+ * @return ActionScheduler_Action An instance of the stored action.
+ */
+ public function get_stored_action( $status, $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
+ // The 6th parameter ($priority) is not formally declared in the method signature to maintain compatibility with
+ // third-party subclasses created before this param was added.
+ $priority = func_num_args() >= 6 ? (int) func_get_arg( 5 ) : 10;
+
+ switch ( $status ) {
+ case ActionScheduler_Store::STATUS_PENDING:
+ $action_class = 'ActionScheduler_Action';
+ break;
+ case ActionScheduler_Store::STATUS_CANCELED:
+ $action_class = 'ActionScheduler_CanceledAction';
+ if ( ! is_null( $schedule ) && ! is_a( $schedule, 'ActionScheduler_CanceledSchedule' ) && ! is_a( $schedule, 'ActionScheduler_NullSchedule' ) ) {
+ $schedule = new ActionScheduler_CanceledSchedule( $schedule->get_date() );
+ }
+ break;
+ default:
+ $action_class = 'ActionScheduler_FinishedAction';
+ break;
+ }
+
+ $action_class = apply_filters( 'action_scheduler_stored_action_class', $action_class, $status, $hook, $args, $schedule, $group );
+
+ $action = new $action_class( $hook, $args, $schedule, $group );
+ $action->set_priority( $priority );
+
+ /**
+ * Allow 3rd party code to change the instantiated action for a given hook, args, schedule and group.
+ *
+ * @param ActionScheduler_Action $action The instantiated action.
+ * @param string $hook The instantiated action's hook.
+ * @param array $args The instantiated action's args.
+ * @param ActionScheduler_Schedule $schedule The instantiated action's schedule.
+ * @param string $group The instantiated action's group.
+ * @param int $priority The action priority.
+ */
+ return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group, $priority );
+ }
+
+ /**
+ * Enqueue an action to run one time, as soon as possible (rather a specific scheduled time).
+ *
+ * This method creates a new action using the NullSchedule. In practice, this results in an action scheduled to
+ * execute "now". Therefore, it will generally run as soon as possible but is not prioritized ahead of other actions
+ * that are already past-due.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param string $group A group to put the action in.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function async( $hook, $args = array(), $group = '' ) {
+ return $this->async_unique( $hook, $args, $group, false );
+ }
+
+ /**
+ * Same as async, but also supports $unique param.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param string $group A group to put the action in.
+ * @param bool $unique Whether to ensure the action is unique.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function async_unique( $hook, $args = array(), $group = '', $unique = true ) {
+ $schedule = new ActionScheduler_NullSchedule();
+ $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
+ return $unique ? $this->store_unique_action( $action, $unique ) : $this->store( $action );
+ }
+
+ /**
+ * Create single action.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $when Unix timestamp when the action will run.
+ * @param string $group A group to put the action in.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function single( $hook, $args = array(), $when = null, $group = '' ) {
+ return $this->single_unique( $hook, $args, $when, $group, false );
+ }
+
+ /**
+ * Create single action only if there is no pending or running action with same name and params.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $when Unix timestamp when the action will run.
+ * @param string $group A group to put the action in.
+ * @param bool $unique Whether action scheduled should be unique.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function single_unique( $hook, $args = array(), $when = null, $group = '', $unique = true ) {
+ $date = as_get_datetime_object( $when );
+ $schedule = new ActionScheduler_SimpleSchedule( $date );
+ $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
+ return $unique ? $this->store_unique_action( $action ) : $this->store( $action );
+ }
+
+ /**
+ * Create the first instance of an action recurring on a given interval.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $first Unix timestamp for the first run.
+ * @param int $interval Seconds between runs.
+ * @param string $group A group to put the action in.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) {
+ return $this->recurring_unique( $hook, $args, $first, $interval, $group, false );
+ }
+
+ /**
+ * Create the first instance of an action recurring on a given interval only if there is no pending or running action with same name and params.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $first Unix timestamp for the first run.
+ * @param int $interval Seconds between runs.
+ * @param string $group A group to put the action in.
+ * @param bool $unique Whether action scheduled should be unique.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function recurring_unique( $hook, $args = array(), $first = null, $interval = null, $group = '', $unique = true ) {
+ if ( empty( $interval ) ) {
+ return $this->single_unique( $hook, $args, $first, $group, $unique );
+ }
+ $date = as_get_datetime_object( $first );
+ $schedule = new ActionScheduler_IntervalSchedule( $date, $interval );
+ $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
+ return $unique ? $this->store_unique_action( $action ) : $this->store( $action );
+ }
+
+ /**
+ * Create the first instance of an action recurring on a Cron schedule.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $base_timestamp The first instance of the action will be scheduled
+ * to run at a time calculated after this timestamp matching the cron
+ * expression. This can be used to delay the first instance of the action.
+ * @param int $schedule A cron definition string.
+ * @param string $group A group to put the action in.
+ *
+ * @return int The ID of the stored action.
+ */
+ public function cron( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '' ) {
+ return $this->cron_unique( $hook, $args, $base_timestamp, $schedule, $group, false );
+ }
+
+
+ /**
+ * Create the first instance of an action recurring on a Cron schedule only if there is no pending or running action with same name and params.
+ *
+ * @param string $hook The hook to trigger when this action runs.
+ * @param array $args Args to pass when the hook is triggered.
+ * @param int $base_timestamp The first instance of the action will be scheduled
+ * to run at a time calculated after this timestamp matching the cron
+ * expression. This can be used to delay the first instance of the action.
+ * @param int $schedule A cron definition string.
+ * @param string $group A group to put the action in.
+ * @param bool $unique Whether action scheduled should be unique.
+ *
+ * @return int The ID of the stored action.
+ **/
+ public function cron_unique( $hook, $args = array(), $base_timestamp = null, $schedule = null, $group = '', $unique = true ) {
+ if ( empty( $schedule ) ) {
+ return $this->single_unique( $hook, $args, $base_timestamp, $group, $unique );
+ }
+ $date = as_get_datetime_object( $base_timestamp );
+ $cron = CronExpression::factory( $schedule );
+ $schedule = new ActionScheduler_CronSchedule( $date, $cron );
+ $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
+ return $unique ? $this->store_unique_action( $action ) : $this->store( $action );
+ }
+
+ /**
+ * Create a successive instance of a recurring or cron action.
+ *
+ * Importantly, the action will be rescheduled to run based on the current date/time.
+ * That means when the action is scheduled to run in the past, the next scheduled date
+ * will be pushed forward. For example, if a recurring action set to run every hour
+ * was scheduled to run 5 seconds ago, it will be next scheduled for 1 hour in the
+ * future, which is 1 hour and 5 seconds from when it was last scheduled to run.
+ *
+ * Alternatively, if the action is scheduled to run in the future, and is run early,
+ * likely via manual intervention, then its schedule will change based on the time now.
+ * For example, if a recurring action set to run every day, and is run 12 hours early,
+ * it will run again in 24 hours, not 36 hours.
+ *
+ * This slippage is less of an issue with Cron actions, as the specific run time can
+ * be set for them to run, e.g. 1am each day. In those cases, and entire period would
+ * need to be missed before there was any change is scheduled, e.g. in the case of an
+ * action scheduled for 1am each day, the action would need to run an entire day late.
+ *
+ * @param ActionScheduler_Action $action The existing action.
+ *
+ * @return string The ID of the stored action
+ * @throws InvalidArgumentException If $action is not a recurring action.
+ */
+ public function repeat( $action ) {
+ $schedule = $action->get_schedule();
+ $next = $schedule->get_next( as_get_datetime_object() );
+
+ if ( is_null( $next ) || ! $schedule->is_recurring() ) {
+ throw new InvalidArgumentException( __( 'Invalid action - must be a recurring action.', 'action-scheduler' ) );
+ }
+
+ $schedule_class = get_class( $schedule );
+ $new_schedule = new $schedule( $next, $schedule->get_recurrence(), $schedule->get_first_date() );
+ $new_action = new ActionScheduler_Action( $action->get_hook(), $action->get_args(), $new_schedule, $action->get_group() );
+ $new_action->set_priority( $action->get_priority() );
+ return $this->store( $new_action );
+ }
+
+ /**
+ * Creates a scheduled action.
+ *
+ * This general purpose method can be used in place of specific methods such as async(),
+ * async_unique(), single() or single_unique(), etc.
+ *
+ * @internal Not intended for public use, should not be overridden by subclasses.
+ *
+ * @param array $options {
+ * Describes the action we wish to schedule.
+ *
+ * @type string $type Must be one of 'async', 'cron', 'recurring', or 'single'.
+ * @type string $hook The hook to be executed.
+ * @type array $arguments Arguments to be passed to the callback.
+ * @type string $group The action group.
+ * @type bool $unique If the action should be unique.
+ * @type int $when Timestamp. Indicates when the action, or first instance of the action in the case
+ * of recurring or cron actions, becomes due.
+ * @type int|string $pattern Recurrence pattern. This is either an interval in seconds for recurring actions
+ * or a cron expression for cron actions.
+ * @type int $priority Lower values means higher priority. Should be in the range 0-255.
+ * }
+ *
+ * @return int The action ID. Zero if there was an error scheduling the action.
+ */
+ public function create( array $options = array() ) {
+ $defaults = array(
+ 'type' => 'single',
+ 'hook' => '',
+ 'arguments' => array(),
+ 'group' => '',
+ 'unique' => false,
+ 'when' => time(),
+ 'pattern' => null,
+ 'priority' => 10,
+ );
+
+ $options = array_merge( $defaults, $options );
+
+ // Cron/recurring actions without a pattern are treated as single actions (this gives calling code the ability
+ // to use functions like as_schedule_recurring_action() to schedule recurring as well as single actions).
+ if ( ( 'cron' === $options['type'] || 'recurring' === $options['type'] ) && empty( $options['pattern'] ) ) {
+ $options['type'] = 'single';
+ }
+
+ switch ( $options['type'] ) {
+ case 'async':
+ $schedule = new ActionScheduler_NullSchedule();
+ break;
+
+ case 'cron':
+ $date = as_get_datetime_object( $options['when'] );
+ $cron = CronExpression::factory( $options['pattern'] );
+ $schedule = new ActionScheduler_CronSchedule( $date, $cron );
+ break;
+
+ case 'recurring':
+ $date = as_get_datetime_object( $options['when'] );
+ $schedule = new ActionScheduler_IntervalSchedule( $date, $options['pattern'] );
+ break;
+
+ case 'single':
+ $date = as_get_datetime_object( $options['when'] );
+ $schedule = new ActionScheduler_SimpleSchedule( $date );
+ break;
+
+ default:
+ error_log( "Unknown action type '{$options['type']}' specified when trying to create an action for '{$options['hook']}'." );
+ return 0;
+ }
+
+ $action = new ActionScheduler_Action( $options['hook'], $options['arguments'], $schedule, $options['group'] );
+ $action->set_priority( $options['priority'] );
+
+ $action_id = 0;
+ try {
+ $action_id = $options['unique'] ? $this->store_unique_action( $action ) : $this->store( $action );
+ } catch ( Exception $e ) {
+ error_log(
+ sprintf(
+ /* translators: %1$s is the name of the hook to be enqueued, %2$s is the exception message. */
+ __( 'Caught exception while enqueuing action "%1$s": %2$s', 'action-scheduler' ),
+ $options['hook'],
+ $e->getMessage()
+ )
+ );
+ }
+ return $action_id;
+ }
+
+ /**
+ * Save action to database.
+ *
+ * @param ActionScheduler_Action $action Action object to save.
+ *
+ * @return int The ID of the stored action
+ */
+ protected function store( ActionScheduler_Action $action ) {
+ $store = ActionScheduler_Store::instance();
+ return $store->save_action( $action );
+ }
+
+ /**
+ * Store action if it's unique.
+ *
+ * @param ActionScheduler_Action $action Action object to store.
+ *
+ * @return int ID of the created action. Will be 0 if action was not created.
+ */
+ protected function store_unique_action( ActionScheduler_Action $action ) {
+ $store = ActionScheduler_Store::instance();
+ if ( method_exists( $store, 'save_unique_action' ) ) {
+ return $store->save_unique_action( $action );
+ } else {
+ /**
+ * Fallback to non-unique action if the store doesn't support unique actions.
+ * We try to save the action as unique, accepting that there might be a race condition.
+ * This is likely still better than giving up on unique actions entirely.
+ */
+ $existing_action_id = (int) $store->find_action(
+ $action->get_hook(),
+ array(
+ 'args' => $action->get_args(),
+ 'status' => ActionScheduler_Store::STATUS_PENDING,
+ 'group' => $action->get_group(),
+ )
+ );
+ if ( $existing_action_id > 0 ) {
+ return 0;
+ }
+ return $store->save_action( $action );
+ }
+ }
+}
--- a/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_AdminView.php
+++ b/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_AdminView.php
@@ -0,0 +1,253 @@
+<?php
+
+/**
+ * Class ActionScheduler_AdminView
+ * @codeCoverageIgnore
+ */
+class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
+
+ private static $admin_view = NULL;
+
+ private static $screen_id = 'tools_page_action-scheduler';
+
+ /** @var ActionScheduler_ListTable */
+ protected $list_table;
+
+ /**
+ * @return ActionScheduler_AdminView
+ * @codeCoverageIgnore
+ */
+ public static function instance() {
+
+ if ( empty( self::$admin_view ) ) {
+ $class = apply_filters('action_scheduler_admin_view_class', 'ActionScheduler_AdminView');
+ self::$admin_view = new $class();
+ }
+
+ return self::$admin_view;
+ }
+
+ /**
+ * @codeCoverageIgnore
+ */
+ public function init() {
+ if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) {
+
+ if ( class_exists( 'WooCommerce' ) ) {
+ add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) );
+ add_action( 'woocommerce_system_status_report', array( $this, 'system_status_report' ) );
+ add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) );
+ }
+
+ add_action( 'admin_menu', array( $this, 'register_menu' ) );
+ add_action( 'admin_notices', array( $this, 'maybe_check_pastdue_actions' ) );
+ add_action( 'current_screen', array( $this, 'add_help_tabs' ) );
+ }
+ }
+
+ public function system_status_report() {
+ $table = new ActionScheduler_wcSystemStatus( ActionScheduler::store() );
+ $table->render();
+ }
+
+ /**
+ * Registers action-scheduler into WooCommerce > System status.
+ *
+ * @param array $tabs An associative array of tab key => label.
+ * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs
+ */
+ public function register_system_status_tab( array $tabs ) {
+ $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' );
+
+ return $tabs;
+ }
+
+ /**
+ * Include Action Scheduler's administration under the Tools menu.
+ *
+ * A menu under the Tools menu is important for backward compatibility (as that's
+ * where it started), and also provides more convenient access than the WooCommerce
+ * System Status page, and for sites where WooCommerce isn't active.
+ */
+ public function register_menu() {
+ $hook_suffix = add_submenu_page(
+ 'tools.php',
+ __( 'Scheduled Actions', 'action-scheduler' ),
+ __( 'Scheduled Actions', 'action-scheduler' ),
+ 'manage_options',
+ 'action-scheduler',
+ array( $this, 'render_admin_ui' )
+ );
+ add_action( 'load-' . $hook_suffix , array( $this, 'process_admin_ui' ) );
+ }
+
+ /**
+ * Triggers processing of any pending actions.
+ */
+ public function process_admin_ui() {
+ $this->get_list_table();
+ }
+
+ /**
+ * Renders the Admin UI
+ */
+ public function render_admin_ui() {
+ $table = $this->get_list_table();
+ $table->display_page();
+ }
+
+ /**
+ * Get the admin UI object and process any requested actions.
+ *
+ * @return ActionScheduler_ListTable
+ */
+ protected function get_list_table() {
+ if ( null === $this->list_table ) {
+ $this->list_table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
+ $this->list_table->process_actions();
+ }
+
+ return $this->list_table;
+ }
+
+ /**
+ * Action: admin_notices
+ *
+ * Maybe check past-due actions, and print notice.
+ *
+ * @uses $this->check_pastdue_actions()
+ */
+ public function maybe_check_pastdue_actions() {
+
+ # Filter to prevent checking actions (ex: inappropriate user).
+ if ( ! apply_filters( 'action_scheduler_check_pastdue_actions', current_user_can( 'manage_options' ) ) ) {
+ return;
+ }
+
+ # Get last check transient.
+ $last_check = get_transient( 'action_scheduler_last_pastdue_actions_check' );
+
+ # If transient exists, we're within interval, so bail.
+ if ( ! empty( $last_check ) ) {
+ return;
+ }
+
+ # Perform the check.
+ $this->check_pastdue_actions();
+ }
+
+ /**
+ * Check past-due actions, and print notice.
+ *
+ * @todo update $link_url to "Past-due" filter when released (see issue #510, PR #511)
+ */
+ protected function check_pastdue_actions() {
+
+ # Set thresholds.
+ $threshold_seconds = ( int ) apply_filters( 'action_scheduler_pastdue_actions_seconds', DAY_IN_SECONDS );
+ $threshold_min = ( int ) apply_filters( 'action_scheduler_pastdue_actions_min', 1 );
+
+ // Set fallback value for past-due actions count.
+ $num_pastdue_actions = 0;
+
+ // Allow third-parties to preempt the default check logic.
+ $check = apply_filters( 'action_scheduler_pastdue_actions_check_pre', null );
+
+ // If no third-party preempted and there are no past-due actions, return early.
+ if ( ! is_null( $check ) ) {
+ return;
+ }
+
+ # Scheduled actions query arguments.
+ $query_args = array(
+ 'date' => as_get_datetime_object( time() - $threshold_seconds ),
+ 'status' => ActionScheduler_Store::STATUS_PENDING,
+ 'per_page' => $threshold_min,
+ );
+
+ # If no third-party preempted, run default check.
+ if ( is_null( $check ) ) {
+ $store = ActionScheduler_Store::instance();
+ $num_pastdue_actions = ( int ) $store->query_actions( $query_args, 'count' );
+
+ # Check if past-due actions count is greater than or equal to threshold.
+ $check = ( $num_pastdue_actions >= $threshold_min );
+ $check = ( bool ) apply_filters( 'action_scheduler_pastdue_actions_check', $check, $num_pastdue_actions, $threshold_seconds, $threshold_min );
+ }
+
+ # If check failed, set transient and abort.
+ if ( ! boolval( $check ) ) {
+ $interval = apply_filters( 'action_scheduler_pastdue_actions_check_interval', round( $threshold_seconds / 4 ), $threshold_seconds );
+ set_transient( 'action_scheduler_last_pastdue_actions_check', time(), $interval );
+
+ return;
+ }
+
+ $actions_url = add_query_arg( array(
+ 'page' => 'action-scheduler',
+ 'status' => 'past-due',
+ 'order' => 'asc',
+ ), admin_url( 'tools.php' ) );
+
+ # Print notice.
+ echo '<div class="notice notice-warning"><p>';
+ printf(
+ // translators: 1) is the number of affected actions, 2) is a link to an admin screen.
+ _n(
+ '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due action</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>',
+ '<strong>Action Scheduler:</strong> %1$d <a href="%2$s">past-due actions</a> found; something may be wrong. <a href="https://actionscheduler.org/faq/#my-site-has-past-due-actions-what-can-i-do" target="_blank">Read documentation »</a>',
+ $num_pastdue_actions,
+ 'action-scheduler'
+ ),
+ $num_pastdue_actions,
+ esc_attr( esc_url( $actions_url ) )
+ );
+ echo '</p></div>';
+
+ # Facilitate third-parties to evaluate and print notices.
+ do_action( 'action_scheduler_pastdue_actions_extra_notices', $query_args );
+ }
+
+ /**
+ * Provide more information about the screen and its data in the help tab.
+ */
+ public function add_help_tabs() {
+ $screen = get_current_screen();
+
+ if ( ! $screen || self::$screen_id != $screen->id ) {
+ return;
+ }
+
+ $as_version = ActionScheduler_Versions::instance()->latest_version();
+ $screen->add_help_tab(
+ array(
+ 'id' => 'action_scheduler_about',
+ 'title' => __( 'About', 'action-scheduler' ),
+ 'content' =>
+ // translators: %s is the Action Scheduler version.
+ '<h2>' . sprintf( __( 'About Action Scheduler %s', 'action-scheduler' ), $as_version ) . '</h2>' .
+ '<p>' .
+ __( 'Action Scheduler is a scalable, traceable job queue for background processing large sets of actions. Action Scheduler works by triggering an action hook to run at some time in the future. Scheduled actions can also be scheduled to run on a recurring schedule.', 'action-scheduler' ) .
+ '</p>',
+ )
+ );
+
+ $screen->add_help_tab(
+ array(
+ 'id' => 'action_scheduler_columns',
+ 'title' => __( 'Columns', 'action-scheduler' ),
+ 'content' =>
+ '<h2>' . __( 'Scheduled Action Columns', 'action-scheduler' ) . '</h2>' .
+ '<ul>' .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Hook', 'action-scheduler' ), __( 'Name of the action hook that will be triggered.', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Status', 'action-scheduler' ), __( 'Action statuses are Pending, Complete, Canceled, Failed', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Arguments', 'action-scheduler' ), __( 'Optional data array passed to the action hook.', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Group', 'action-scheduler' ), __( 'Optional action group.', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Recurrence', 'action-scheduler' ), __( 'The action's schedule frequency.', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Scheduled', 'action-scheduler' ), __( 'The date/time the action is/was scheduled to run.', 'action-scheduler' ) ) .
+ sprintf( '<li><strong>%1$s</strong>: %2$s</li>', __( 'Log', 'action-scheduler' ), __( 'Activity log for the action.', 'action-scheduler' ) ) .
+ '</ul>',
+ )
+ );
+ }
+}
--- a/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php
+++ b/the-events-calendar/common/vendor/woocommerce/action-scheduler/classes/ActionScheduler_AsyncRequest_QueueRunner.php
@@ -0,0 +1,97 @@
+<?php
+/**
+ * ActionScheduler_AsyncRequest_QueueRunner
+ */
+
+defined( 'ABSPATH' ) || exit;
+
+/**
+ * ActionScheduler_AsyncRequest_QueueRunner class.
+ */
+class ActionScheduler_AsyncRequest_QueueRunner extends WP_Async_Request {
+
+ /**
+ * Data store for querying actions
+ *
+ * @var ActionScheduler_Store
+ * @access protected
+ */
+ protected $store;
+
+ /**
+ * Prefix for ajax hooks
+ *
+ * @var string
+ * @access protected
+ */
+ protected $prefix = 'as';
+
+ /**
+ * Action for ajax hooks
+ *
+ * @var string
+ * @access protected
+ */
+ protected $action = 'async_request_queue_runner';
+
+ /**
+ * Initiate new async request
+ */
+ public function __construct( ActionScheduler_Store $store ) {
+ parent::__construct();
+ $this->store = $store;
+ }
+
+ /**
+ * Handle async requests
+ *
+ * Run a queue, and maybe dispatch another async request to run another queue
+ * if there are still pending actions after completing a queue in this request.
+ */
+ protected function handle() {
+ do_action( 'action_scheduler_run_queue', 'Async Request' ); // run a queue in the same way as WP Cron, but declare the Async Request context
+
+ $sleep_seconds = $this->get_sleep_seconds();
+
+ if ( $sleep_seconds ) {
+ sleep( $sleep_seconds );
+ }
+
+ $this->maybe_dispatch();
+ }
+
+ /**
+ * If the async request runner is needed and allowed to run, dispatch a request.
+ */
+ public function maybe_dispatch() {
+ if ( ! $this->allow() ) {
+ return;
+ }
+
+ $this->dispatch();
+ ActionScheduler_QueueRunner::instance()->unhook_dispatch_async_request();
+ }
+
+ /**
+ * Only allow async requests when needed.
+ *
+ * Also allow 3rd party code to disable running actions via async requests.
+ */
+ protected function allow() {
+
+ if ( ! has_action( 'action_scheduler_run_queue' ) || ActionScheduler::runner()->has_maximum_concurrent_batches() || ! $this->store->has_pending_actions_due() ) {
+ $allow = false;
+ } else {
+ $allow = true;
+ }
+
+ return apply_filters( 'act