Changeset 3328081
- Timestamp:
- 07/15/2025 09:33:30 AM (5 months ago)
- Location:
- action-scheduler
- Files:
-
- 2 added
- 42 edited
- 1 copied
-
tags/3.9.3 (copied) (copied from action-scheduler/trunk)
-
tags/3.9.3/action-scheduler.php (modified) (6 diffs)
-
tags/3.9.3/changelog.txt (modified) (1 diff)
-
tags/3.9.3/classes/ActionScheduler_DataController.php (modified) (1 diff)
-
tags/3.9.3/classes/ActionScheduler_RecurringActionScheduler.php (added)
-
tags/3.9.3/classes/ActionScheduler_wcSystemStatus.php (modified) (1 diff)
-
tags/3.9.3/classes/WP_CLI/Action/Create_Command.php (modified) (1 diff)
-
tags/3.9.3/classes/WP_CLI/Action/Get_Command.php (modified) (1 diff)
-
tags/3.9.3/classes/WP_CLI/System_Command.php (modified) (1 diff)
-
tags/3.9.3/classes/abstracts/ActionScheduler.php (modified) (3 diffs)
-
tags/3.9.3/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php (modified) (1 diff)
-
tags/3.9.3/classes/data-stores/ActionScheduler_DBStore.php (modified) (7 diffs)
-
tags/3.9.3/classes/data-stores/ActionScheduler_HybridStore.php (modified) (1 diff)
-
tags/3.9.3/classes/data-stores/ActionScheduler_wpPostStore.php (modified) (3 diffs)
-
tags/3.9.3/classes/schema/ActionScheduler_StoreSchema.php (modified) (2 diffs)
-
tags/3.9.3/functions.php (modified) (4 diffs)
-
tags/3.9.3/readme.txt (modified) (3 diffs)
-
tags/3.9.3/vendor/autoload.php (modified) (1 diff)
-
tags/3.9.3/vendor/composer/InstalledVersions.php (modified) (3 diffs)
-
tags/3.9.3/vendor/composer/autoload_real.php (modified) (2 diffs)
-
tags/3.9.3/vendor/composer/autoload_static.php (modified) (2 diffs)
-
tags/3.9.3/vendor/composer/installed.php (modified) (2 diffs)
-
tags/3.9.3/vendor/composer/platform_check.php (modified) (1 diff)
-
trunk/action-scheduler.php (modified) (6 diffs)
-
trunk/changelog.txt (modified) (1 diff)
-
trunk/classes/ActionScheduler_DataController.php (modified) (1 diff)
-
trunk/classes/ActionScheduler_RecurringActionScheduler.php (added)
-
trunk/classes/ActionScheduler_wcSystemStatus.php (modified) (1 diff)
-
trunk/classes/WP_CLI/Action/Create_Command.php (modified) (1 diff)
-
trunk/classes/WP_CLI/Action/Get_Command.php (modified) (1 diff)
-
trunk/classes/WP_CLI/System_Command.php (modified) (1 diff)
-
trunk/classes/abstracts/ActionScheduler.php (modified) (3 diffs)
-
trunk/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php (modified) (1 diff)
-
trunk/classes/data-stores/ActionScheduler_DBStore.php (modified) (7 diffs)
-
trunk/classes/data-stores/ActionScheduler_HybridStore.php (modified) (1 diff)
-
trunk/classes/data-stores/ActionScheduler_wpPostStore.php (modified) (3 diffs)
-
trunk/classes/schema/ActionScheduler_StoreSchema.php (modified) (2 diffs)
-
trunk/functions.php (modified) (4 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/vendor/autoload.php (modified) (1 diff)
-
trunk/vendor/composer/InstalledVersions.php (modified) (3 diffs)
-
trunk/vendor/composer/autoload_real.php (modified) (2 diffs)
-
trunk/vendor/composer/autoload_static.php (modified) (2 diffs)
-
trunk/vendor/composer/installed.php (modified) (2 diffs)
-
trunk/vendor/composer/platform_check.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
action-scheduler/tags/3.9.3/action-scheduler.php
r3233744 r3328081 6 6 * Author: Automattic 7 7 * Author URI: https://automattic.com/ 8 * Version: 3.9. 28 * Version: 3.9.3 9 9 * License: GPLv3 10 10 * Requires at least: 6.5 11 * Tested up to: 6. 712 * Requires PHP: 7. 111 * Tested up to: 6.8 12 * Requires PHP: 7.2 13 13 * 14 14 * Copyright 2019 Automattic, Inc. (https://automattic.com/contact/) … … 30 30 */ 31 31 32 if ( ! function_exists( 'action_scheduler_register_3_dot_9_dot_ 2' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION.32 if ( ! function_exists( 'action_scheduler_register_3_dot_9_dot_3' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION. 33 33 34 34 if ( ! class_exists( 'ActionScheduler_Versions', false ) ) { … … 37 37 } 38 38 39 add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_9_dot_ 2', 0, 0 ); // WRCS: DEFINED_VERSION.39 add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_9_dot_3', 0, 0 ); // WRCS: DEFINED_VERSION. 40 40 41 41 // phpcs:disable Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace … … 43 43 * Registers this version of Action Scheduler. 44 44 */ 45 function action_scheduler_register_3_dot_9_dot_ 2() { // WRCS: DEFINED_VERSION.45 function action_scheduler_register_3_dot_9_dot_3() { // WRCS: DEFINED_VERSION. 46 46 $versions = ActionScheduler_Versions::instance(); 47 $versions->register( '3.9. 2', 'action_scheduler_initialize_3_dot_9_dot_2' ); // WRCS: DEFINED_VERSION.47 $versions->register( '3.9.3', 'action_scheduler_initialize_3_dot_9_dot_3' ); // WRCS: DEFINED_VERSION. 48 48 } 49 49 … … 52 52 * Initializes this version of Action Scheduler. 53 53 */ 54 function action_scheduler_initialize_3_dot_9_dot_ 2() { // WRCS: DEFINED_VERSION.54 function action_scheduler_initialize_3_dot_9_dot_3() { // WRCS: DEFINED_VERSION. 55 55 // A final safety check is required even here, because historic versions of Action Scheduler 56 56 // followed a different pattern (in some unusual cases, we could reach this point and the … … 64 64 // Support usage in themes - load this version if no plugin has loaded a version yet. 65 65 if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) { 66 action_scheduler_initialize_3_dot_9_dot_ 2(); // WRCS: DEFINED_VERSION.66 action_scheduler_initialize_3_dot_9_dot_3(); // WRCS: DEFINED_VERSION. 67 67 do_action( 'action_scheduler_pre_theme_init' ); 68 68 ActionScheduler_Versions::initialize_latest_version(); -
action-scheduler/tags/3.9.3/changelog.txt
r3233744 r3328081 1 1 *** Changelog *** 2 3 = 3.9.3 - 2025-07-15 = 4 * Add hook 'action_scheduler_ensure_recurring_actions' specifically for scheduling recurring actions. 5 * Assume an action is valid until proven otherwise. 6 * Implement SKIP LOCKED during action claiming. 7 * Import `get_flag_value()` from `WP_CLI\Utils` before using. 8 * Make `$unique` available to all pre-creation/short-circuit hooks. 9 * Make version/source information available via new class. 10 * Only release claims on pending actions. 11 * Tweak - WP 6.8 compatibility. 12 * Update minimum supported php and phpunit versions. 13 * Update readme.txt. 14 * WP CLI get action command: correct parentheses/nesting of conditional checks. 2 15 3 16 = 3.9.2 - 2025-02-03 = -
action-scheduler/tags/3.9.3/classes/ActionScheduler_DataController.php
r3189111 r3328081 163 163 } 164 164 165 $wp_object_cache->group_ops = array(); 166 $wp_object_cache->stats = array(); 167 $wp_object_cache->memcache_debug = array(); 168 $wp_object_cache->cache = array(); 165 // Not all drop-ins support these props, however, there may be existing installations that rely on these being cleared. 166 if ( property_exists( $wp_object_cache, 'group_ops' ) ) { 167 $wp_object_cache->group_ops = array(); 168 } 169 if ( property_exists( $wp_object_cache, 'stats' ) ) { 170 $wp_object_cache->stats = array(); 171 } 172 if ( property_exists( $wp_object_cache, 'memcache_debug' ) ) { 173 $wp_object_cache->memcache_debug = array(); 174 } 175 if ( property_exists( $wp_object_cache, 'cache' ) ) { 176 $wp_object_cache->cache = array(); 177 } 169 178 170 179 if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) { -
action-scheduler/tags/3.9.3/classes/ActionScheduler_wcSystemStatus.php
r2622865 r3328081 77 77 $action = $this->store->query_actions( 78 78 array( 79 'claimed' => false,80 79 'status' => $status, 81 80 'per_page' => 1, -
action-scheduler/tags/3.9.3/classes/WP_CLI/Action/Create_Command.php
r3226133 r3328081 2 2 3 3 namespace Action_Scheduler\WP_CLI\Action; 4 5 use function \WP_CLI\Utils\get_flag_value; 4 6 5 7 /** -
action-scheduler/tags/3.9.3/classes/WP_CLI/Action/Get_Command.php
r3226133 r3328081 25 25 26 26 $only_logs = ! empty( $this->assoc_args['field'] ) && 'log_entries' === $this->assoc_args['field']; 27 $only_logs = $only_logs || ( ! empty( $this->assoc_args['fields'] && 'log_entries' === $this->assoc_args['fields'] ));27 $only_logs = $only_logs || ( ! empty( $this->assoc_args['fields'] ) && 'log_entries' === $this->assoc_args['fields'] ); 28 28 $log_entries = array(); 29 29 -
action-scheduler/tags/3.9.3/classes/WP_CLI/System_Command.php
r3233744 r3328081 263 263 264 264 $args = array( 265 'claimed' => false,266 265 'status' => $status, 267 266 'per_page' => 1, -
action-scheduler/tags/3.9.3/classes/abstracts/ActionScheduler.php
r3226133 r3328081 185 185 ActionScheduler_DataController::init(); 186 186 187 $store = self::store(); 188 $logger = self::logger(); 189 $runner = self::runner(); 190 $admin_view = self::admin_view(); 187 $store = self::store(); 188 $logger = self::logger(); 189 $runner = self::runner(); 190 $admin_view = self::admin_view(); 191 $recurring_action_scheduler = new ActionScheduler_RecurringActionScheduler(); 191 192 192 193 // Ensure initialization on plugin activation. … … 197 198 add_action( 'init', array( $logger, 'init' ), 1, 0 ); 198 199 add_action( 'init', array( $runner, 'init' ), 1, 0 ); 200 add_action( 'init', array( $recurring_action_scheduler, 'init' ), 1, 0 ); 199 201 200 202 add_action( … … 224 226 $logger->init(); 225 227 $runner->init(); 228 $recurring_action_scheduler->init(); 226 229 self::$data_store_initialized = true; 227 230 -
action-scheduler/tags/3.9.3/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php
r3189111 r3328081 87 87 try { 88 88 try { 89 $valid_action = false; 89 $valid_action = true; 90 90 91 do_action( 'action_scheduler_before_execute', $action_id, $context ); 91 92 92 93 if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { 94 $valid_action = false; 93 95 do_action( 'action_scheduler_execution_ignored', $action_id, $context ); 94 96 return; 95 97 } 96 98 97 $valid_action = true;98 99 do_action( 'action_scheduler_begin_execute', $action_id, $context ); 99 100 -
action-scheduler/tags/3.9.3/classes/data-stores/ActionScheduler_DBStore.php
r3189111 r3328081 932 932 */ 933 933 global $wpdb; 934 935 934 $now = as_get_datetime_object(); 936 935 $date = is_null( $before_date ) ? $now : clone $before_date; 937 // can't use $wpdb->update() because of the <= condition.938 $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";939 $params = array(940 $claim_id,941 $now->format( 'Y-m-d H:i:s' ),942 current_time( 'mysql' ),943 );944 936 945 937 // Set claim filters. … … 955 947 } 956 948 957 $where = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s'; 958 $params[] = $date->format( 'Y-m-d H:i:s' ); 959 $params[] = self::STATUS_PENDING; 949 $where = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s'; 950 $where_params = array( 951 $date->format( 'Y-m-d H:i:s' ), 952 self::STATUS_PENDING, 953 ); 960 954 961 955 if ( ! empty( $hooks ) ) { 962 956 $placeholders = array_fill( 0, count( $hooks ), '%s' ); 963 $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';964 $ params = array_merge( $params, array_values( $hooks ) );957 $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')'; 958 $where_params = array_merge( $where_params, array_values( $hooks ) ); 965 959 } 966 960 … … 997 991 * Sets the order-by clause used in the action claim query. 998 992 * 999 * @since 3.4.01000 * @since 3.8.3 Made $claim_id and $hooks available.1001 *1002 993 * @param string $order_by_sql 1003 994 * @param string $claim_id Claim Id. 1004 * @param array $hooks Hooks to filter for. 1005 */ 1006 $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY priority ASC, attempts ASC, scheduled_date_gmt ASC, action_id ASC', $claim_id, $hooks ); 1007 $params[] = $limit; 1008 1009 $sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders 1010 $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 995 * @param array $hooks Hooks to filter for. 996 * 997 * @since 3.8.3 Made $claim_id and $hooks available. 998 * @since 3.4.0 999 */ 1000 $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY priority ASC, attempts ASC, scheduled_date_gmt ASC, action_id ASC', $claim_id, $hooks ); 1001 $skip_locked = $this->db_supports_skip_locked() ? ' SKIP LOCKED' : ''; 1002 1003 // Selecting the action_ids that we plan to claim, while skipping any locked rows to avoid deadlocking. 1004 $select_sql = $wpdb->prepare( "SELECT action_id from {$wpdb->actionscheduler_actions} {$where} {$order} LIMIT %d FOR UPDATE{$skip_locked}", array_merge( $where_params, array( $limit ) ) ); 1005 1006 // Now place it into an UPDATE statement by joining the result sets, allowing for the SKIP LOCKED behavior to take effect. 1007 $update_sql = "UPDATE {$wpdb->actionscheduler_actions} t1 JOIN ( $select_sql ) t2 ON t1.action_id = t2.action_id SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s"; 1008 $update_params = array( 1009 $claim_id, 1010 $now->format( 'Y-m-d H:i:s' ), 1011 current_time( 'mysql' ), 1012 ); 1013 1014 $rows_affected = $wpdb->query( $wpdb->prepare( $update_sql, $update_params ) ); 1011 1015 if ( false === $rows_affected ) { 1012 1016 $error = empty( $wpdb->last_error ) 1013 1017 ? _x( 'unknown', 'database error', 'action-scheduler' ) 1014 1018 : $wpdb->last_error; 1015 1016 1019 throw new \RuntimeException( 1017 1020 sprintf( … … 1027 1030 1028 1031 /** 1032 * Determines whether the database supports using SKIP LOCKED. This logic mimicks the $wpdb::has_cap() logic. 1033 * 1034 * SKIP_LOCKED support was added to MariaDB in 10.6.0 and to MySQL in 8.0.1 1035 * 1036 * @return bool 1037 */ 1038 private function db_supports_skip_locked() { 1039 global $wpdb; 1040 $db_version = $wpdb->db_version(); 1041 $db_server_info = $wpdb->db_server_info(); 1042 $is_mariadb = ( false !== strpos( $db_server_info, 'MariaDB' ) ); 1043 1044 if ( $is_mariadb && 1045 '5.5.5' === $db_version && 1046 PHP_VERSION_ID < 80016 // PHP 8.0.15 or older. 1047 ) { 1048 /* 1049 * Account for MariaDB version being prefixed with '5.5.5-' on older PHP versions. 1050 */ 1051 $db_server_info = preg_replace( '/^5\.5\.5-(.*)/', '$1', $db_server_info ); 1052 $db_version = preg_replace( '/[^0-9.].*/', '', $db_server_info ); 1053 } 1054 1055 $is_supported = ( $is_mariadb && version_compare( $db_version, '10.6.0', '>=' ) ) || 1056 ( ! $is_mariadb && version_compare( $db_version, '8.0.1', '>=' ) ); 1057 1058 /** 1059 * Filter whether the database supports the SKIP LOCKED modifier for queries. 1060 * 1061 * @param bool $is_supported Whether SKIP LOCKED is supported. 1062 * 1063 * @since 3.9.3 1064 */ 1065 return apply_filters( 'action_scheduler_db_supports_skip_locked', $is_supported ); 1066 } 1067 1068 /** 1029 1069 * Get the number of active claims. 1030 1070 * … … 1095 1135 1096 1136 /** 1097 * Release actions from a claim and delete the claim.1137 * Release pending actions from a claim and delete the claim. 1098 1138 * 1099 1139 * @param ActionScheduler_ActionClaim $claim Claim object. … … 1107 1147 */ 1108 1148 global $wpdb; 1149 1150 if ( 0 === intval( $claim->get_id() ) ) { 1151 // Verify that the claim_id is valid before attempting to release it. 1152 return; 1153 } 1109 1154 1110 1155 /** … … 1114 1159 * 1115 1160 * We resolve this by getting all the actions_id that we want to release claim from in a separate query, and then releasing the claim on each of them. This way, our lock is acquired on the action_id index instead of the claim_id index. Note that the lock on claim_id will still be acquired, but it will only when we actually make the update, rather than when we select the actions. 1116 */ 1117 $action_ids = $wpdb->get_col( $wpdb->prepare( "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", $claim->get_id() ) ); 1161 * 1162 * We only release pending actions in order for them to be claimed by another process. 1163 */ 1164 $action_ids = $wpdb->get_col( $wpdb->prepare( "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d AND status = %s", $claim->get_id(), self::STATUS_PENDING ) ); 1118 1165 1119 1166 $row_updates = 0; -
action-scheduler/tags/3.9.3/classes/data-stores/ActionScheduler_HybridStore.php
r3189111 r3328081 433 433 434 434 /** 435 * Release a claim in the table data store .435 * Release a claim in the table data store on any pending actions. 436 436 * 437 437 * @param ActionScheduler_ActionClaim $claim Claim object. -
action-scheduler/tags/3.9.3/classes/data-stores/ActionScheduler_wpPostStore.php
r3189111 r3328081 792 792 793 793 /** 794 * Release claim.794 * Release pending actions from a claim. 795 795 * 796 796 * @param ActionScheduler_ActionClaim $claim Claim object to release. … … 799 799 */ 800 800 public function release_claim( ActionScheduler_ActionClaim $claim ) { 801 $action_ids = $this->find_actions_by_claim_id( $claim->get_id() );802 if ( empty( $action_ids ) ) {803 return; // nothing to do.804 }805 $action_id_string = implode( ',', array_map( 'intval', $action_ids ) );806 801 /** 807 802 * Global wpdb object. … … 810 805 */ 811 806 global $wpdb; 807 808 $claim_id = $claim->get_id(); 809 if ( trim( $claim_id ) === '' ) { 810 // Verify that the claim_id is valid before attempting to release it. 811 return; 812 } 813 814 // Only attempt to release pending actions to be claimed again. Running and complete actions are no longer relevant outside of admin/analytics. 815 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 816 $action_ids = $wpdb->get_col( 817 $wpdb->prepare( 818 "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s AND post_status = %s", 819 self::POST_TYPE, 820 $claim_id, 821 self::STATUS_PENDING 822 ) 823 ); 824 825 if ( empty( $action_ids ) ) { 826 return; // nothing to do. 827 } 828 $action_id_string = implode( ',', array_map( 'intval', $action_ids ) ); 812 829 813 830 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -
action-scheduler/tags/3.9.3/classes/schema/ActionScheduler_StoreSchema.php
r3189111 r3328081 21 21 * @var int 22 22 */ 23 protected $schema_version = 7;23 protected $schema_version = 8; 24 24 25 25 /** … … 81 81 KEY group_id (group_id), 82 82 KEY last_attempt_gmt (last_attempt_gmt), 83 KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`) 83 KEY `claim_id_status_priority_scheduled_date_gmt` (`claim_id`,`status`,`priority`,`scheduled_date_gmt`), 84 KEY `status_last_attempt_gmt` (`status`,`last_attempt_gmt`), 85 KEY `status_claim_id` (`status`,`claim_id`) 84 86 ) $charset_collate"; 85 87 -
action-scheduler/tags/3.9.3/functions.php
r3189111 r3328081 87 87 * @param string $group Action group. 88 88 * @param int $priorities Action priority. 89 * @param bool $unique Unique action. 89 90 */ 90 $pre = apply_filters( 'pre_as_schedule_single_action', null, $timestamp, $hook, $args, $group, $priority );91 $pre = apply_filters( 'pre_as_schedule_single_action', null, $timestamp, $hook, $args, $group, $priority, $unique ); 91 92 if ( null !== $pre ) { 92 93 return is_int( $pre ) ? $pre : 0; … … 160 161 * @param string $group Action group. 161 162 * @param int $priority Action priority. 163 * @param bool $unique Unique action. 162 164 */ 163 $pre = apply_filters( 'pre_as_schedule_recurring_action', null, $timestamp, $interval_in_seconds, $hook, $args, $group, $priority );165 $pre = apply_filters( 'pre_as_schedule_recurring_action', null, $timestamp, $interval_in_seconds, $hook, $args, $group, $priority, $unique ); 164 166 if ( null !== $pre ) { 165 167 return is_int( $pre ) ? $pre : 0; … … 226 228 * @param string $group Action group. 227 229 * @param int $priority Action priority. 230 * @param bool $unique Unique action. 228 231 */ 229 $pre = apply_filters( 'pre_as_schedule_cron_action', null, $timestamp, $schedule, $hook, $args, $group, $priority );232 $pre = apply_filters( 'pre_as_schedule_cron_action', null, $timestamp, $schedule, $hook, $args, $group, $priority, $unique ); 230 233 if ( null !== $pre ) { 231 234 return is_int( $pre ) ? $pre : 0; … … 494 497 return $date; 495 498 } 499 500 /** 501 * Check if a specific feature is supported by the current version of Action Scheduler. 502 * 503 * @since 3.9.3 504 * 505 * @param string $feature The feature to check support for. 506 * 507 * @return bool True if the feature is supported, false otherwise. 508 */ 509 function as_supports( string $feature ): bool { 510 $supported_features = array( 'ensure_recurring_actions_hook' ); 511 512 return in_array( $feature, $supported_features, true ); 513 } -
action-scheduler/tags/3.9.3/readme.txt
r3233744 r3328081 2 2 Contributors: Automattic, wpmuguru, claudiosanches, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, royho, barryhughes-1 3 3 Tags: scheduler, cron 4 Stable tag: 3.9. 24 Stable tag: 3.9.3 5 5 License: GPLv3 6 6 Requires at least: 6.5 7 Tested up to: 6. 78 Requires PHP: 7. 17 Tested up to: 6.8 8 Requires PHP: 7.2 9 9 10 10 Action Scheduler - Job Queue for WordPress … … 30 30 ## Learn More 31 31 32 To learn more about how toAction Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org).32 To learn more about how Action Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org). 33 33 34 34 There you will find: … … 47 47 48 48 == Changelog == 49 50 = 3.9.3 - 2025-07-15 = 51 * Add hook 'action_scheduler_ensure_recurring_actions' specifically for scheduling recurring actions. 52 * Assume an action is valid until proven otherwise. 53 * Implement SKIP LOCKED during action claiming. 54 * Import `get_flag_value()` from `WP_CLI\Utils` before using. 55 * Make `$unique` available to all pre-creation/short-circuit hooks. 56 * Make version/source information available via new class. 57 * Only release claims on pending actions. 58 * Tweak - WP 6.8 compatibility. 59 * Update minimum supported php and phpunit versions. 60 * Update readme.txt. 61 * WP CLI get action command: correct parentheses/nesting of conditional checks. 49 62 50 63 = 3.9.2 - 2025-02-03 = -
action-scheduler/tags/3.9.3/vendor/autoload.php
r3151094 r3328081 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1::getLoader();25 return ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685::getLoader(); -
action-scheduler/tags/3.9.3/vendor/composer/InstalledVersions.php
r3151094 r3328081 323 323 324 324 $installed = array(); 325 $copiedLocalDir = false; 325 326 326 327 if (self::$canGetVendors) { … … 331 332 /** @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 */ 332 333 $required = require $vendorDir.'/composer/installed.php'; 333 $installed[] = self::$installedByVendor[$vendorDir] = $required; 334 if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 335 self::$installed = $installed[count($installed) - 1]; 334 self::$installedByVendor[$vendorDir] = $required; 335 $installed[] = $required; 336 if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 337 self::$installed = $required; 338 $copiedLocalDir = true; 336 339 } 337 340 } … … 351 354 } 352 355 353 if (self::$installed !== array() ) {356 if (self::$installed !== array() && !$copiedLocalDir) { 354 357 $installed[] = self::$installed; 355 358 } -
action-scheduler/tags/3.9.3/vendor/composer/autoload_real.php
r3151094 r3328081 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df15 class ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df1::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685::getInitializer($loader)); 33 33 34 34 $loader->register(true); -
action-scheduler/tags/3.9.3/vendor/composer/autoload_static.php
r3151094 r3328081 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df17 class ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685 8 8 { 9 9 public static $classMap = array ( … … 14 14 { 15 15 return \Closure::bind(function () use ($loader) { 16 $loader->classMap = ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df1::$classMap;16 $loader->classMap = ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685::$classMap; 17 17 18 18 }, null, ClassLoader::class); -
action-scheduler/tags/3.9.3/vendor/composer/installed.php
r3233744 r3328081 2 2 'root' => array( 3 3 'name' => 'woocommerce/action-scheduler', 4 'pretty_version' => 'dev-release/3.9. 2',5 'version' => 'dev-release/3.9. 2',6 'reference' => ' efbb7953f72a433086335b249292f280dd43ddfe',4 'pretty_version' => 'dev-release/3.9.3', 5 'version' => 'dev-release/3.9.3', 6 'reference' => 'c58cdbab17651303d406cd3b22cf9d75c71c986c', 7 7 'type' => 'wordpress-plugin', 8 8 'install_path' => __DIR__ . '/../../', … … 12 12 'versions' => array( 13 13 'woocommerce/action-scheduler' => array( 14 'pretty_version' => 'dev-release/3.9. 2',15 'version' => 'dev-release/3.9. 2',16 'reference' => ' efbb7953f72a433086335b249292f280dd43ddfe',14 'pretty_version' => 'dev-release/3.9.3', 15 'version' => 'dev-release/3.9.3', 16 'reference' => 'c58cdbab17651303d406cd3b22cf9d75c71c986c', 17 17 'type' => 'wordpress-plugin', 18 18 'install_path' => __DIR__ . '/../../', -
action-scheduler/tags/3.9.3/vendor/composer/platform_check.php
r3189111 r3328081 5 5 $issues = array(); 6 6 7 if (!(PHP_VERSION_ID >= 70 100)) {8 $issues[] = 'Your Composer dependencies require a PHP version ">= 7. 1.0". You are running ' . PHP_VERSION . '.';7 if (!(PHP_VERSION_ID >= 70200)) { 8 $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; 9 9 } 10 10 -
action-scheduler/trunk/action-scheduler.php
r3233744 r3328081 6 6 * Author: Automattic 7 7 * Author URI: https://automattic.com/ 8 * Version: 3.9. 28 * Version: 3.9.3 9 9 * License: GPLv3 10 10 * Requires at least: 6.5 11 * Tested up to: 6. 712 * Requires PHP: 7. 111 * Tested up to: 6.8 12 * Requires PHP: 7.2 13 13 * 14 14 * Copyright 2019 Automattic, Inc. (https://automattic.com/contact/) … … 30 30 */ 31 31 32 if ( ! function_exists( 'action_scheduler_register_3_dot_9_dot_ 2' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION.32 if ( ! function_exists( 'action_scheduler_register_3_dot_9_dot_3' ) && function_exists( 'add_action' ) ) { // WRCS: DEFINED_VERSION. 33 33 34 34 if ( ! class_exists( 'ActionScheduler_Versions', false ) ) { … … 37 37 } 38 38 39 add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_9_dot_ 2', 0, 0 ); // WRCS: DEFINED_VERSION.39 add_action( 'plugins_loaded', 'action_scheduler_register_3_dot_9_dot_3', 0, 0 ); // WRCS: DEFINED_VERSION. 40 40 41 41 // phpcs:disable Generic.Functions.OpeningFunctionBraceKernighanRitchie.ContentAfterBrace … … 43 43 * Registers this version of Action Scheduler. 44 44 */ 45 function action_scheduler_register_3_dot_9_dot_ 2() { // WRCS: DEFINED_VERSION.45 function action_scheduler_register_3_dot_9_dot_3() { // WRCS: DEFINED_VERSION. 46 46 $versions = ActionScheduler_Versions::instance(); 47 $versions->register( '3.9. 2', 'action_scheduler_initialize_3_dot_9_dot_2' ); // WRCS: DEFINED_VERSION.47 $versions->register( '3.9.3', 'action_scheduler_initialize_3_dot_9_dot_3' ); // WRCS: DEFINED_VERSION. 48 48 } 49 49 … … 52 52 * Initializes this version of Action Scheduler. 53 53 */ 54 function action_scheduler_initialize_3_dot_9_dot_ 2() { // WRCS: DEFINED_VERSION.54 function action_scheduler_initialize_3_dot_9_dot_3() { // WRCS: DEFINED_VERSION. 55 55 // A final safety check is required even here, because historic versions of Action Scheduler 56 56 // followed a different pattern (in some unusual cases, we could reach this point and the … … 64 64 // Support usage in themes - load this version if no plugin has loaded a version yet. 65 65 if ( did_action( 'plugins_loaded' ) && ! doing_action( 'plugins_loaded' ) && ! class_exists( 'ActionScheduler', false ) ) { 66 action_scheduler_initialize_3_dot_9_dot_ 2(); // WRCS: DEFINED_VERSION.66 action_scheduler_initialize_3_dot_9_dot_3(); // WRCS: DEFINED_VERSION. 67 67 do_action( 'action_scheduler_pre_theme_init' ); 68 68 ActionScheduler_Versions::initialize_latest_version(); -
action-scheduler/trunk/changelog.txt
r3233744 r3328081 1 1 *** Changelog *** 2 3 = 3.9.3 - 2025-07-15 = 4 * Add hook 'action_scheduler_ensure_recurring_actions' specifically for scheduling recurring actions. 5 * Assume an action is valid until proven otherwise. 6 * Implement SKIP LOCKED during action claiming. 7 * Import `get_flag_value()` from `WP_CLI\Utils` before using. 8 * Make `$unique` available to all pre-creation/short-circuit hooks. 9 * Make version/source information available via new class. 10 * Only release claims on pending actions. 11 * Tweak - WP 6.8 compatibility. 12 * Update minimum supported php and phpunit versions. 13 * Update readme.txt. 14 * WP CLI get action command: correct parentheses/nesting of conditional checks. 2 15 3 16 = 3.9.2 - 2025-02-03 = -
action-scheduler/trunk/classes/ActionScheduler_DataController.php
r3189111 r3328081 163 163 } 164 164 165 $wp_object_cache->group_ops = array(); 166 $wp_object_cache->stats = array(); 167 $wp_object_cache->memcache_debug = array(); 168 $wp_object_cache->cache = array(); 165 // Not all drop-ins support these props, however, there may be existing installations that rely on these being cleared. 166 if ( property_exists( $wp_object_cache, 'group_ops' ) ) { 167 $wp_object_cache->group_ops = array(); 168 } 169 if ( property_exists( $wp_object_cache, 'stats' ) ) { 170 $wp_object_cache->stats = array(); 171 } 172 if ( property_exists( $wp_object_cache, 'memcache_debug' ) ) { 173 $wp_object_cache->memcache_debug = array(); 174 } 175 if ( property_exists( $wp_object_cache, 'cache' ) ) { 176 $wp_object_cache->cache = array(); 177 } 169 178 170 179 if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) { -
action-scheduler/trunk/classes/ActionScheduler_wcSystemStatus.php
r2622865 r3328081 77 77 $action = $this->store->query_actions( 78 78 array( 79 'claimed' => false,80 79 'status' => $status, 81 80 'per_page' => 1, -
action-scheduler/trunk/classes/WP_CLI/Action/Create_Command.php
r3226133 r3328081 2 2 3 3 namespace Action_Scheduler\WP_CLI\Action; 4 5 use function \WP_CLI\Utils\get_flag_value; 4 6 5 7 /** -
action-scheduler/trunk/classes/WP_CLI/Action/Get_Command.php
r3226133 r3328081 25 25 26 26 $only_logs = ! empty( $this->assoc_args['field'] ) && 'log_entries' === $this->assoc_args['field']; 27 $only_logs = $only_logs || ( ! empty( $this->assoc_args['fields'] && 'log_entries' === $this->assoc_args['fields'] ));27 $only_logs = $only_logs || ( ! empty( $this->assoc_args['fields'] ) && 'log_entries' === $this->assoc_args['fields'] ); 28 28 $log_entries = array(); 29 29 -
action-scheduler/trunk/classes/WP_CLI/System_Command.php
r3233744 r3328081 263 263 264 264 $args = array( 265 'claimed' => false,266 265 'status' => $status, 267 266 'per_page' => 1, -
action-scheduler/trunk/classes/abstracts/ActionScheduler.php
r3226133 r3328081 185 185 ActionScheduler_DataController::init(); 186 186 187 $store = self::store(); 188 $logger = self::logger(); 189 $runner = self::runner(); 190 $admin_view = self::admin_view(); 187 $store = self::store(); 188 $logger = self::logger(); 189 $runner = self::runner(); 190 $admin_view = self::admin_view(); 191 $recurring_action_scheduler = new ActionScheduler_RecurringActionScheduler(); 191 192 192 193 // Ensure initialization on plugin activation. … … 197 198 add_action( 'init', array( $logger, 'init' ), 1, 0 ); 198 199 add_action( 'init', array( $runner, 'init' ), 1, 0 ); 200 add_action( 'init', array( $recurring_action_scheduler, 'init' ), 1, 0 ); 199 201 200 202 add_action( … … 224 226 $logger->init(); 225 227 $runner->init(); 228 $recurring_action_scheduler->init(); 226 229 self::$data_store_initialized = true; 227 230 -
action-scheduler/trunk/classes/abstracts/ActionScheduler_Abstract_QueueRunner.php
r3189111 r3328081 87 87 try { 88 88 try { 89 $valid_action = false; 89 $valid_action = true; 90 90 91 do_action( 'action_scheduler_before_execute', $action_id, $context ); 91 92 92 93 if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) { 94 $valid_action = false; 93 95 do_action( 'action_scheduler_execution_ignored', $action_id, $context ); 94 96 return; 95 97 } 96 98 97 $valid_action = true;98 99 do_action( 'action_scheduler_begin_execute', $action_id, $context ); 99 100 -
action-scheduler/trunk/classes/data-stores/ActionScheduler_DBStore.php
r3189111 r3328081 932 932 */ 933 933 global $wpdb; 934 935 934 $now = as_get_datetime_object(); 936 935 $date = is_null( $before_date ) ? $now : clone $before_date; 937 // can't use $wpdb->update() because of the <= condition.938 $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";939 $params = array(940 $claim_id,941 $now->format( 'Y-m-d H:i:s' ),942 current_time( 'mysql' ),943 );944 936 945 937 // Set claim filters. … … 955 947 } 956 948 957 $where = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s'; 958 $params[] = $date->format( 'Y-m-d H:i:s' ); 959 $params[] = self::STATUS_PENDING; 949 $where = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s'; 950 $where_params = array( 951 $date->format( 'Y-m-d H:i:s' ), 952 self::STATUS_PENDING, 953 ); 960 954 961 955 if ( ! empty( $hooks ) ) { 962 956 $placeholders = array_fill( 0, count( $hooks ), '%s' ); 963 $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';964 $ params = array_merge( $params, array_values( $hooks ) );957 $where .= ' AND hook IN (' . join( ', ', $placeholders ) . ')'; 958 $where_params = array_merge( $where_params, array_values( $hooks ) ); 965 959 } 966 960 … … 997 991 * Sets the order-by clause used in the action claim query. 998 992 * 999 * @since 3.4.01000 * @since 3.8.3 Made $claim_id and $hooks available.1001 *1002 993 * @param string $order_by_sql 1003 994 * @param string $claim_id Claim Id. 1004 * @param array $hooks Hooks to filter for. 1005 */ 1006 $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY priority ASC, attempts ASC, scheduled_date_gmt ASC, action_id ASC', $claim_id, $hooks ); 1007 $params[] = $limit; 1008 1009 $sql = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders 1010 $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 995 * @param array $hooks Hooks to filter for. 996 * 997 * @since 3.8.3 Made $claim_id and $hooks available. 998 * @since 3.4.0 999 */ 1000 $order = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY priority ASC, attempts ASC, scheduled_date_gmt ASC, action_id ASC', $claim_id, $hooks ); 1001 $skip_locked = $this->db_supports_skip_locked() ? ' SKIP LOCKED' : ''; 1002 1003 // Selecting the action_ids that we plan to claim, while skipping any locked rows to avoid deadlocking. 1004 $select_sql = $wpdb->prepare( "SELECT action_id from {$wpdb->actionscheduler_actions} {$where} {$order} LIMIT %d FOR UPDATE{$skip_locked}", array_merge( $where_params, array( $limit ) ) ); 1005 1006 // Now place it into an UPDATE statement by joining the result sets, allowing for the SKIP LOCKED behavior to take effect. 1007 $update_sql = "UPDATE {$wpdb->actionscheduler_actions} t1 JOIN ( $select_sql ) t2 ON t1.action_id = t2.action_id SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s"; 1008 $update_params = array( 1009 $claim_id, 1010 $now->format( 'Y-m-d H:i:s' ), 1011 current_time( 'mysql' ), 1012 ); 1013 1014 $rows_affected = $wpdb->query( $wpdb->prepare( $update_sql, $update_params ) ); 1011 1015 if ( false === $rows_affected ) { 1012 1016 $error = empty( $wpdb->last_error ) 1013 1017 ? _x( 'unknown', 'database error', 'action-scheduler' ) 1014 1018 : $wpdb->last_error; 1015 1016 1019 throw new \RuntimeException( 1017 1020 sprintf( … … 1027 1030 1028 1031 /** 1032 * Determines whether the database supports using SKIP LOCKED. This logic mimicks the $wpdb::has_cap() logic. 1033 * 1034 * SKIP_LOCKED support was added to MariaDB in 10.6.0 and to MySQL in 8.0.1 1035 * 1036 * @return bool 1037 */ 1038 private function db_supports_skip_locked() { 1039 global $wpdb; 1040 $db_version = $wpdb->db_version(); 1041 $db_server_info = $wpdb->db_server_info(); 1042 $is_mariadb = ( false !== strpos( $db_server_info, 'MariaDB' ) ); 1043 1044 if ( $is_mariadb && 1045 '5.5.5' === $db_version && 1046 PHP_VERSION_ID < 80016 // PHP 8.0.15 or older. 1047 ) { 1048 /* 1049 * Account for MariaDB version being prefixed with '5.5.5-' on older PHP versions. 1050 */ 1051 $db_server_info = preg_replace( '/^5\.5\.5-(.*)/', '$1', $db_server_info ); 1052 $db_version = preg_replace( '/[^0-9.].*/', '', $db_server_info ); 1053 } 1054 1055 $is_supported = ( $is_mariadb && version_compare( $db_version, '10.6.0', '>=' ) ) || 1056 ( ! $is_mariadb && version_compare( $db_version, '8.0.1', '>=' ) ); 1057 1058 /** 1059 * Filter whether the database supports the SKIP LOCKED modifier for queries. 1060 * 1061 * @param bool $is_supported Whether SKIP LOCKED is supported. 1062 * 1063 * @since 3.9.3 1064 */ 1065 return apply_filters( 'action_scheduler_db_supports_skip_locked', $is_supported ); 1066 } 1067 1068 /** 1029 1069 * Get the number of active claims. 1030 1070 * … … 1095 1135 1096 1136 /** 1097 * Release actions from a claim and delete the claim.1137 * Release pending actions from a claim and delete the claim. 1098 1138 * 1099 1139 * @param ActionScheduler_ActionClaim $claim Claim object. … … 1107 1147 */ 1108 1148 global $wpdb; 1149 1150 if ( 0 === intval( $claim->get_id() ) ) { 1151 // Verify that the claim_id is valid before attempting to release it. 1152 return; 1153 } 1109 1154 1110 1155 /** … … 1114 1159 * 1115 1160 * We resolve this by getting all the actions_id that we want to release claim from in a separate query, and then releasing the claim on each of them. This way, our lock is acquired on the action_id index instead of the claim_id index. Note that the lock on claim_id will still be acquired, but it will only when we actually make the update, rather than when we select the actions. 1116 */ 1117 $action_ids = $wpdb->get_col( $wpdb->prepare( "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d", $claim->get_id() ) ); 1161 * 1162 * We only release pending actions in order for them to be claimed by another process. 1163 */ 1164 $action_ids = $wpdb->get_col( $wpdb->prepare( "SELECT action_id FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d AND status = %s", $claim->get_id(), self::STATUS_PENDING ) ); 1118 1165 1119 1166 $row_updates = 0; -
action-scheduler/trunk/classes/data-stores/ActionScheduler_HybridStore.php
r3189111 r3328081 433 433 434 434 /** 435 * Release a claim in the table data store .435 * Release a claim in the table data store on any pending actions. 436 436 * 437 437 * @param ActionScheduler_ActionClaim $claim Claim object. -
action-scheduler/trunk/classes/data-stores/ActionScheduler_wpPostStore.php
r3189111 r3328081 792 792 793 793 /** 794 * Release claim.794 * Release pending actions from a claim. 795 795 * 796 796 * @param ActionScheduler_ActionClaim $claim Claim object to release. … … 799 799 */ 800 800 public function release_claim( ActionScheduler_ActionClaim $claim ) { 801 $action_ids = $this->find_actions_by_claim_id( $claim->get_id() );802 if ( empty( $action_ids ) ) {803 return; // nothing to do.804 }805 $action_id_string = implode( ',', array_map( 'intval', $action_ids ) );806 801 /** 807 802 * Global wpdb object. … … 810 805 */ 811 806 global $wpdb; 807 808 $claim_id = $claim->get_id(); 809 if ( trim( $claim_id ) === '' ) { 810 // Verify that the claim_id is valid before attempting to release it. 811 return; 812 } 813 814 // Only attempt to release pending actions to be claimed again. Running and complete actions are no longer relevant outside of admin/analytics. 815 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 816 $action_ids = $wpdb->get_col( 817 $wpdb->prepare( 818 "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s AND post_status = %s", 819 self::POST_TYPE, 820 $claim_id, 821 self::STATUS_PENDING 822 ) 823 ); 824 825 if ( empty( $action_ids ) ) { 826 return; // nothing to do. 827 } 828 $action_id_string = implode( ',', array_map( 'intval', $action_ids ) ); 812 829 813 830 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -
action-scheduler/trunk/classes/schema/ActionScheduler_StoreSchema.php
r3189111 r3328081 21 21 * @var int 22 22 */ 23 protected $schema_version = 7;23 protected $schema_version = 8; 24 24 25 25 /** … … 81 81 KEY group_id (group_id), 82 82 KEY last_attempt_gmt (last_attempt_gmt), 83 KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`) 83 KEY `claim_id_status_priority_scheduled_date_gmt` (`claim_id`,`status`,`priority`,`scheduled_date_gmt`), 84 KEY `status_last_attempt_gmt` (`status`,`last_attempt_gmt`), 85 KEY `status_claim_id` (`status`,`claim_id`) 84 86 ) $charset_collate"; 85 87 -
action-scheduler/trunk/functions.php
r3189111 r3328081 87 87 * @param string $group Action group. 88 88 * @param int $priorities Action priority. 89 * @param bool $unique Unique action. 89 90 */ 90 $pre = apply_filters( 'pre_as_schedule_single_action', null, $timestamp, $hook, $args, $group, $priority );91 $pre = apply_filters( 'pre_as_schedule_single_action', null, $timestamp, $hook, $args, $group, $priority, $unique ); 91 92 if ( null !== $pre ) { 92 93 return is_int( $pre ) ? $pre : 0; … … 160 161 * @param string $group Action group. 161 162 * @param int $priority Action priority. 163 * @param bool $unique Unique action. 162 164 */ 163 $pre = apply_filters( 'pre_as_schedule_recurring_action', null, $timestamp, $interval_in_seconds, $hook, $args, $group, $priority );165 $pre = apply_filters( 'pre_as_schedule_recurring_action', null, $timestamp, $interval_in_seconds, $hook, $args, $group, $priority, $unique ); 164 166 if ( null !== $pre ) { 165 167 return is_int( $pre ) ? $pre : 0; … … 226 228 * @param string $group Action group. 227 229 * @param int $priority Action priority. 230 * @param bool $unique Unique action. 228 231 */ 229 $pre = apply_filters( 'pre_as_schedule_cron_action', null, $timestamp, $schedule, $hook, $args, $group, $priority );232 $pre = apply_filters( 'pre_as_schedule_cron_action', null, $timestamp, $schedule, $hook, $args, $group, $priority, $unique ); 230 233 if ( null !== $pre ) { 231 234 return is_int( $pre ) ? $pre : 0; … … 494 497 return $date; 495 498 } 499 500 /** 501 * Check if a specific feature is supported by the current version of Action Scheduler. 502 * 503 * @since 3.9.3 504 * 505 * @param string $feature The feature to check support for. 506 * 507 * @return bool True if the feature is supported, false otherwise. 508 */ 509 function as_supports( string $feature ): bool { 510 $supported_features = array( 'ensure_recurring_actions_hook' ); 511 512 return in_array( $feature, $supported_features, true ); 513 } -
action-scheduler/trunk/readme.txt
r3233744 r3328081 2 2 Contributors: Automattic, wpmuguru, claudiosanches, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, royho, barryhughes-1 3 3 Tags: scheduler, cron 4 Stable tag: 3.9. 24 Stable tag: 3.9.3 5 5 License: GPLv3 6 6 Requires at least: 6.5 7 Tested up to: 6. 78 Requires PHP: 7. 17 Tested up to: 6.8 8 Requires PHP: 7.2 9 9 10 10 Action Scheduler - Job Queue for WordPress … … 30 30 ## Learn More 31 31 32 To learn more about how toAction Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org).32 To learn more about how Action Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org). 33 33 34 34 There you will find: … … 47 47 48 48 == Changelog == 49 50 = 3.9.3 - 2025-07-15 = 51 * Add hook 'action_scheduler_ensure_recurring_actions' specifically for scheduling recurring actions. 52 * Assume an action is valid until proven otherwise. 53 * Implement SKIP LOCKED during action claiming. 54 * Import `get_flag_value()` from `WP_CLI\Utils` before using. 55 * Make `$unique` available to all pre-creation/short-circuit hooks. 56 * Make version/source information available via new class. 57 * Only release claims on pending actions. 58 * Tweak - WP 6.8 compatibility. 59 * Update minimum supported php and phpunit versions. 60 * Update readme.txt. 61 * WP CLI get action command: correct parentheses/nesting of conditional checks. 49 62 50 63 = 3.9.2 - 2025-02-03 = -
action-scheduler/trunk/vendor/autoload.php
r3151094 r3328081 23 23 require_once __DIR__ . '/composer/autoload_real.php'; 24 24 25 return ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1::getLoader();25 return ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685::getLoader(); -
action-scheduler/trunk/vendor/composer/InstalledVersions.php
r3151094 r3328081 323 323 324 324 $installed = array(); 325 $copiedLocalDir = false; 325 326 326 327 if (self::$canGetVendors) { … … 331 332 /** @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 */ 332 333 $required = require $vendorDir.'/composer/installed.php'; 333 $installed[] = self::$installedByVendor[$vendorDir] = $required; 334 if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 335 self::$installed = $installed[count($installed) - 1]; 334 self::$installedByVendor[$vendorDir] = $required; 335 $installed[] = $required; 336 if (strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { 337 self::$installed = $required; 338 $copiedLocalDir = true; 336 339 } 337 340 } … … 351 354 } 352 355 353 if (self::$installed !== array() ) {356 if (self::$installed !== array() && !$copiedLocalDir) { 354 357 $installed[] = self::$installed; 355 358 } -
action-scheduler/trunk/vendor/composer/autoload_real.php
r3151094 r3328081 3 3 // autoload_real.php @generated by Composer 4 4 5 class ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df15 class ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685 6 6 { 7 7 private static $loader; … … 25 25 require __DIR__ . '/platform_check.php'; 26 26 27 spl_autoload_register(array('ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1', 'loadClassLoader'), true, true);27 spl_autoload_register(array('ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685', 'loadClassLoader'), true, true); 28 28 self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__)); 29 spl_autoload_unregister(array('ComposerAutoloaderInit 81fd3951ccfed0a222e6f4b949998df1', 'loadClassLoader'));29 spl_autoload_unregister(array('ComposerAutoloaderInit55c846ad8e6e369a91b7de2e9976f685', 'loadClassLoader')); 30 30 31 31 require __DIR__ . '/autoload_static.php'; 32 call_user_func(\Composer\Autoload\ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df1::getInitializer($loader));32 call_user_func(\Composer\Autoload\ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685::getInitializer($loader)); 33 33 34 34 $loader->register(true); -
action-scheduler/trunk/vendor/composer/autoload_static.php
r3151094 r3328081 5 5 namespace Composer\Autoload; 6 6 7 class ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df17 class ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685 8 8 { 9 9 public static $classMap = array ( … … 14 14 { 15 15 return \Closure::bind(function () use ($loader) { 16 $loader->classMap = ComposerStaticInit 81fd3951ccfed0a222e6f4b949998df1::$classMap;16 $loader->classMap = ComposerStaticInit55c846ad8e6e369a91b7de2e9976f685::$classMap; 17 17 18 18 }, null, ClassLoader::class); -
action-scheduler/trunk/vendor/composer/installed.php
r3233744 r3328081 2 2 'root' => array( 3 3 'name' => 'woocommerce/action-scheduler', 4 'pretty_version' => 'dev-release/3.9. 2',5 'version' => 'dev-release/3.9. 2',6 'reference' => ' efbb7953f72a433086335b249292f280dd43ddfe',4 'pretty_version' => 'dev-release/3.9.3', 5 'version' => 'dev-release/3.9.3', 6 'reference' => 'c58cdbab17651303d406cd3b22cf9d75c71c986c', 7 7 'type' => 'wordpress-plugin', 8 8 'install_path' => __DIR__ . '/../../', … … 12 12 'versions' => array( 13 13 'woocommerce/action-scheduler' => array( 14 'pretty_version' => 'dev-release/3.9. 2',15 'version' => 'dev-release/3.9. 2',16 'reference' => ' efbb7953f72a433086335b249292f280dd43ddfe',14 'pretty_version' => 'dev-release/3.9.3', 15 'version' => 'dev-release/3.9.3', 16 'reference' => 'c58cdbab17651303d406cd3b22cf9d75c71c986c', 17 17 'type' => 'wordpress-plugin', 18 18 'install_path' => __DIR__ . '/../../', -
action-scheduler/trunk/vendor/composer/platform_check.php
r3189111 r3328081 5 5 $issues = array(); 6 6 7 if (!(PHP_VERSION_ID >= 70 100)) {8 $issues[] = 'Your Composer dependencies require a PHP version ">= 7. 1.0". You are running ' . PHP_VERSION . '.';7 if (!(PHP_VERSION_ID >= 70200)) { 8 $issues[] = 'Your Composer dependencies require a PHP version ">= 7.2.0". You are running ' . PHP_VERSION . '.'; 9 9 } 10 10
Note: See TracChangeset
for help on using the changeset viewer.