Completed
Pull Request — develop (#1630)
by
unknown
01:13
created
src/ext/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php 2 patches
Indentation   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -8,35 +8,35 @@  discard block
 block discarded – undo
8 8
  * Creates a custom table for storing action logs
9 9
  */
10 10
 class ActionScheduler_LoggerSchema extends ActionScheduler_Abstract_Schema {
11
-	const LOG_TABLE = 'actionscheduler_logs';
11
+    const LOG_TABLE = 'actionscheduler_logs';
12 12
 
13
-	/**
14
-	 * @var int Increment this value to trigger a schema update.
15
-	 */
16
-	protected $schema_version = 3;
13
+    /**
14
+     * @var int Increment this value to trigger a schema update.
15
+     */
16
+    protected $schema_version = 3;
17 17
 
18
-	public function __construct() {
19
-		$this->tables = array(
20
-			self::LOG_TABLE,
21
-		);
22
-	}
18
+    public function __construct() {
19
+        $this->tables = array(
20
+            self::LOG_TABLE,
21
+        );
22
+    }
23 23
 
24
-	/**
25
-	 * Performs additional setup work required to support this schema.
26
-	 */
27
-	public function init() {
28
-		add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_3_0' ), 10, 2 );
29
-	}
24
+    /**
25
+     * Performs additional setup work required to support this schema.
26
+     */
27
+    public function init() {
28
+        add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_3_0' ), 10, 2 );
29
+    }
30 30
 
31
-	protected function get_table_definition( $table ) {
32
-		global $wpdb;
33
-		$table_name      = $wpdb->$table;
34
-		$charset_collate = $wpdb->get_charset_collate();
35
-		switch ( $table ) {
31
+    protected function get_table_definition( $table ) {
32
+        global $wpdb;
33
+        $table_name      = $wpdb->$table;
34
+        $charset_collate = $wpdb->get_charset_collate();
35
+        switch ( $table ) {
36 36
 
37
-			case self::LOG_TABLE:
38
-				$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
39
-				return "CREATE TABLE $table_name (
37
+            case self::LOG_TABLE:
38
+                $default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
39
+                return "CREATE TABLE $table_name (
40 40
 				        log_id bigint(20) unsigned NOT NULL auto_increment,
41 41
 				        action_id bigint(20) unsigned NOT NULL,
42 42
 				        message text NOT NULL,
@@ -47,43 +47,43 @@  discard block
 block discarded – undo
47 47
 				        KEY log_date_gmt (log_date_gmt)
48 48
 				        ) $charset_collate";
49 49
 
50
-			default:
51
-				return '';
52
-		}
53
-	}
50
+            default:
51
+                return '';
52
+        }
53
+    }
54 54
 
55
-	/**
56
-	 * Update the logs table schema, allowing datetime fields to be NULL.
57
-	 *
58
-	 * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
59
-	 * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
60
-	 *
61
-	 * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
62
-	 * that method relies on dbDelta() and this change is not possible when using that function.
63
-	 *
64
-	 * @param string $table Name of table being updated.
65
-	 * @param string $db_version The existing schema version of the table.
66
-	 */
67
-	public function update_schema_3_0( $table, $db_version ) {
68
-		global $wpdb;
55
+    /**
56
+     * Update the logs table schema, allowing datetime fields to be NULL.
57
+     *
58
+     * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
59
+     * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
60
+     *
61
+     * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
62
+     * that method relies on dbDelta() and this change is not possible when using that function.
63
+     *
64
+     * @param string $table Name of table being updated.
65
+     * @param string $db_version The existing schema version of the table.
66
+     */
67
+    public function update_schema_3_0( $table, $db_version ) {
68
+        global $wpdb;
69 69
 
70
-		if ( 'actionscheduler_logs' !== $table || version_compare( $db_version, '3', '>=' ) ) {
71
-			return;
72
-		}
70
+        if ( 'actionscheduler_logs' !== $table || version_compare( $db_version, '3', '>=' ) ) {
71
+            return;
72
+        }
73 73
 
74
-		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
75
-		$table_name   = $wpdb->prefix . 'actionscheduler_logs';
76
-		$table_list   = $wpdb->get_col( "SHOW TABLES LIKE '{$table_name}'" );
77
-		$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
74
+        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
75
+        $table_name   = $wpdb->prefix . 'actionscheduler_logs';
76
+        $table_list   = $wpdb->get_col( "SHOW TABLES LIKE '{$table_name}'" );
77
+        $default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
78 78
 
79
-		if ( ! empty( $table_list ) ) {
80
-			$query = "
79
+        if ( ! empty( $table_list ) ) {
80
+            $query = "
81 81
 				ALTER TABLE {$table_name}
82 82
 				MODIFY COLUMN log_date_gmt datetime NULL default '{$default_date}',
83 83
 				MODIFY COLUMN log_date_local datetime NULL default '{$default_date}'
84 84
 			";
85
-			$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
86
-		}
87
-		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
88
-	}
85
+            $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
86
+        }
87
+        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
88
+    }
89 89
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -25,14 +25,14 @@  discard block
 block discarded – undo
25 25
 	 * Performs additional setup work required to support this schema.
26 26
 	 */
27 27
 	public function init() {
28
-		add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_3_0' ), 10, 2 );
28
+		add_action('action_scheduler_before_schema_update', array($this, 'update_schema_3_0'), 10, 2);
29 29
 	}
30 30
 
31
-	protected function get_table_definition( $table ) {
31
+	protected function get_table_definition($table) {
32 32
 		global $wpdb;
33 33
 		$table_name      = $wpdb->$table;
34 34
 		$charset_collate = $wpdb->get_charset_collate();
35
-		switch ( $table ) {
35
+		switch ($table) {
36 36
 
37 37
 			case self::LOG_TABLE:
38 38
 				$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
@@ -64,25 +64,25 @@  discard block
 block discarded – undo
64 64
 	 * @param string $table Name of table being updated.
65 65
 	 * @param string $db_version The existing schema version of the table.
66 66
 	 */
67
-	public function update_schema_3_0( $table, $db_version ) {
67
+	public function update_schema_3_0($table, $db_version) {
68 68
 		global $wpdb;
69 69
 
70
-		if ( 'actionscheduler_logs' !== $table || version_compare( $db_version, '3', '>=' ) ) {
70
+		if ('actionscheduler_logs' !== $table || version_compare($db_version, '3', '>=')) {
71 71
 			return;
72 72
 		}
73 73
 
74 74
 		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
75
-		$table_name   = $wpdb->prefix . 'actionscheduler_logs';
76
-		$table_list   = $wpdb->get_col( "SHOW TABLES LIKE '{$table_name}'" );
75
+		$table_name   = $wpdb->prefix.'actionscheduler_logs';
76
+		$table_list   = $wpdb->get_col("SHOW TABLES LIKE '{$table_name}'");
77 77
 		$default_date = ActionScheduler_StoreSchema::DEFAULT_DATE;
78 78
 
79
-		if ( ! empty( $table_list ) ) {
79
+		if ( ! empty($table_list)) {
80 80
 			$query = "
81 81
 				ALTER TABLE {$table_name}
82 82
 				MODIFY COLUMN log_date_gmt datetime NULL default '{$default_date}',
83 83
 				MODIFY COLUMN log_date_local datetime NULL default '{$default_date}'
84 84
 			";
85
-			$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
85
+			$wpdb->query($query); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
86 86
 		}
87 87
 		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
88 88
 	}
Please login to merge, or discard this patch.
src/ext/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php 2 patches
Indentation   +65 added lines, -65 removed lines patch added patch discarded remove patch
@@ -8,41 +8,41 @@  discard block
 block discarded – undo
8 8
  * Creates custom tables for storing scheduled actions
9 9
  */
10 10
 class ActionScheduler_StoreSchema extends ActionScheduler_Abstract_Schema {
11
-	const ACTIONS_TABLE = 'actionscheduler_actions';
12
-	const CLAIMS_TABLE  = 'actionscheduler_claims';
13
-	const GROUPS_TABLE  = 'actionscheduler_groups';
14
-	const DEFAULT_DATE  = '0000-00-00 00:00:00';
11
+    const ACTIONS_TABLE = 'actionscheduler_actions';
12
+    const CLAIMS_TABLE  = 'actionscheduler_claims';
13
+    const GROUPS_TABLE  = 'actionscheduler_groups';
14
+    const DEFAULT_DATE  = '0000-00-00 00:00:00';
15 15
 
16
-	/**
17
-	 * @var int Increment this value to trigger a schema update.
18
-	 */
19
-	protected $schema_version = 6;
16
+    /**
17
+     * @var int Increment this value to trigger a schema update.
18
+     */
19
+    protected $schema_version = 6;
20 20
 
21
-	public function __construct() {
22
-		$this->tables = array(
23
-			self::ACTIONS_TABLE,
24
-			self::CLAIMS_TABLE,
25
-			self::GROUPS_TABLE,
26
-		);
27
-	}
21
+    public function __construct() {
22
+        $this->tables = array(
23
+            self::ACTIONS_TABLE,
24
+            self::CLAIMS_TABLE,
25
+            self::GROUPS_TABLE,
26
+        );
27
+    }
28 28
 
29
-	/**
30
-	 * Performs additional setup work required to support this schema.
31
-	 */
32
-	public function init() {
33
-		add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_5_0' ), 10, 2 );
34
-	}
29
+    /**
30
+     * Performs additional setup work required to support this schema.
31
+     */
32
+    public function init() {
33
+        add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_5_0' ), 10, 2 );
34
+    }
35 35
 
36
-	protected function get_table_definition( $table ) {
37
-		global $wpdb;
38
-		$table_name       = $wpdb->$table;
39
-		$charset_collate  = $wpdb->get_charset_collate();
40
-		$max_index_length = 191; // @see wp_get_db_schema()
41
-		$default_date     = self::DEFAULT_DATE;
42
-		switch ( $table ) {
36
+    protected function get_table_definition( $table ) {
37
+        global $wpdb;
38
+        $table_name       = $wpdb->$table;
39
+        $charset_collate  = $wpdb->get_charset_collate();
40
+        $max_index_length = 191; // @see wp_get_db_schema()
41
+        $default_date     = self::DEFAULT_DATE;
42
+        switch ( $table ) {
43 43
 
44
-			case self::ACTIONS_TABLE:
45
-				return "CREATE TABLE {$table_name} (
44
+            case self::ACTIONS_TABLE:
45
+                return "CREATE TABLE {$table_name} (
46 46
 				        action_id bigint(20) unsigned NOT NULL auto_increment,
47 47
 				        hook varchar(191) NOT NULL,
48 48
 				        status varchar(20) NOT NULL,
@@ -66,61 +66,61 @@  discard block
 block discarded – undo
66 66
 				        KEY `claim_id_status_scheduled_date_gmt` (`claim_id`, `status`, `scheduled_date_gmt`)
67 67
 				        ) $charset_collate";
68 68
 
69
-			case self::CLAIMS_TABLE:
70
-				return "CREATE TABLE {$table_name} (
69
+            case self::CLAIMS_TABLE:
70
+                return "CREATE TABLE {$table_name} (
71 71
 				        claim_id bigint(20) unsigned NOT NULL auto_increment,
72 72
 				        date_created_gmt datetime NULL default '${default_date}',
73 73
 				        PRIMARY KEY  (claim_id),
74 74
 				        KEY date_created_gmt (date_created_gmt)
75 75
 				        ) $charset_collate";
76 76
 
77
-			case self::GROUPS_TABLE:
78
-				return "CREATE TABLE {$table_name} (
77
+            case self::GROUPS_TABLE:
78
+                return "CREATE TABLE {$table_name} (
79 79
 				        group_id bigint(20) unsigned NOT NULL auto_increment,
80 80
 				        slug varchar(255) NOT NULL,
81 81
 				        PRIMARY KEY  (group_id),
82 82
 				        KEY slug (slug($max_index_length))
83 83
 				        ) $charset_collate";
84 84
 
85
-			default:
86
-				return '';
87
-		}
88
-	}
85
+            default:
86
+                return '';
87
+        }
88
+    }
89 89
 
90
-	/**
91
-	 * Update the actions table schema, allowing datetime fields to be NULL.
92
-	 *
93
-	 * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
94
-	 * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
95
-	 *
96
-	 * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
97
-	 * that method relies on dbDelta() and this change is not possible when using that function.
98
-	 *
99
-	 * @param string $table Name of table being updated.
100
-	 * @param string $db_version The existing schema version of the table.
101
-	 */
102
-	public function update_schema_5_0( $table, $db_version ) {
103
-		global $wpdb;
90
+    /**
91
+     * Update the actions table schema, allowing datetime fields to be NULL.
92
+     *
93
+     * This is needed because the NOT NULL constraint causes a conflict with some versions of MySQL
94
+     * configured with sql_mode=NO_ZERO_DATE, which can for instance lead to tables not being created.
95
+     *
96
+     * Most other schema updates happen via ActionScheduler_Abstract_Schema::update_table(), however
97
+     * that method relies on dbDelta() and this change is not possible when using that function.
98
+     *
99
+     * @param string $table Name of table being updated.
100
+     * @param string $db_version The existing schema version of the table.
101
+     */
102
+    public function update_schema_5_0( $table, $db_version ) {
103
+        global $wpdb;
104 104
 
105
-		if ( 'actionscheduler_actions' !== $table || version_compare( $db_version, '5', '>=' ) ) {
106
-			return;
107
-		}
105
+        if ( 'actionscheduler_actions' !== $table || version_compare( $db_version, '5', '>=' ) ) {
106
+            return;
107
+        }
108 108
 
109
-		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
110
-		$table_name   = $wpdb->prefix . 'actionscheduler_actions';
111
-		$table_list   = $wpdb->get_col( "SHOW TABLES LIKE '${table_name}'" );
112
-		$default_date = self::DEFAULT_DATE;
109
+        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
110
+        $table_name   = $wpdb->prefix . 'actionscheduler_actions';
111
+        $table_list   = $wpdb->get_col( "SHOW TABLES LIKE '${table_name}'" );
112
+        $default_date = self::DEFAULT_DATE;
113 113
 
114
-		if ( ! empty( $table_list ) ) {
115
-			$query = "
114
+        if ( ! empty( $table_list ) ) {
115
+            $query = "
116 116
 				ALTER TABLE ${table_name}
117 117
 				MODIFY COLUMN scheduled_date_gmt datetime NULL default '${default_date}',
118 118
 				MODIFY COLUMN scheduled_date_local datetime NULL default '${default_date}',
119 119
 				MODIFY COLUMN last_attempt_gmt datetime NULL default '${default_date}',
120 120
 				MODIFY COLUMN last_attempt_local datetime NULL default '${default_date}'
121 121
 		";
122
-			$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
123
-		}
124
-		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
125
-	}
122
+            $wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
123
+        }
124
+        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
125
+    }
126 126
 }
Please login to merge, or discard this patch.
Spacing   +9 added lines, -9 removed lines patch added patch discarded remove patch
@@ -30,16 +30,16 @@  discard block
 block discarded – undo
30 30
 	 * Performs additional setup work required to support this schema.
31 31
 	 */
32 32
 	public function init() {
33
-		add_action( 'action_scheduler_before_schema_update', array( $this, 'update_schema_5_0' ), 10, 2 );
33
+		add_action('action_scheduler_before_schema_update', array($this, 'update_schema_5_0'), 10, 2);
34 34
 	}
35 35
 
36
-	protected function get_table_definition( $table ) {
36
+	protected function get_table_definition($table) {
37 37
 		global $wpdb;
38 38
 		$table_name       = $wpdb->$table;
39 39
 		$charset_collate  = $wpdb->get_charset_collate();
40 40
 		$max_index_length = 191; // @see wp_get_db_schema()
41 41
 		$default_date     = self::DEFAULT_DATE;
42
-		switch ( $table ) {
42
+		switch ($table) {
43 43
 
44 44
 			case self::ACTIONS_TABLE:
45 45
 				return "CREATE TABLE {$table_name} (
@@ -99,19 +99,19 @@  discard block
 block discarded – undo
99 99
 	 * @param string $table Name of table being updated.
100 100
 	 * @param string $db_version The existing schema version of the table.
101 101
 	 */
102
-	public function update_schema_5_0( $table, $db_version ) {
102
+	public function update_schema_5_0($table, $db_version) {
103 103
 		global $wpdb;
104 104
 
105
-		if ( 'actionscheduler_actions' !== $table || version_compare( $db_version, '5', '>=' ) ) {
105
+		if ('actionscheduler_actions' !== $table || version_compare($db_version, '5', '>=')) {
106 106
 			return;
107 107
 		}
108 108
 
109 109
 		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
110
-		$table_name   = $wpdb->prefix . 'actionscheduler_actions';
111
-		$table_list   = $wpdb->get_col( "SHOW TABLES LIKE '${table_name}'" );
110
+		$table_name   = $wpdb->prefix.'actionscheduler_actions';
111
+		$table_list   = $wpdb->get_col("SHOW TABLES LIKE '${table_name}'");
112 112
 		$default_date = self::DEFAULT_DATE;
113 113
 
114
-		if ( ! empty( $table_list ) ) {
114
+		if ( ! empty($table_list)) {
115 115
 			$query = "
116 116
 				ALTER TABLE ${table_name}
117 117
 				MODIFY COLUMN scheduled_date_gmt datetime NULL default '${default_date}',
@@ -119,7 +119,7 @@  discard block
 block discarded – undo
119 119
 				MODIFY COLUMN last_attempt_gmt datetime NULL default '${default_date}',
120 120
 				MODIFY COLUMN last_attempt_local datetime NULL default '${default_date}'
121 121
 		";
122
-			$wpdb->query( $query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
122
+			$wpdb->query($query); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
123 123
 		}
124 124
 		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
125 125
 	}
Please login to merge, or discard this patch.
src/ext/action-scheduler/classes/ActionScheduler_Compatibility.php 2 patches
Indentation   +87 added lines, -87 removed lines patch added patch discarded remove patch
@@ -5,105 +5,105 @@
 block discarded – undo
5 5
  */
6 6
 class ActionScheduler_Compatibility {
7 7
 
8
-	/**
9
-	 * Converts a shorthand byte value to an integer byte value.
10
-	 *
11
-	 * Wrapper for wp_convert_hr_to_bytes(), moved to load.php in WordPress 4.6 from media.php
12
-	 *
13
-	 * @link https://secure.php.net/manual/en/function.ini-get.php
14
-	 * @link https://secure.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
15
-	 *
16
-	 * @param string $value A (PHP ini) byte value, either shorthand or ordinary.
17
-	 * @return int An integer byte value.
18
-	 */
19
-	public static function convert_hr_to_bytes( $value ) {
20
-		if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
21
-			return wp_convert_hr_to_bytes( $value );
22
-		}
8
+    /**
9
+     * Converts a shorthand byte value to an integer byte value.
10
+     *
11
+     * Wrapper for wp_convert_hr_to_bytes(), moved to load.php in WordPress 4.6 from media.php
12
+     *
13
+     * @link https://secure.php.net/manual/en/function.ini-get.php
14
+     * @link https://secure.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
15
+     *
16
+     * @param string $value A (PHP ini) byte value, either shorthand or ordinary.
17
+     * @return int An integer byte value.
18
+     */
19
+    public static function convert_hr_to_bytes( $value ) {
20
+        if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
21
+            return wp_convert_hr_to_bytes( $value );
22
+        }
23 23
 
24
-		$value = strtolower( trim( $value ) );
25
-		$bytes = (int) $value;
24
+        $value = strtolower( trim( $value ) );
25
+        $bytes = (int) $value;
26 26
 
27
-		if ( false !== strpos( $value, 'g' ) ) {
28
-			$bytes *= GB_IN_BYTES;
29
-		} elseif ( false !== strpos( $value, 'm' ) ) {
30
-			$bytes *= MB_IN_BYTES;
31
-		} elseif ( false !== strpos( $value, 'k' ) ) {
32
-			$bytes *= KB_IN_BYTES;
33
-		}
27
+        if ( false !== strpos( $value, 'g' ) ) {
28
+            $bytes *= GB_IN_BYTES;
29
+        } elseif ( false !== strpos( $value, 'm' ) ) {
30
+            $bytes *= MB_IN_BYTES;
31
+        } elseif ( false !== strpos( $value, 'k' ) ) {
32
+            $bytes *= KB_IN_BYTES;
33
+        }
34 34
 
35
-		// Deal with large (float) values which run into the maximum integer size.
36
-		return min( $bytes, PHP_INT_MAX );
37
-	}
35
+        // Deal with large (float) values which run into the maximum integer size.
36
+        return min( $bytes, PHP_INT_MAX );
37
+    }
38 38
 
39
-	/**
40
-	 * Attempts to raise the PHP memory limit for memory intensive processes.
41
-	 *
42
-	 * Only allows raising the existing limit and prevents lowering it.
43
-	 *
44
-	 * Wrapper for wp_raise_memory_limit(), added in WordPress v4.6.0
45
-	 *
46
-	 * @return bool|int|string The limit that was set or false on failure.
47
-	 */
48
-	public static function raise_memory_limit() {
49
-		if ( function_exists( 'wp_raise_memory_limit' ) ) {
50
-			return wp_raise_memory_limit( 'admin' );
51
-		}
39
+    /**
40
+     * Attempts to raise the PHP memory limit for memory intensive processes.
41
+     *
42
+     * Only allows raising the existing limit and prevents lowering it.
43
+     *
44
+     * Wrapper for wp_raise_memory_limit(), added in WordPress v4.6.0
45
+     *
46
+     * @return bool|int|string The limit that was set or false on failure.
47
+     */
48
+    public static function raise_memory_limit() {
49
+        if ( function_exists( 'wp_raise_memory_limit' ) ) {
50
+            return wp_raise_memory_limit( 'admin' );
51
+        }
52 52
 
53
-		$current_limit     = @ini_get( 'memory_limit' );
54
-		$current_limit_int = self::convert_hr_to_bytes( $current_limit );
53
+        $current_limit     = @ini_get( 'memory_limit' );
54
+        $current_limit_int = self::convert_hr_to_bytes( $current_limit );
55 55
 
56
-		if ( -1 === $current_limit_int ) {
57
-			return false;
58
-		}
56
+        if ( -1 === $current_limit_int ) {
57
+            return false;
58
+        }
59 59
 
60
-		$wp_max_limit       = WP_MAX_MEMORY_LIMIT;
61
-		$wp_max_limit_int   = self::convert_hr_to_bytes( $wp_max_limit );
62
-		$filtered_limit     = apply_filters( 'admin_memory_limit', $wp_max_limit );
63
-		$filtered_limit_int = self::convert_hr_to_bytes( $filtered_limit );
60
+        $wp_max_limit       = WP_MAX_MEMORY_LIMIT;
61
+        $wp_max_limit_int   = self::convert_hr_to_bytes( $wp_max_limit );
62
+        $filtered_limit     = apply_filters( 'admin_memory_limit', $wp_max_limit );
63
+        $filtered_limit_int = self::convert_hr_to_bytes( $filtered_limit );
64 64
 
65
-		if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
66
-			if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
67
-				return $filtered_limit;
68
-			} else {
69
-				return false;
70
-			}
71
-		} elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
72
-			if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
73
-				return $wp_max_limit;
74
-			} else {
75
-				return false;
76
-			}
77
-		}
78
-		return false;
79
-	}
65
+        if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
66
+            if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
67
+                return $filtered_limit;
68
+            } else {
69
+                return false;
70
+            }
71
+        } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
72
+            if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
73
+                return $wp_max_limit;
74
+            } else {
75
+                return false;
76
+            }
77
+        }
78
+        return false;
79
+    }
80 80
 
81
-	/**
82
-	 * Attempts to raise the PHP timeout for time intensive processes.
83
-	 *
84
-	 * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
85
-	 *
86
-	 * @param int $limit The time limit in seconds.
87
-	 */
88
-	public static function raise_time_limit( $limit = 0 ) {
89
-		$limit              = (int) $limit;
90
-		$max_execution_time = (int) ini_get( 'max_execution_time' );
81
+    /**
82
+     * Attempts to raise the PHP timeout for time intensive processes.
83
+     *
84
+     * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
85
+     *
86
+     * @param int $limit The time limit in seconds.
87
+     */
88
+    public static function raise_time_limit( $limit = 0 ) {
89
+        $limit              = (int) $limit;
90
+        $max_execution_time = (int) ini_get( 'max_execution_time' );
91 91
 
92
-		/*
92
+        /*
93 93
 		 * If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed
94 94
 		 * limit, there is no reason for us to make further changes (we never want to lower it).
95 95
 		 */
96
-		if (
97
-			0 === $max_execution_time
98
-			|| ( $max_execution_time >= $limit && $limit !== 0 )
99
-		) {
100
-			return;
101
-		}
96
+        if (
97
+            0 === $max_execution_time
98
+            || ( $max_execution_time >= $limit && $limit !== 0 )
99
+        ) {
100
+            return;
101
+        }
102 102
 
103
-		if ( function_exists( 'wc_set_time_limit' ) ) {
104
-			wc_set_time_limit( $limit );
105
-		} elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
106
-			@set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
107
-		}
108
-	}
103
+        if ( function_exists( 'wc_set_time_limit' ) ) {
104
+            wc_set_time_limit( $limit );
105
+        } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
106
+            @set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
107
+        }
108
+    }
109 109
 }
Please login to merge, or discard this patch.
Spacing   +25 added lines, -25 removed lines patch added patch discarded remove patch
@@ -16,24 +16,24 @@  discard block
 block discarded – undo
16 16
 	 * @param string $value A (PHP ini) byte value, either shorthand or ordinary.
17 17
 	 * @return int An integer byte value.
18 18
 	 */
19
-	public static function convert_hr_to_bytes( $value ) {
20
-		if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
21
-			return wp_convert_hr_to_bytes( $value );
19
+	public static function convert_hr_to_bytes($value) {
20
+		if (function_exists('wp_convert_hr_to_bytes')) {
21
+			return wp_convert_hr_to_bytes($value);
22 22
 		}
23 23
 
24
-		$value = strtolower( trim( $value ) );
24
+		$value = strtolower(trim($value));
25 25
 		$bytes = (int) $value;
26 26
 
27
-		if ( false !== strpos( $value, 'g' ) ) {
27
+		if (false !== strpos($value, 'g')) {
28 28
 			$bytes *= GB_IN_BYTES;
29
-		} elseif ( false !== strpos( $value, 'm' ) ) {
29
+		} elseif (false !== strpos($value, 'm')) {
30 30
 			$bytes *= MB_IN_BYTES;
31
-		} elseif ( false !== strpos( $value, 'k' ) ) {
31
+		} elseif (false !== strpos($value, 'k')) {
32 32
 			$bytes *= KB_IN_BYTES;
33 33
 		}
34 34
 
35 35
 		// Deal with large (float) values which run into the maximum integer size.
36
-		return min( $bytes, PHP_INT_MAX );
36
+		return min($bytes, PHP_INT_MAX);
37 37
 	}
38 38
 
39 39
 	/**
@@ -46,30 +46,30 @@  discard block
 block discarded – undo
46 46
 	 * @return bool|int|string The limit that was set or false on failure.
47 47
 	 */
48 48
 	public static function raise_memory_limit() {
49
-		if ( function_exists( 'wp_raise_memory_limit' ) ) {
50
-			return wp_raise_memory_limit( 'admin' );
49
+		if (function_exists('wp_raise_memory_limit')) {
50
+			return wp_raise_memory_limit('admin');
51 51
 		}
52 52
 
53
-		$current_limit     = @ini_get( 'memory_limit' );
54
-		$current_limit_int = self::convert_hr_to_bytes( $current_limit );
53
+		$current_limit     = @ini_get('memory_limit');
54
+		$current_limit_int = self::convert_hr_to_bytes($current_limit);
55 55
 
56 56
 		if ( -1 === $current_limit_int ) {
57 57
 			return false;
58 58
 		}
59 59
 
60 60
 		$wp_max_limit       = WP_MAX_MEMORY_LIMIT;
61
-		$wp_max_limit_int   = self::convert_hr_to_bytes( $wp_max_limit );
62
-		$filtered_limit     = apply_filters( 'admin_memory_limit', $wp_max_limit );
63
-		$filtered_limit_int = self::convert_hr_to_bytes( $filtered_limit );
61
+		$wp_max_limit_int   = self::convert_hr_to_bytes($wp_max_limit);
62
+		$filtered_limit     = apply_filters('admin_memory_limit', $wp_max_limit);
63
+		$filtered_limit_int = self::convert_hr_to_bytes($filtered_limit);
64 64
 
65
-		if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
66
-			if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
65
+		if ( -1 === $filtered_limit_int || ($filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int) ) {
66
+			if (false !== @ini_set('memory_limit', $filtered_limit)) {
67 67
 				return $filtered_limit;
68 68
 			} else {
69 69
 				return false;
70 70
 			}
71 71
 		} elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
72
-			if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
72
+			if (false !== @ini_set('memory_limit', $wp_max_limit)) {
73 73
 				return $wp_max_limit;
74 74
 			} else {
75 75
 				return false;
@@ -85,9 +85,9 @@  discard block
 block discarded – undo
85 85
 	 *
86 86
 	 * @param int $limit The time limit in seconds.
87 87
 	 */
88
-	public static function raise_time_limit( $limit = 0 ) {
88
+	public static function raise_time_limit($limit = 0) {
89 89
 		$limit              = (int) $limit;
90
-		$max_execution_time = (int) ini_get( 'max_execution_time' );
90
+		$max_execution_time = (int) ini_get('max_execution_time');
91 91
 
92 92
 		/*
93 93
 		 * If the max execution time is already unlimited (zero), or if it exceeds or is equal to the proposed
@@ -95,15 +95,15 @@  discard block
 block discarded – undo
95 95
 		 */
96 96
 		if (
97 97
 			0 === $max_execution_time
98
-			|| ( $max_execution_time >= $limit && $limit !== 0 )
98
+			|| ($max_execution_time >= $limit && $limit !== 0)
99 99
 		) {
100 100
 			return;
101 101
 		}
102 102
 
103
-		if ( function_exists( 'wc_set_time_limit' ) ) {
104
-			wc_set_time_limit( $limit );
105
-		} elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
106
-			@set_time_limit( $limit ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
103
+		if (function_exists('wc_set_time_limit')) {
104
+			wc_set_time_limit($limit);
105
+		} elseif (function_exists('set_time_limit') && false === strpos(ini_get('disable_functions'), 'set_time_limit') && ! ini_get('safe_mode')) { // phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
106
+			@set_time_limit($limit); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
107 107
 		}
108 108
 	}
109 109
 }
Please login to merge, or discard this patch.
src/ext/action-scheduler/classes/ActionScheduler_QueueRunner.php 2 patches
Indentation   +207 added lines, -207 removed lines patch added patch discarded remove patch
@@ -4,214 +4,214 @@
 block discarded – undo
4 4
  * Class ActionScheduler_QueueRunner
5 5
  */
6 6
 class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
7
-	const WP_CRON_HOOK = 'action_scheduler_run_queue';
8
-
9
-	const WP_CRON_SCHEDULE = 'every_minute';
10
-
11
-	/** @var ActionScheduler_AsyncRequest_QueueRunner */
12
-	protected $async_request;
13
-
14
-	/** @var ActionScheduler_QueueRunner  */
15
-	private static $runner = null;
16
-
17
-	/**
18
-	 * @return ActionScheduler_QueueRunner
19
-	 * @codeCoverageIgnore
20
-	 */
21
-	public static function instance() {
22
-		if ( empty( self::$runner ) ) {
23
-			$class        = apply_filters( 'action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner' );
24
-			self::$runner = new $class();
25
-		}
26
-		return self::$runner;
27
-	}
28
-
29
-	/**
30
-	 * ActionScheduler_QueueRunner constructor.
31
-	 *
32
-	 * @param ActionScheduler_Store             $store
33
-	 * @param ActionScheduler_FatalErrorMonitor $monitor
34
-	 * @param ActionScheduler_QueueCleaner      $cleaner
35
-	 */
36
-	public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) {
37
-		parent::__construct( $store, $monitor, $cleaner );
38
-
39
-		if ( $async_request === null ) {
40
-			$async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
41
-		}
42
-
43
-		$this->async_request = $async_request;
44
-	}
45
-
46
-	/**
47
-	 * @codeCoverageIgnore
48
-	 */
49
-	public function init() {
50
-
51
-		add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
52
-
53
-		// Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
54
-		$next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
55
-		if ( $next_timestamp ) {
56
-			wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
57
-		}
58
-
59
-		$cron_context = array( 'WP Cron' );
60
-
61
-		if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
62
-			$schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
63
-			wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
64
-		}
65
-
66
-		add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
67
-		$this->hook_dispatch_async_request();
68
-	}
69
-
70
-	/**
71
-	 * Hook check for dispatching an async request.
72
-	 */
73
-	public function hook_dispatch_async_request() {
74
-		add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
75
-	}
76
-
77
-	/**
78
-	 * Unhook check for dispatching an async request.
79
-	 */
80
-	public function unhook_dispatch_async_request() {
81
-		remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
82
-	}
83
-
84
-	/**
85
-	 * Check if we should dispatch an async request to process actions.
86
-	 *
87
-	 * This method is attached to 'shutdown', so is called frequently. To avoid slowing down
88
-	 * the site, it mitigates the work performed in each request by:
89
-	 * 1. checking if it's in the admin context and then
90
-	 * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
91
-	 * 3. haven't exceeded the number of allowed batches.
92
-	 *
93
-	 * The order of these checks is important, because they run from a check on a value:
94
-	 * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
95
-	 * 2. in memory - transients use autoloaded options by default
96
-	 * 3. from a database query - has_maximum_concurrent_batches() run the query
97
-	 *    $this->store->get_claim_count() to find the current number of claims in the DB.
98
-	 *
99
-	 * If all of these conditions are met, then we request an async runner check whether it
100
-	 * should dispatch a request to process pending actions.
101
-	 */
102
-	public function maybe_dispatch_async_request() {
103
-		if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
104
-			// Only start an async queue at most once every 60 seconds
105
-			ActionScheduler::lock()->set( 'async-request-runner' );
106
-			$this->async_request->maybe_dispatch();
107
-		}
108
-	}
109
-
110
-	/**
111
-	 * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
112
-	 *
113
-	 * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
114
-	 * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
115
-	 * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
116
-	 * should set a context as the first parameter. For an example of this, refer to the code seen in
117
-	 *
118
-	 * @see ActionScheduler_AsyncRequest_QueueRunner::handle()
119
-	 *
120
-	 * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
121
-	 *        Generally, this should be capitalised and not localised as it's a proper noun.
122
-	 * @return int The number of actions processed.
123
-	 */
124
-	public function run( $context = 'WP Cron' ) {
125
-		ActionScheduler_Compatibility::raise_memory_limit();
126
-		ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
127
-		do_action( 'action_scheduler_before_process_queue' );
128
-		$this->run_cleanup();
129
-		$processed_actions = 0;
130
-		if ( false === $this->has_maximum_concurrent_batches() ) {
131
-			$batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
132
-			do {
133
-				$processed_actions_in_batch = $this->do_batch( $batch_size, $context );
134
-				$processed_actions         += $processed_actions_in_batch;
135
-			} while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
136
-		}
137
-
138
-		do_action( 'action_scheduler_after_process_queue' );
139
-		return $processed_actions;
140
-	}
141
-
142
-	/**
143
-	 * Process a batch of actions pending in the queue.
144
-	 *
145
-	 * Actions are processed by claiming a set of pending actions then processing each one until either the batch
146
-	 * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
147
-	 *
148
-	 * @param int    $size The maximum number of actions to process in the batch.
149
-	 * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
150
-	 *        Generally, this should be capitalised and not localised as it's a proper noun.
151
-	 * @return int The number of actions processed.
152
-	 */
153
-	protected function do_batch( $size = 100, $context = '' ) {
154
-		$claim = $this->store->stake_claim( $size );
155
-		$this->monitor->attach( $claim );
156
-		$processed_actions = 0;
157
-
158
-		foreach ( $claim->get_actions() as $action_id ) {
159
-			// bail if we lost the claim
160
-			if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
161
-				break;
162
-			}
163
-			$this->process_action( $action_id, $context );
164
-			$processed_actions++;
165
-
166
-			if ( $this->batch_limits_exceeded( $processed_actions ) ) {
167
-				break;
168
-			}
169
-		}
170
-		$this->store->release_claim( $claim );
171
-		$this->monitor->detach();
172
-		$this->clear_caches();
173
-		return $processed_actions;
174
-	}
175
-
176
-	/**
177
-	 * Flush the cache if possible (intended for use after a batch of actions has been processed).
178
-	 *
179
-	 * This is useful because running large batches can eat up memory and because invalid data can accrue in the
180
-	 * runtime cache, which may lead to unexpected results.
181
-	 */
182
-	protected function clear_caches() {
183
-		/*
7
+    const WP_CRON_HOOK = 'action_scheduler_run_queue';
8
+
9
+    const WP_CRON_SCHEDULE = 'every_minute';
10
+
11
+    /** @var ActionScheduler_AsyncRequest_QueueRunner */
12
+    protected $async_request;
13
+
14
+    /** @var ActionScheduler_QueueRunner  */
15
+    private static $runner = null;
16
+
17
+    /**
18
+     * @return ActionScheduler_QueueRunner
19
+     * @codeCoverageIgnore
20
+     */
21
+    public static function instance() {
22
+        if ( empty( self::$runner ) ) {
23
+            $class        = apply_filters( 'action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner' );
24
+            self::$runner = new $class();
25
+        }
26
+        return self::$runner;
27
+    }
28
+
29
+    /**
30
+     * ActionScheduler_QueueRunner constructor.
31
+     *
32
+     * @param ActionScheduler_Store             $store
33
+     * @param ActionScheduler_FatalErrorMonitor $monitor
34
+     * @param ActionScheduler_QueueCleaner      $cleaner
35
+     */
36
+    public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) {
37
+        parent::__construct( $store, $monitor, $cleaner );
38
+
39
+        if ( $async_request === null ) {
40
+            $async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
41
+        }
42
+
43
+        $this->async_request = $async_request;
44
+    }
45
+
46
+    /**
47
+     * @codeCoverageIgnore
48
+     */
49
+    public function init() {
50
+
51
+        add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
52
+
53
+        // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
54
+        $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
55
+        if ( $next_timestamp ) {
56
+            wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
57
+        }
58
+
59
+        $cron_context = array( 'WP Cron' );
60
+
61
+        if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
62
+            $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
63
+            wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
64
+        }
65
+
66
+        add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
67
+        $this->hook_dispatch_async_request();
68
+    }
69
+
70
+    /**
71
+     * Hook check for dispatching an async request.
72
+     */
73
+    public function hook_dispatch_async_request() {
74
+        add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
75
+    }
76
+
77
+    /**
78
+     * Unhook check for dispatching an async request.
79
+     */
80
+    public function unhook_dispatch_async_request() {
81
+        remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
82
+    }
83
+
84
+    /**
85
+     * Check if we should dispatch an async request to process actions.
86
+     *
87
+     * This method is attached to 'shutdown', so is called frequently. To avoid slowing down
88
+     * the site, it mitigates the work performed in each request by:
89
+     * 1. checking if it's in the admin context and then
90
+     * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
91
+     * 3. haven't exceeded the number of allowed batches.
92
+     *
93
+     * The order of these checks is important, because they run from a check on a value:
94
+     * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
95
+     * 2. in memory - transients use autoloaded options by default
96
+     * 3. from a database query - has_maximum_concurrent_batches() run the query
97
+     *    $this->store->get_claim_count() to find the current number of claims in the DB.
98
+     *
99
+     * If all of these conditions are met, then we request an async runner check whether it
100
+     * should dispatch a request to process pending actions.
101
+     */
102
+    public function maybe_dispatch_async_request() {
103
+        if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
104
+            // Only start an async queue at most once every 60 seconds
105
+            ActionScheduler::lock()->set( 'async-request-runner' );
106
+            $this->async_request->maybe_dispatch();
107
+        }
108
+    }
109
+
110
+    /**
111
+     * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
112
+     *
113
+     * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
114
+     * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
115
+     * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
116
+     * should set a context as the first parameter. For an example of this, refer to the code seen in
117
+     *
118
+     * @see ActionScheduler_AsyncRequest_QueueRunner::handle()
119
+     *
120
+     * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
121
+     *        Generally, this should be capitalised and not localised as it's a proper noun.
122
+     * @return int The number of actions processed.
123
+     */
124
+    public function run( $context = 'WP Cron' ) {
125
+        ActionScheduler_Compatibility::raise_memory_limit();
126
+        ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
127
+        do_action( 'action_scheduler_before_process_queue' );
128
+        $this->run_cleanup();
129
+        $processed_actions = 0;
130
+        if ( false === $this->has_maximum_concurrent_batches() ) {
131
+            $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
132
+            do {
133
+                $processed_actions_in_batch = $this->do_batch( $batch_size, $context );
134
+                $processed_actions         += $processed_actions_in_batch;
135
+            } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
136
+        }
137
+
138
+        do_action( 'action_scheduler_after_process_queue' );
139
+        return $processed_actions;
140
+    }
141
+
142
+    /**
143
+     * Process a batch of actions pending in the queue.
144
+     *
145
+     * Actions are processed by claiming a set of pending actions then processing each one until either the batch
146
+     * size is completed, or memory or time limits are reached, defined by @see $this->batch_limits_exceeded().
147
+     *
148
+     * @param int    $size The maximum number of actions to process in the batch.
149
+     * @param string $context Optional identifer for the context in which this action is being processed, e.g. 'WP CLI' or 'WP Cron'
150
+     *        Generally, this should be capitalised and not localised as it's a proper noun.
151
+     * @return int The number of actions processed.
152
+     */
153
+    protected function do_batch( $size = 100, $context = '' ) {
154
+        $claim = $this->store->stake_claim( $size );
155
+        $this->monitor->attach( $claim );
156
+        $processed_actions = 0;
157
+
158
+        foreach ( $claim->get_actions() as $action_id ) {
159
+            // bail if we lost the claim
160
+            if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
161
+                break;
162
+            }
163
+            $this->process_action( $action_id, $context );
164
+            $processed_actions++;
165
+
166
+            if ( $this->batch_limits_exceeded( $processed_actions ) ) {
167
+                break;
168
+            }
169
+        }
170
+        $this->store->release_claim( $claim );
171
+        $this->monitor->detach();
172
+        $this->clear_caches();
173
+        return $processed_actions;
174
+    }
175
+
176
+    /**
177
+     * Flush the cache if possible (intended for use after a batch of actions has been processed).
178
+     *
179
+     * This is useful because running large batches can eat up memory and because invalid data can accrue in the
180
+     * runtime cache, which may lead to unexpected results.
181
+     */
182
+    protected function clear_caches() {
183
+        /*
184 184
 		 * Calling wp_cache_flush_runtime() lets us clear the runtime cache without invalidating the external object
185 185
 		 * cache, so we will always prefer this when it is available (but it was only introduced in WordPress 6.0).
186 186
 		 */
187
-		if ( function_exists( 'wp_cache_flush_runtime' ) ) {
188
-			wp_cache_flush_runtime();
189
-		} elseif (
190
-			! wp_using_ext_object_cache()
191
-			/**
192
-			 * When an external object cache is in use, and when wp_cache_flush_runtime() is not available, then
193
-			 * normally the cache will not be flushed after processing a batch of actions (to avoid a performance
194
-			 * penalty for other processes).
195
-			 *
196
-			 * This filter makes it possible to override this behavior and always flush the cache, even if an external
197
-			 * object cache is in use.
198
-			 *
199
-			 * @since 1.0
200
-			 *
201
-			 * @param bool $flush_cache If the cache should be flushed.
202
-			 */
203
-			|| apply_filters( 'action_scheduler_queue_runner_flush_cache', false )
204
-		) {
205
-			wp_cache_flush();
206
-		}
207
-	}
208
-
209
-	public function add_wp_cron_schedule( $schedules ) {
210
-		$schedules['every_minute'] = array(
211
-			'interval' => 60, // in seconds
212
-			'display'  => __( 'Every minute', 'action-scheduler' ),
213
-		);
214
-
215
-		return $schedules;
216
-	}
187
+        if ( function_exists( 'wp_cache_flush_runtime' ) ) {
188
+            wp_cache_flush_runtime();
189
+        } elseif (
190
+            ! wp_using_ext_object_cache()
191
+            /**
192
+             * When an external object cache is in use, and when wp_cache_flush_runtime() is not available, then
193
+             * normally the cache will not be flushed after processing a batch of actions (to avoid a performance
194
+             * penalty for other processes).
195
+             *
196
+             * This filter makes it possible to override this behavior and always flush the cache, even if an external
197
+             * object cache is in use.
198
+             *
199
+             * @since 1.0
200
+             *
201
+             * @param bool $flush_cache If the cache should be flushed.
202
+             */
203
+            || apply_filters( 'action_scheduler_queue_runner_flush_cache', false )
204
+        ) {
205
+            wp_cache_flush();
206
+        }
207
+    }
208
+
209
+    public function add_wp_cron_schedule( $schedules ) {
210
+        $schedules['every_minute'] = array(
211
+            'interval' => 60, // in seconds
212
+            'display'  => __( 'Every minute', 'action-scheduler' ),
213
+        );
214
+
215
+        return $schedules;
216
+    }
217 217
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -19,8 +19,8 @@  discard block
 block discarded – undo
19 19
 	 * @codeCoverageIgnore
20 20
 	 */
21 21
 	public static function instance() {
22
-		if ( empty( self::$runner ) ) {
23
-			$class        = apply_filters( 'action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner' );
22
+		if (empty(self::$runner)) {
23
+			$class        = apply_filters('action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner');
24 24
 			self::$runner = new $class();
25 25
 		}
26 26
 		return self::$runner;
@@ -33,11 +33,11 @@  discard block
 block discarded – undo
33 33
 	 * @param ActionScheduler_FatalErrorMonitor $monitor
34 34
 	 * @param ActionScheduler_QueueCleaner      $cleaner
35 35
 	 */
36
-	public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null ) {
37
-		parent::__construct( $store, $monitor, $cleaner );
36
+	public function __construct(ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null, ActionScheduler_AsyncRequest_QueueRunner $async_request = null) {
37
+		parent::__construct($store, $monitor, $cleaner);
38 38
 
39
-		if ( $async_request === null ) {
40
-			$async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
39
+		if ($async_request === null) {
40
+			$async_request = new ActionScheduler_AsyncRequest_QueueRunner($this->store);
41 41
 		}
42 42
 
43 43
 		$this->async_request = $async_request;
@@ -48,22 +48,22 @@  discard block
 block discarded – undo
48 48
 	 */
49 49
 	public function init() {
50 50
 
51
-		add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
51
+		add_filter('cron_schedules', array(self::instance(), 'add_wp_cron_schedule'));
52 52
 
53 53
 		// Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
54
-		$next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
55
-		if ( $next_timestamp ) {
56
-			wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
54
+		$next_timestamp = wp_next_scheduled(self::WP_CRON_HOOK);
55
+		if ($next_timestamp) {
56
+			wp_unschedule_event($next_timestamp, self::WP_CRON_HOOK);
57 57
 		}
58 58
 
59
-		$cron_context = array( 'WP Cron' );
59
+		$cron_context = array('WP Cron');
60 60
 
61
-		if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
62
-			$schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
63
-			wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
61
+		if ( ! wp_next_scheduled(self::WP_CRON_HOOK, $cron_context)) {
62
+			$schedule = apply_filters('action_scheduler_run_schedule', self::WP_CRON_SCHEDULE);
63
+			wp_schedule_event(time(), $schedule, self::WP_CRON_HOOK, $cron_context);
64 64
 		}
65 65
 
66
-		add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
66
+		add_action(self::WP_CRON_HOOK, array(self::instance(), 'run'));
67 67
 		$this->hook_dispatch_async_request();
68 68
 	}
69 69
 
@@ -71,14 +71,14 @@  discard block
 block discarded – undo
71 71
 	 * Hook check for dispatching an async request.
72 72
 	 */
73 73
 	public function hook_dispatch_async_request() {
74
-		add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
74
+		add_action('shutdown', array($this, 'maybe_dispatch_async_request'));
75 75
 	}
76 76
 
77 77
 	/**
78 78
 	 * Unhook check for dispatching an async request.
79 79
 	 */
80 80
 	public function unhook_dispatch_async_request() {
81
-		remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
81
+		remove_action('shutdown', array($this, 'maybe_dispatch_async_request'));
82 82
 	}
83 83
 
84 84
 	/**
@@ -100,9 +100,9 @@  discard block
 block discarded – undo
100 100
 	 * should dispatch a request to process pending actions.
101 101
 	 */
102 102
 	public function maybe_dispatch_async_request() {
103
-		if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
103
+		if (is_admin() && ! ActionScheduler::lock()->is_locked('async-request-runner')) {
104 104
 			// Only start an async queue at most once every 60 seconds
105
-			ActionScheduler::lock()->set( 'async-request-runner' );
105
+			ActionScheduler::lock()->set('async-request-runner');
106 106
 			$this->async_request->maybe_dispatch();
107 107
 		}
108 108
 	}
@@ -121,21 +121,21 @@  discard block
 block discarded – undo
121 121
 	 *        Generally, this should be capitalised and not localised as it's a proper noun.
122 122
 	 * @return int The number of actions processed.
123 123
 	 */
124
-	public function run( $context = 'WP Cron' ) {
124
+	public function run($context = 'WP Cron') {
125 125
 		ActionScheduler_Compatibility::raise_memory_limit();
126
-		ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
127
-		do_action( 'action_scheduler_before_process_queue' );
126
+		ActionScheduler_Compatibility::raise_time_limit($this->get_time_limit());
127
+		do_action('action_scheduler_before_process_queue');
128 128
 		$this->run_cleanup();
129 129
 		$processed_actions = 0;
130
-		if ( false === $this->has_maximum_concurrent_batches() ) {
131
-			$batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
130
+		if (false === $this->has_maximum_concurrent_batches()) {
131
+			$batch_size = apply_filters('action_scheduler_queue_runner_batch_size', 25);
132 132
 			do {
133
-				$processed_actions_in_batch = $this->do_batch( $batch_size, $context );
133
+				$processed_actions_in_batch = $this->do_batch($batch_size, $context);
134 134
 				$processed_actions         += $processed_actions_in_batch;
135
-			} while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
135
+			} while ($processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded($processed_actions)); // keep going until we run out of actions, time, or memory
136 136
 		}
137 137
 
138
-		do_action( 'action_scheduler_after_process_queue' );
138
+		do_action('action_scheduler_after_process_queue');
139 139
 		return $processed_actions;
140 140
 	}
141 141
 
@@ -150,24 +150,24 @@  discard block
 block discarded – undo
150 150
 	 *        Generally, this should be capitalised and not localised as it's a proper noun.
151 151
 	 * @return int The number of actions processed.
152 152
 	 */
153
-	protected function do_batch( $size = 100, $context = '' ) {
154
-		$claim = $this->store->stake_claim( $size );
155
-		$this->monitor->attach( $claim );
153
+	protected function do_batch($size = 100, $context = '') {
154
+		$claim = $this->store->stake_claim($size);
155
+		$this->monitor->attach($claim);
156 156
 		$processed_actions = 0;
157 157
 
158
-		foreach ( $claim->get_actions() as $action_id ) {
158
+		foreach ($claim->get_actions() as $action_id) {
159 159
 			// bail if we lost the claim
160
-			if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
160
+			if ( ! in_array($action_id, $this->store->find_actions_by_claim_id($claim->get_id()))) {
161 161
 				break;
162 162
 			}
163
-			$this->process_action( $action_id, $context );
163
+			$this->process_action($action_id, $context);
164 164
 			$processed_actions++;
165 165
 
166
-			if ( $this->batch_limits_exceeded( $processed_actions ) ) {
166
+			if ($this->batch_limits_exceeded($processed_actions)) {
167 167
 				break;
168 168
 			}
169 169
 		}
170
-		$this->store->release_claim( $claim );
170
+		$this->store->release_claim($claim);
171 171
 		$this->monitor->detach();
172 172
 		$this->clear_caches();
173 173
 		return $processed_actions;
@@ -184,7 +184,7 @@  discard block
 block discarded – undo
184 184
 		 * Calling wp_cache_flush_runtime() lets us clear the runtime cache without invalidating the external object
185 185
 		 * cache, so we will always prefer this when it is available (but it was only introduced in WordPress 6.0).
186 186
 		 */
187
-		if ( function_exists( 'wp_cache_flush_runtime' ) ) {
187
+		if (function_exists('wp_cache_flush_runtime')) {
188 188
 			wp_cache_flush_runtime();
189 189
 		} elseif (
190 190
 			! wp_using_ext_object_cache()
@@ -200,16 +200,16 @@  discard block
 block discarded – undo
200 200
 			 *
201 201
 			 * @param bool $flush_cache If the cache should be flushed.
202 202
 			 */
203
-			|| apply_filters( 'action_scheduler_queue_runner_flush_cache', false )
203
+			|| apply_filters('action_scheduler_queue_runner_flush_cache', false)
204 204
 		) {
205 205
 			wp_cache_flush();
206 206
 		}
207 207
 	}
208 208
 
209
-	public function add_wp_cron_schedule( $schedules ) {
209
+	public function add_wp_cron_schedule($schedules) {
210 210
 		$schedules['every_minute'] = array(
211 211
 			'interval' => 60, // in seconds
212
-			'display'  => __( 'Every minute', 'action-scheduler' ),
212
+			'display'  => __('Every minute', 'action-scheduler'),
213 213
 		);
214 214
 
215 215
 		return $schedules;
Please login to merge, or discard this patch.
src/ext/action-scheduler/classes/data-stores/ActionScheduler_DBStore.php 2 patches
Indentation   +1043 added lines, -1043 removed lines patch added patch discarded remove patch
@@ -9,1055 +9,1055 @@
 block discarded – undo
9 9
  */
10 10
 class ActionScheduler_DBStore extends ActionScheduler_Store {
11 11
 
12
-	/**
13
-	 * Used to share information about the before_date property of claims internally.
14
-	 *
15
-	 * This is used in preference to passing the same information as a method param
16
-	 * for backwards-compatibility reasons.
17
-	 *
18
-	 * @var DateTime|null
19
-	 */
20
-	private $claim_before_date = null;
21
-
22
-	/** @var int */
23
-	protected static $max_args_length = 8000;
24
-
25
-	/** @var int */
26
-	protected static $max_index_length = 191;
27
-
28
-	/**
29
-	 * Initialize the data store
30
-	 *
31
-	 * @codeCoverageIgnore
32
-	 */
33
-	public function init() {
34
-		$table_maker = new ActionScheduler_StoreSchema();
35
-		$table_maker->init();
36
-		$table_maker->register_tables();
37
-	}
38
-
39
-	/**
40
-	 * Save an action, checks if this is a unique action before actually saving.
41
-	 *
42
-	 * @param ActionScheduler_Action $action         Action object.
43
-	 * @param \DateTime              $scheduled_date Optional schedule date. Default null.
44
-	 *
45
-	 * @return int                  Action ID.
46
-	 * @throws RuntimeException     Throws exception when saving the action fails.
47
-	 */
48
-	public function save_unique_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
49
-		return $this->save_action_to_db( $action, $scheduled_date, true );
50
-	}
51
-
52
-	/**
53
-	 * Save an action. Can save duplicate action as well, prefer using `save_unique_action` instead.
54
-	 *
55
-	 * @param ActionScheduler_Action $action Action object.
56
-	 * @param \DateTime              $scheduled_date Optional schedule date. Default null.
57
-	 *
58
-	 * @return int Action ID.
59
-	 * @throws RuntimeException     Throws exception when saving the action fails.
60
-	 */
61
-	public function save_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
62
-		return $this->save_action_to_db( $action, $scheduled_date, false );
63
-	}
64
-
65
-	/**
66
-	 * Save an action.
67
-	 *
68
-	 * @param ActionScheduler_Action $action Action object.
69
-	 * @param ?DateTime              $date Optional schedule date. Default null.
70
-	 * @param bool                   $unique Whether the action should be unique.
71
-	 *
72
-	 * @return int Action ID.
73
-	 * @throws RuntimeException     Throws exception when saving the action fails.
74
-	 */
75
-	private function save_action_to_db( ActionScheduler_Action $action, DateTime $date = null, $unique = false ) {
76
-		global $wpdb;
77
-
78
-		try {
79
-			$this->validate_action( $action );
80
-
81
-			$data = array(
82
-				'hook'                 => $action->get_hook(),
83
-				'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
84
-				'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
85
-				'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
86
-				'schedule'             => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
87
-				'group_id'             => $this->get_group_id( $action->get_group() ),
88
-			);
89
-
90
-			$args = wp_json_encode( $action->get_args() );
91
-			if ( strlen( $args ) <= static::$max_index_length ) {
92
-				$data['args'] = $args;
93
-			} else {
94
-				$data['args']          = $this->hash_args( $args );
95
-				$data['extended_args'] = $args;
96
-			}
97
-
98
-			$insert_sql = $this->build_insert_sql( $data, $unique );
99
-
100
-			// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $insert_sql should be already prepared.
101
-			$wpdb->query( $insert_sql );
102
-			$action_id = $wpdb->insert_id;
103
-
104
-			if ( is_wp_error( $action_id ) ) {
105
-				throw new \RuntimeException( $action_id->get_error_message() );
106
-			} elseif ( empty( $action_id ) ) {
107
-				if ( $unique ) {
108
-					return 0;
109
-				}
110
-				throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
111
-			}
112
-
113
-			do_action( 'action_scheduler_stored_action', $action_id );
114
-
115
-			return $action_id;
116
-		} catch ( \Exception $e ) {
117
-			/* translators: %s: error message */
118
-			throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
119
-		}
120
-	}
121
-
122
-	/**
123
-	 * Helper function to build insert query.
124
-	 *
125
-	 * @param array $data Row data for action.
126
-	 * @param bool  $unique Whether the action should be unique.
127
-	 *
128
-	 * @return string Insert query.
129
-	 */
130
-	private function build_insert_sql( array $data, $unique ) {
131
-		global $wpdb;
132
-		$columns      = array_keys( $data );
133
-		$values       = array_values( $data );
134
-		$placeholders = array_map( array( $this, 'get_placeholder_for_column' ), $columns );
135
-
136
-		$table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
137
-
138
-		$column_sql      = '`' . implode( '`, `', $columns ) . '`';
139
-		$placeholder_sql = implode( ', ', $placeholders );
140
-		$where_clause    = $this->build_where_clause_for_insert( $data, $table_name, $unique );
141
-		// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $column_sql and $where_clause are already prepared. $placeholder_sql is hardcoded.
142
-		$insert_query = $wpdb->prepare(
143
-			"
12
+    /**
13
+     * Used to share information about the before_date property of claims internally.
14
+     *
15
+     * This is used in preference to passing the same information as a method param
16
+     * for backwards-compatibility reasons.
17
+     *
18
+     * @var DateTime|null
19
+     */
20
+    private $claim_before_date = null;
21
+
22
+    /** @var int */
23
+    protected static $max_args_length = 8000;
24
+
25
+    /** @var int */
26
+    protected static $max_index_length = 191;
27
+
28
+    /**
29
+     * Initialize the data store
30
+     *
31
+     * @codeCoverageIgnore
32
+     */
33
+    public function init() {
34
+        $table_maker = new ActionScheduler_StoreSchema();
35
+        $table_maker->init();
36
+        $table_maker->register_tables();
37
+    }
38
+
39
+    /**
40
+     * Save an action, checks if this is a unique action before actually saving.
41
+     *
42
+     * @param ActionScheduler_Action $action         Action object.
43
+     * @param \DateTime              $scheduled_date Optional schedule date. Default null.
44
+     *
45
+     * @return int                  Action ID.
46
+     * @throws RuntimeException     Throws exception when saving the action fails.
47
+     */
48
+    public function save_unique_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
49
+        return $this->save_action_to_db( $action, $scheduled_date, true );
50
+    }
51
+
52
+    /**
53
+     * Save an action. Can save duplicate action as well, prefer using `save_unique_action` instead.
54
+     *
55
+     * @param ActionScheduler_Action $action Action object.
56
+     * @param \DateTime              $scheduled_date Optional schedule date. Default null.
57
+     *
58
+     * @return int Action ID.
59
+     * @throws RuntimeException     Throws exception when saving the action fails.
60
+     */
61
+    public function save_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
62
+        return $this->save_action_to_db( $action, $scheduled_date, false );
63
+    }
64
+
65
+    /**
66
+     * Save an action.
67
+     *
68
+     * @param ActionScheduler_Action $action Action object.
69
+     * @param ?DateTime              $date Optional schedule date. Default null.
70
+     * @param bool                   $unique Whether the action should be unique.
71
+     *
72
+     * @return int Action ID.
73
+     * @throws RuntimeException     Throws exception when saving the action fails.
74
+     */
75
+    private function save_action_to_db( ActionScheduler_Action $action, DateTime $date = null, $unique = false ) {
76
+        global $wpdb;
77
+
78
+        try {
79
+            $this->validate_action( $action );
80
+
81
+            $data = array(
82
+                'hook'                 => $action->get_hook(),
83
+                'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
84
+                'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
85
+                'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
86
+                'schedule'             => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
87
+                'group_id'             => $this->get_group_id( $action->get_group() ),
88
+            );
89
+
90
+            $args = wp_json_encode( $action->get_args() );
91
+            if ( strlen( $args ) <= static::$max_index_length ) {
92
+                $data['args'] = $args;
93
+            } else {
94
+                $data['args']          = $this->hash_args( $args );
95
+                $data['extended_args'] = $args;
96
+            }
97
+
98
+            $insert_sql = $this->build_insert_sql( $data, $unique );
99
+
100
+            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $insert_sql should be already prepared.
101
+            $wpdb->query( $insert_sql );
102
+            $action_id = $wpdb->insert_id;
103
+
104
+            if ( is_wp_error( $action_id ) ) {
105
+                throw new \RuntimeException( $action_id->get_error_message() );
106
+            } elseif ( empty( $action_id ) ) {
107
+                if ( $unique ) {
108
+                    return 0;
109
+                }
110
+                throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
111
+            }
112
+
113
+            do_action( 'action_scheduler_stored_action', $action_id );
114
+
115
+            return $action_id;
116
+        } catch ( \Exception $e ) {
117
+            /* translators: %s: error message */
118
+            throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
119
+        }
120
+    }
121
+
122
+    /**
123
+     * Helper function to build insert query.
124
+     *
125
+     * @param array $data Row data for action.
126
+     * @param bool  $unique Whether the action should be unique.
127
+     *
128
+     * @return string Insert query.
129
+     */
130
+    private function build_insert_sql( array $data, $unique ) {
131
+        global $wpdb;
132
+        $columns      = array_keys( $data );
133
+        $values       = array_values( $data );
134
+        $placeholders = array_map( array( $this, 'get_placeholder_for_column' ), $columns );
135
+
136
+        $table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
137
+
138
+        $column_sql      = '`' . implode( '`, `', $columns ) . '`';
139
+        $placeholder_sql = implode( ', ', $placeholders );
140
+        $where_clause    = $this->build_where_clause_for_insert( $data, $table_name, $unique );
141
+        // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $column_sql and $where_clause are already prepared. $placeholder_sql is hardcoded.
142
+        $insert_query = $wpdb->prepare(
143
+            "
144 144
 INSERT INTO $table_name ( $column_sql )
145 145
 SELECT $placeholder_sql FROM DUAL
146 146
 WHERE ( $where_clause ) IS NULL",
147
-			$values
148
-		);
149
-		// phpcs:enable
150
-
151
-		return $insert_query;
152
-	}
153
-
154
-	/**
155
-	 * Helper method to build where clause for action insert statement.
156
-	 *
157
-	 * @param array  $data Row data for action.
158
-	 * @param string $table_name Action table name.
159
-	 * @param bool   $unique Where action should be unique.
160
-	 *
161
-	 * @return string Where clause to be used with insert.
162
-	 */
163
-	private function build_where_clause_for_insert( $data, $table_name, $unique ) {
164
-		global $wpdb;
165
-
166
-		if ( ! $unique ) {
167
-			return 'SELECT NULL FROM DUAL';
168
-		}
169
-
170
-		$pending_statuses            = array(
171
-			ActionScheduler_Store::STATUS_PENDING,
172
-			ActionScheduler_Store::STATUS_RUNNING,
173
-		);
174
-		$pending_status_placeholders = implode( ', ', array_fill( 0, count( $pending_statuses ), '%s' ) );
175
-		// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pending_status_placeholders is hardcoded.
176
-		$where_clause = $wpdb->prepare(
177
-			"
147
+            $values
148
+        );
149
+        // phpcs:enable
150
+
151
+        return $insert_query;
152
+    }
153
+
154
+    /**
155
+     * Helper method to build where clause for action insert statement.
156
+     *
157
+     * @param array  $data Row data for action.
158
+     * @param string $table_name Action table name.
159
+     * @param bool   $unique Where action should be unique.
160
+     *
161
+     * @return string Where clause to be used with insert.
162
+     */
163
+    private function build_where_clause_for_insert( $data, $table_name, $unique ) {
164
+        global $wpdb;
165
+
166
+        if ( ! $unique ) {
167
+            return 'SELECT NULL FROM DUAL';
168
+        }
169
+
170
+        $pending_statuses            = array(
171
+            ActionScheduler_Store::STATUS_PENDING,
172
+            ActionScheduler_Store::STATUS_RUNNING,
173
+        );
174
+        $pending_status_placeholders = implode( ', ', array_fill( 0, count( $pending_statuses ), '%s' ) );
175
+        // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pending_status_placeholders is hardcoded.
176
+        $where_clause = $wpdb->prepare(
177
+            "
178 178
 SELECT action_id FROM $table_name
179 179
 WHERE status IN ( $pending_status_placeholders )
180 180
 AND hook = %s
181 181
 AND `group_id` = %d
182 182
 ",
183
-			array_merge(
184
-				$pending_statuses,
185
-				array(
186
-					$data['hook'],
187
-					$data['group_id'],
188
-				)
189
-			)
190
-		);
191
-		// phpcs:enable
192
-
193
-		return "$where_clause" . ' LIMIT 1';
194
-	}
195
-
196
-	/**
197
-	 * Helper method to get $wpdb->prepare placeholder for a given column name.
198
-	 *
199
-	 * @param string $column_name Name of column in actions table.
200
-	 *
201
-	 * @return string Placeholder to use for given column.
202
-	 */
203
-	private function get_placeholder_for_column( $column_name ) {
204
-		$string_columns = array(
205
-			'hook',
206
-			'status',
207
-			'scheduled_date_gmt',
208
-			'scheduled_date_local',
209
-			'args',
210
-			'schedule',
211
-			'last_attempt_gmt',
212
-			'last_attempt_local',
213
-			'extended_args',
214
-		);
215
-
216
-		return in_array( $column_name, $string_columns ) ? '%s' : '%d';
217
-	}
218
-
219
-	/**
220
-	 * Generate a hash from json_encoded $args using MD5 as this isn't for security.
221
-	 *
222
-	 * @param string $args JSON encoded action args.
223
-	 * @return string
224
-	 */
225
-	protected function hash_args( $args ) {
226
-		return md5( $args );
227
-	}
228
-
229
-	/**
230
-	 * Get action args query param value from action args.
231
-	 *
232
-	 * @param array $args Action args.
233
-	 * @return string
234
-	 */
235
-	protected function get_args_for_query( $args ) {
236
-		$encoded = wp_json_encode( $args );
237
-		if ( strlen( $encoded ) <= static::$max_index_length ) {
238
-			return $encoded;
239
-		}
240
-		return $this->hash_args( $encoded );
241
-	}
242
-	/**
243
-	 * Get a group's ID based on its name/slug.
244
-	 *
245
-	 * @param string $slug The string name of a group.
246
-	 * @param bool   $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
247
-	 *
248
-	 * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
249
-	 */
250
-	protected function get_group_id( $slug, $create_if_not_exists = true ) {
251
-		if ( empty( $slug ) ) {
252
-			return 0;
253
-		}
254
-		/** @var \wpdb $wpdb */
255
-		global $wpdb;
256
-		$group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
257
-		if ( empty( $group_id ) && $create_if_not_exists ) {
258
-			$group_id = $this->create_group( $slug );
259
-		}
260
-
261
-		return $group_id;
262
-	}
263
-
264
-	/**
265
-	 * Create an action group.
266
-	 *
267
-	 * @param string $slug Group slug.
268
-	 *
269
-	 * @return int Group ID.
270
-	 */
271
-	protected function create_group( $slug ) {
272
-		/** @var \wpdb $wpdb */
273
-		global $wpdb;
274
-		$wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );
275
-
276
-		return (int) $wpdb->insert_id;
277
-	}
278
-
279
-	/**
280
-	 * Retrieve an action.
281
-	 *
282
-	 * @param int $action_id Action ID.
283
-	 *
284
-	 * @return ActionScheduler_Action
285
-	 */
286
-	public function fetch_action( $action_id ) {
287
-		/** @var \wpdb $wpdb */
288
-		global $wpdb;
289
-		$data = $wpdb->get_row(
290
-			$wpdb->prepare(
291
-				"SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
292
-				$action_id
293
-			)
294
-		);
295
-
296
-		if ( empty( $data ) ) {
297
-			return $this->get_null_action();
298
-		}
299
-
300
-		if ( ! empty( $data->extended_args ) ) {
301
-			$data->args = $data->extended_args;
302
-			unset( $data->extended_args );
303
-		}
304
-
305
-		// Convert NULL dates to zero dates.
306
-		$date_fields = array(
307
-			'scheduled_date_gmt',
308
-			'scheduled_date_local',
309
-			'last_attempt_gmt',
310
-			'last_attempt_gmt',
311
-		);
312
-		foreach ( $date_fields as $date_field ) {
313
-			if ( $data->$date_field === null ) {
314
-				$data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
315
-			}
316
-		}
317
-
318
-		try {
319
-			$action = $this->make_action_from_db_record( $data );
320
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
321
-			do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
322
-			return $this->get_null_action();
323
-		}
324
-
325
-		return $action;
326
-	}
327
-
328
-	/**
329
-	 * Create a null action.
330
-	 *
331
-	 * @return ActionScheduler_NullAction
332
-	 */
333
-	protected function get_null_action() {
334
-		return new ActionScheduler_NullAction();
335
-	}
336
-
337
-	/**
338
-	 * Create an action from a database record.
339
-	 *
340
-	 * @param object $data Action database record.
341
-	 *
342
-	 * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
343
-	 */
344
-	protected function make_action_from_db_record( $data ) {
345
-
346
-		$hook     = $data->hook;
347
-		$args     = json_decode( $data->args, true );
348
-		$schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
349
-
350
-		$this->validate_args( $args, $data->action_id );
351
-		$this->validate_schedule( $schedule, $data->action_id );
352
-
353
-		if ( empty( $schedule ) ) {
354
-			$schedule = new ActionScheduler_NullSchedule();
355
-		}
356
-		$group = $data->group ? $data->group : '';
357
-
358
-		return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
359
-	}
360
-
361
-	/**
362
-	 * Returns the SQL statement to query (or count) actions.
363
-	 *
364
-	 * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
365
-	 *
366
-	 * @param array  $query Filtering options.
367
-	 * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count.
368
-	 *
369
-	 * @return string SQL statement already properly escaped.
370
-	 * @throws InvalidArgumentException If the query is invalid.
371
-	 */
372
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
373
-
374
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
375
-			throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
376
-		}
377
-
378
-		$query = wp_parse_args(
379
-			$query,
380
-			array(
381
-				'hook'                  => '',
382
-				'args'                  => null,
383
-				'partial_args_matching' => 'off', // can be 'like' or 'json'
384
-				'date'                  => null,
385
-				'date_compare'          => '<=',
386
-				'modified'              => null,
387
-				'modified_compare'      => '<=',
388
-				'group'                 => '',
389
-				'status'                => '',
390
-				'claimed'               => null,
391
-				'per_page'              => 5,
392
-				'offset'                => 0,
393
-				'orderby'               => 'date',
394
-				'order'                 => 'ASC',
395
-			)
396
-		);
397
-
398
-		/** @var \wpdb $wpdb */
399
-		global $wpdb;
400
-
401
-		$db_server_info = is_callable( array( $wpdb, 'db_server_info' ) ) ? $wpdb->db_server_info() : $wpdb->db_version();
402
-		if ( false !== strpos( $db_server_info, 'MariaDB' ) ) {
403
-			$supports_json = version_compare(
404
-				PHP_VERSION_ID >= 80016 ? $wpdb->db_version() : preg_replace( '/[^0-9.].*/', '', str_replace( '5.5.5-', '', $db_server_info ) ),
405
-				'10.2',
406
-				'>='
407
-			);
408
-		} else {
409
-			$supports_json = version_compare( $wpdb->db_version(), '5.7', '>=' );
410
-		}
411
-
412
-		$sql        = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
413
-		$sql       .= " FROM {$wpdb->actionscheduler_actions} a";
414
-		$sql_params = array();
415
-
416
-		if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
417
-			$sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
418
-		}
419
-
420
-		$sql .= ' WHERE 1=1';
421
-
422
-		if ( ! empty( $query['group'] ) ) {
423
-			$sql         .= ' AND g.slug=%s';
424
-			$sql_params[] = $query['group'];
425
-		}
426
-
427
-		if ( ! empty( $query['hook'] ) ) {
428
-			$sql         .= ' AND a.hook=%s';
429
-			$sql_params[] = $query['hook'];
430
-		}
431
-
432
-		if ( $query['args'] !== null ) {
433
-			switch ( $query['partial_args_matching'] ) {
434
-				case 'json':
435
-					if ( ! $supports_json ) {
436
-						throw new \RuntimeException( __( 'JSON partial matching not supported in your environment. Please check your MySQL/MariaDB version.', 'action-scheduler' ) );
437
-					}
438
-					$supported_types = array(
439
-						'integer' => '%d',
440
-						'boolean' => '%s',
441
-						'double'  => '%f',
442
-						'string'  => '%s',
443
-					);
444
-					foreach ( $query['args'] as $key => $value ) {
445
-						$value_type = gettype( $value );
446
-						if ( 'boolean' === $value_type ) {
447
-							$value = $value ? 'true' : 'false';
448
-						}
449
-						$placeholder = isset( $supported_types[ $value_type ] ) ? $supported_types[ $value_type ] : false;
450
-						if ( ! $placeholder ) {
451
-							throw new \RuntimeException(
452
-								sprintf(
453
-								/* translators: %s: provided value type */
454
-									__( 'The value type for the JSON partial matching is not supported. Must be either integer, boolean, double or string. %s type provided.', 'action-scheduler' ),
455
-									$value_type
456
-								)
457
-							);
458
-						}
459
-						$sql         .= ' AND JSON_EXTRACT(a.args, %s)=' . $placeholder;
460
-						$sql_params[] = '$.' . $key;
461
-						$sql_params[] = $value;
462
-					}
463
-					break;
464
-				case 'like':
465
-					foreach ( $query['args'] as $key => $value ) {
466
-						$sql         .= ' AND a.args LIKE %s';
467
-						$json_partial = $wpdb->esc_like( trim( json_encode( array( $key => $value ) ), '{}' ) );
468
-						$sql_params[] = "%{$json_partial}%";
469
-					}
470
-					break;
471
-				case 'off':
472
-					$sql         .= ' AND a.args=%s';
473
-					$sql_params[] = $this->get_args_for_query( $query['args'] );
474
-					break;
475
-				default:
476
-					throw new \RuntimeException( __( 'Unknown partial args matching value.', 'action-scheduler' ) );
477
-			}
478
-		}
479
-
480
-		if ( $query['status'] ) {
481
-			$statuses     = (array) $query['status'];
482
-			$placeholders = array_fill( 0, count( $statuses ), '%s' );
483
-			$sql         .= ' AND a.status IN (' . join( ', ', $placeholders ) . ')';
484
-			$sql_params   = array_merge( $sql_params, array_values( $statuses ) );
485
-		}
486
-
487
-		if ( $query['date'] instanceof \DateTime ) {
488
-			$date = clone $query['date'];
489
-			$date->setTimezone( new \DateTimeZone( 'UTC' ) );
490
-			$date_string  = $date->format( 'Y-m-d H:i:s' );
491
-			$comparator   = $this->validate_sql_comparator( $query['date_compare'] );
492
-			$sql         .= " AND a.scheduled_date_gmt $comparator %s";
493
-			$sql_params[] = $date_string;
494
-		}
495
-
496
-		if ( $query['modified'] instanceof \DateTime ) {
497
-			$modified = clone $query['modified'];
498
-			$modified->setTimezone( new \DateTimeZone( 'UTC' ) );
499
-			$date_string  = $modified->format( 'Y-m-d H:i:s' );
500
-			$comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
501
-			$sql         .= " AND a.last_attempt_gmt $comparator %s";
502
-			$sql_params[] = $date_string;
503
-		}
504
-
505
-		if ( true === $query['claimed'] ) {
506
-			$sql .= ' AND a.claim_id != 0';
507
-		} elseif ( false === $query['claimed'] ) {
508
-			$sql .= ' AND a.claim_id = 0';
509
-		} elseif ( $query['claimed'] !== null ) {
510
-			$sql         .= ' AND a.claim_id = %d';
511
-			$sql_params[] = $query['claimed'];
512
-		}
513
-
514
-		if ( ! empty( $query['search'] ) ) {
515
-			$sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s';
516
-			for ( $i = 0; $i < 3; $i++ ) {
517
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
518
-			}
519
-
520
-			$search_claim_id = (int) $query['search'];
521
-			if ( $search_claim_id ) {
522
-				$sql         .= ' OR a.claim_id = %d';
523
-				$sql_params[] = $search_claim_id;
524
-			}
525
-
526
-			$sql .= ')';
527
-		}
528
-
529
-		if ( 'select' === $select_or_count ) {
530
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
531
-				$order = 'ASC';
532
-			} else {
533
-				$order = 'DESC';
534
-			}
535
-			switch ( $query['orderby'] ) {
536
-				case 'hook':
537
-					$sql .= " ORDER BY a.hook $order";
538
-					break;
539
-				case 'group':
540
-					$sql .= " ORDER BY g.slug $order";
541
-					break;
542
-				case 'modified':
543
-					$sql .= " ORDER BY a.last_attempt_gmt $order";
544
-					break;
545
-				case 'none':
546
-					break;
547
-				case 'action_id':
548
-					$sql .= " ORDER BY a.action_id $order";
549
-					break;
550
-				case 'date':
551
-				default:
552
-					$sql .= " ORDER BY a.scheduled_date_gmt $order";
553
-					break;
554
-			}
555
-
556
-			if ( $query['per_page'] > 0 ) {
557
-				$sql         .= ' LIMIT %d, %d';
558
-				$sql_params[] = $query['offset'];
559
-				$sql_params[] = $query['per_page'];
560
-			}
561
-		}
562
-
563
-		if ( ! empty( $sql_params ) ) {
564
-			$sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
565
-		}
566
-
567
-		return $sql;
568
-	}
569
-
570
-	/**
571
-	 * Query for action count or list of action IDs.
572
-	 *
573
-	 * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
574
-	 *
575
-	 * @see ActionScheduler_Store::query_actions for $query arg usage.
576
-	 *
577
-	 * @param array  $query      Query filtering options.
578
-	 * @param string $query_type Whether to select or count the results. Defaults to select.
579
-	 *
580
-	 * @return string|array|null The IDs of actions matching the query. Null on failure.
581
-	 */
582
-	public function query_actions( $query = array(), $query_type = 'select' ) {
583
-		/** @var wpdb $wpdb */
584
-		global $wpdb;
585
-
586
-		$sql = $this->get_query_actions_sql( $query, $query_type );
587
-
588
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
589
-	}
590
-
591
-	/**
592
-	 * Get a count of all actions in the store, grouped by status.
593
-	 *
594
-	 * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
595
-	 */
596
-	public function action_counts() {
597
-		global $wpdb;
598
-
599
-		$sql  = "SELECT a.status, count(a.status) as 'count'";
600
-		$sql .= " FROM {$wpdb->actionscheduler_actions} a";
601
-		$sql .= ' GROUP BY a.status';
602
-
603
-		$actions_count_by_status = array();
604
-		$action_stati_and_labels = $this->get_status_labels();
605
-
606
-		foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
607
-			// Ignore any actions with invalid status.
608
-			if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
609
-				$actions_count_by_status[ $action_data->status ] = $action_data->count;
610
-			}
611
-		}
612
-
613
-		return $actions_count_by_status;
614
-	}
615
-
616
-	/**
617
-	 * Cancel an action.
618
-	 *
619
-	 * @param int $action_id Action ID.
620
-	 *
621
-	 * @return void
622
-	 * @throws \InvalidArgumentException If the action update failed.
623
-	 */
624
-	public function cancel_action( $action_id ) {
625
-		/** @var \wpdb $wpdb */
626
-		global $wpdb;
627
-
628
-		$updated = $wpdb->update(
629
-			$wpdb->actionscheduler_actions,
630
-			array( 'status' => self::STATUS_CANCELED ),
631
-			array( 'action_id' => $action_id ),
632
-			array( '%s' ),
633
-			array( '%d' )
634
-		);
635
-		if ( false === $updated ) {
636
-			/* translators: %s: action ID */
637
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
638
-		}
639
-		do_action( 'action_scheduler_canceled_action', $action_id );
640
-	}
641
-
642
-	/**
643
-	 * Cancel pending actions by hook.
644
-	 *
645
-	 * @since 3.0.0
646
-	 *
647
-	 * @param string $hook Hook name.
648
-	 *
649
-	 * @return void
650
-	 */
651
-	public function cancel_actions_by_hook( $hook ) {
652
-		$this->bulk_cancel_actions( array( 'hook' => $hook ) );
653
-	}
654
-
655
-	/**
656
-	 * Cancel pending actions by group.
657
-	 *
658
-	 * @param string $group Group slug.
659
-	 *
660
-	 * @return void
661
-	 */
662
-	public function cancel_actions_by_group( $group ) {
663
-		$this->bulk_cancel_actions( array( 'group' => $group ) );
664
-	}
665
-
666
-	/**
667
-	 * Bulk cancel actions.
668
-	 *
669
-	 * @since 3.0.0
670
-	 *
671
-	 * @param array $query_args Query parameters.
672
-	 */
673
-	protected function bulk_cancel_actions( $query_args ) {
674
-		/** @var \wpdb $wpdb */
675
-		global $wpdb;
676
-
677
-		if ( ! is_array( $query_args ) ) {
678
-			return;
679
-		}
680
-
681
-		// Don't cancel actions that are already canceled.
682
-		if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
683
-			return;
684
-		}
685
-
686
-		$action_ids = true;
687
-		$query_args = wp_parse_args(
688
-			$query_args,
689
-			array(
690
-				'per_page' => 1000,
691
-				'status'   => self::STATUS_PENDING,
692
-				'orderby'  => 'action_id',
693
-			)
694
-		);
695
-
696
-		while ( $action_ids ) {
697
-			$action_ids = $this->query_actions( $query_args );
698
-			if ( empty( $action_ids ) ) {
699
-				break;
700
-			}
701
-
702
-			$format     = array_fill( 0, count( $action_ids ), '%d' );
703
-			$query_in   = '(' . implode( ',', $format ) . ')';
704
-			$parameters = $action_ids;
705
-			array_unshift( $parameters, self::STATUS_CANCELED );
706
-
707
-			$wpdb->query(
708
-				$wpdb->prepare(
709
-					"UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
710
-					$parameters
711
-				)
712
-			);
713
-
714
-			do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
715
-		}
716
-	}
717
-
718
-	/**
719
-	 * Delete an action.
720
-	 *
721
-	 * @param int $action_id Action ID.
722
-	 * @throws \InvalidArgumentException If the action deletion failed.
723
-	 */
724
-	public function delete_action( $action_id ) {
725
-		/** @var \wpdb $wpdb */
726
-		global $wpdb;
727
-		$deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
728
-		if ( empty( $deleted ) ) {
729
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
730
-		}
731
-		do_action( 'action_scheduler_deleted_action', $action_id );
732
-	}
733
-
734
-	/**
735
-	 * Get the schedule date for an action.
736
-	 *
737
-	 * @param string $action_id Action ID.
738
-	 *
739
-	 * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
740
-	 */
741
-	public function get_date( $action_id ) {
742
-		$date = $this->get_date_gmt( $action_id );
743
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
744
-		return $date;
745
-	}
746
-
747
-	/**
748
-	 * Get the GMT schedule date for an action.
749
-	 *
750
-	 * @param int $action_id Action ID.
751
-	 *
752
-	 * @throws \InvalidArgumentException If action cannot be identified.
753
-	 * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
754
-	 */
755
-	protected function get_date_gmt( $action_id ) {
756
-		/** @var \wpdb $wpdb */
757
-		global $wpdb;
758
-		$record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
759
-		if ( empty( $record ) ) {
760
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
761
-		}
762
-		if ( self::STATUS_PENDING === $record->status ) {
763
-			return as_get_datetime_object( $record->scheduled_date_gmt );
764
-		} else {
765
-			return as_get_datetime_object( $record->last_attempt_gmt );
766
-		}
767
-	}
768
-
769
-	/**
770
-	 * Stake a claim on actions.
771
-	 *
772
-	 * @param int       $max_actions Maximum number of action to include in claim.
773
-	 * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
774
-	 * @param array     $hooks Hooks to filter for.
775
-	 * @param string    $group Group to filter for.
776
-	 *
777
-	 * @return ActionScheduler_ActionClaim
778
-	 */
779
-	public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
780
-		$claim_id = $this->generate_claim_id();
781
-
782
-		$this->claim_before_date = $before_date;
783
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
784
-		$action_ids              = $this->find_actions_by_claim_id( $claim_id );
785
-		$this->claim_before_date = null;
786
-
787
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
788
-	}
789
-
790
-	/**
791
-	 * Generate a new action claim.
792
-	 *
793
-	 * @return int Claim ID.
794
-	 */
795
-	protected function generate_claim_id() {
796
-		/** @var \wpdb $wpdb */
797
-		global $wpdb;
798
-		$now = as_get_datetime_object();
799
-		$wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) );
800
-
801
-		return $wpdb->insert_id;
802
-	}
803
-
804
-	/**
805
-	 * Mark actions claimed.
806
-	 *
807
-	 * @param string    $claim_id Claim Id.
808
-	 * @param int       $limit Number of action to include in claim.
809
-	 * @param \DateTime $before_date Should use UTC timezone.
810
-	 * @param array     $hooks Hooks to filter for.
811
-	 * @param string    $group Group to filter for.
812
-	 *
813
-	 * @return int The number of actions that were claimed.
814
-	 * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
815
-	 * @throws \RuntimeException Throws RuntimeException if unable to claim action.
816
-	 */
817
-	protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
818
-		/** @var \wpdb $wpdb */
819
-		global $wpdb;
820
-
821
-		$now  = as_get_datetime_object();
822
-		$date = $before_date === null ? $now : clone $before_date;
823
-
824
-		// can't use $wpdb->update() because of the <= condition.
825
-		$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
826
-		$params = array(
827
-			$claim_id,
828
-			$now->format( 'Y-m-d H:i:s' ),
829
-			current_time( 'mysql' ),
830
-		);
831
-
832
-		$where    = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s';
833
-		$params[] = $date->format( 'Y-m-d H:i:s' );
834
-		$params[] = self::STATUS_PENDING;
835
-
836
-		if ( ! empty( $hooks ) ) {
837
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
838
-			$where       .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
839
-			$params       = array_merge( $params, array_values( $hooks ) );
840
-		}
841
-
842
-		if ( ! empty( $group ) ) {
843
-
844
-			$group_id = $this->get_group_id( $group, false );
845
-
846
-			// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
847
-			if ( empty( $group_id ) ) {
848
-				/* translators: %s: group name */
849
-				throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
850
-			}
851
-
852
-			$where   .= ' AND group_id = %d';
853
-			$params[] = $group_id;
854
-		}
855
-
856
-		/**
857
-		 * Sets the order-by clause used in the action claim query.
858
-		 *
859
-		 * @since 3.4.0
860
-		 *
861
-		 * @param string $order_by_sql
862
-		 */
863
-		$order    = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
864
-		$params[] = $limit;
865
-
866
-		$sql           = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
867
-		$rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
868
-		if ( false === $rows_affected ) {
869
-			throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
870
-		}
871
-
872
-		return (int) $rows_affected;
873
-	}
874
-
875
-	/**
876
-	 * Get the number of active claims.
877
-	 *
878
-	 * @return int
879
-	 */
880
-	public function get_claim_count() {
881
-		global $wpdb;
882
-
883
-		$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
884
-		$sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
885
-
886
-		return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
887
-	}
888
-
889
-	/**
890
-	 * Return an action's claim ID, as stored in the claim_id column.
891
-	 *
892
-	 * @param string $action_id Action ID.
893
-	 * @return mixed
894
-	 */
895
-	public function get_claim_id( $action_id ) {
896
-		/** @var \wpdb $wpdb */
897
-		global $wpdb;
898
-
899
-		$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
900
-		$sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
901
-
902
-		return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
903
-	}
904
-
905
-	/**
906
-	 * Retrieve the action IDs of action in a claim.
907
-	 *
908
-	 * @param  int $claim_id Claim ID.
909
-	 * @return int[]
910
-	 */
911
-	public function find_actions_by_claim_id( $claim_id ) {
912
-		/** @var \wpdb $wpdb */
913
-		global $wpdb;
914
-
915
-		$action_ids  = array();
916
-		$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
917
-		$cut_off     = $before_date->format( 'Y-m-d H:i:s' );
918
-
919
-		$sql = $wpdb->prepare(
920
-			"SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d",
921
-			$claim_id
922
-		);
923
-
924
-		// Verify that the scheduled date for each action is within the expected bounds (in some unusual
925
-		// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
926
-		foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
927
-			if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
928
-				$action_ids[] = absint( $claimed_action->action_id );
929
-			}
930
-		}
931
-
932
-		return $action_ids;
933
-	}
934
-
935
-	/**
936
-	 * Release actions from a claim and delete the claim.
937
-	 *
938
-	 * @param ActionScheduler_ActionClaim $claim Claim object.
939
-	 */
940
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
941
-		/** @var \wpdb $wpdb */
942
-		global $wpdb;
943
-		$wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) );
944
-		$wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) );
945
-	}
946
-
947
-	/**
948
-	 * Remove the claim from an action.
949
-	 *
950
-	 * @param int $action_id Action ID.
951
-	 *
952
-	 * @return void
953
-	 */
954
-	public function unclaim_action( $action_id ) {
955
-		/** @var \wpdb $wpdb */
956
-		global $wpdb;
957
-		$wpdb->update(
958
-			$wpdb->actionscheduler_actions,
959
-			array( 'claim_id' => 0 ),
960
-			array( 'action_id' => $action_id ),
961
-			array( '%s' ),
962
-			array( '%d' )
963
-		);
964
-	}
965
-
966
-	/**
967
-	 * Mark an action as failed.
968
-	 *
969
-	 * @param int $action_id Action ID.
970
-	 * @throws \InvalidArgumentException Throw an exception if action was not updated.
971
-	 */
972
-	public function mark_failure( $action_id ) {
973
-		/** @var \wpdb $wpdb */
974
-		global $wpdb;
975
-		$updated = $wpdb->update(
976
-			$wpdb->actionscheduler_actions,
977
-			array( 'status' => self::STATUS_FAILED ),
978
-			array( 'action_id' => $action_id ),
979
-			array( '%s' ),
980
-			array( '%d' )
981
-		);
982
-		if ( empty( $updated ) ) {
983
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
984
-		}
985
-	}
986
-
987
-	/**
988
-	 * Add execution message to action log.
989
-	 *
990
-	 * @param int $action_id Action ID.
991
-	 *
992
-	 * @return void
993
-	 */
994
-	public function log_execution( $action_id ) {
995
-		/** @var \wpdb $wpdb */
996
-		global $wpdb;
997
-
998
-		$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
999
-		$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1000
-		$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1001
-	}
1002
-
1003
-	/**
1004
-	 * Mark an action as complete.
1005
-	 *
1006
-	 * @param int $action_id Action ID.
1007
-	 *
1008
-	 * @return void
1009
-	 * @throws \InvalidArgumentException Throw an exception if action was not updated.
1010
-	 */
1011
-	public function mark_complete( $action_id ) {
1012
-		/** @var \wpdb $wpdb */
1013
-		global $wpdb;
1014
-		$updated = $wpdb->update(
1015
-			$wpdb->actionscheduler_actions,
1016
-			array(
1017
-				'status'             => self::STATUS_COMPLETE,
1018
-				'last_attempt_gmt'   => current_time( 'mysql', true ),
1019
-				'last_attempt_local' => current_time( 'mysql' ),
1020
-			),
1021
-			array( 'action_id' => $action_id ),
1022
-			array( '%s' ),
1023
-			array( '%d' )
1024
-		);
1025
-		if ( empty( $updated ) ) {
1026
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
1027
-		}
1028
-
1029
-		/**
1030
-		 * Fires after a scheduled action has been completed.
1031
-		 *
1032
-		 * @since 3.4.2
1033
-		 *
1034
-		 * @param int $action_id Action ID.
1035
-		 */
1036
-		do_action( 'action_scheduler_completed_action', $action_id );
1037
-	}
1038
-
1039
-	/**
1040
-	 * Get an action's status.
1041
-	 *
1042
-	 * @param int $action_id Action ID.
1043
-	 *
1044
-	 * @return string
1045
-	 * @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
1046
-	 * @throws \RuntimeException Throw an exception if action status could not be retrieved.
1047
-	 */
1048
-	public function get_status( $action_id ) {
1049
-		/** @var \wpdb $wpdb */
1050
-		global $wpdb;
1051
-		$sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
1052
-		$sql    = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1053
-		$status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1054
-
1055
-		if ( null === $status ) {
1056
-			throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
1057
-		} elseif ( empty( $status ) ) {
1058
-			throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
1059
-		} else {
1060
-			return $status;
1061
-		}
1062
-	}
183
+            array_merge(
184
+                $pending_statuses,
185
+                array(
186
+                    $data['hook'],
187
+                    $data['group_id'],
188
+                )
189
+            )
190
+        );
191
+        // phpcs:enable
192
+
193
+        return "$where_clause" . ' LIMIT 1';
194
+    }
195
+
196
+    /**
197
+     * Helper method to get $wpdb->prepare placeholder for a given column name.
198
+     *
199
+     * @param string $column_name Name of column in actions table.
200
+     *
201
+     * @return string Placeholder to use for given column.
202
+     */
203
+    private function get_placeholder_for_column( $column_name ) {
204
+        $string_columns = array(
205
+            'hook',
206
+            'status',
207
+            'scheduled_date_gmt',
208
+            'scheduled_date_local',
209
+            'args',
210
+            'schedule',
211
+            'last_attempt_gmt',
212
+            'last_attempt_local',
213
+            'extended_args',
214
+        );
215
+
216
+        return in_array( $column_name, $string_columns ) ? '%s' : '%d';
217
+    }
218
+
219
+    /**
220
+     * Generate a hash from json_encoded $args using MD5 as this isn't for security.
221
+     *
222
+     * @param string $args JSON encoded action args.
223
+     * @return string
224
+     */
225
+    protected function hash_args( $args ) {
226
+        return md5( $args );
227
+    }
228
+
229
+    /**
230
+     * Get action args query param value from action args.
231
+     *
232
+     * @param array $args Action args.
233
+     * @return string
234
+     */
235
+    protected function get_args_for_query( $args ) {
236
+        $encoded = wp_json_encode( $args );
237
+        if ( strlen( $encoded ) <= static::$max_index_length ) {
238
+            return $encoded;
239
+        }
240
+        return $this->hash_args( $encoded );
241
+    }
242
+    /**
243
+     * Get a group's ID based on its name/slug.
244
+     *
245
+     * @param string $slug The string name of a group.
246
+     * @param bool   $create_if_not_exists Whether to create the group if it does not already exist. Default, true - create the group.
247
+     *
248
+     * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
249
+     */
250
+    protected function get_group_id( $slug, $create_if_not_exists = true ) {
251
+        if ( empty( $slug ) ) {
252
+            return 0;
253
+        }
254
+        /** @var \wpdb $wpdb */
255
+        global $wpdb;
256
+        $group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
257
+        if ( empty( $group_id ) && $create_if_not_exists ) {
258
+            $group_id = $this->create_group( $slug );
259
+        }
260
+
261
+        return $group_id;
262
+    }
263
+
264
+    /**
265
+     * Create an action group.
266
+     *
267
+     * @param string $slug Group slug.
268
+     *
269
+     * @return int Group ID.
270
+     */
271
+    protected function create_group( $slug ) {
272
+        /** @var \wpdb $wpdb */
273
+        global $wpdb;
274
+        $wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );
275
+
276
+        return (int) $wpdb->insert_id;
277
+    }
278
+
279
+    /**
280
+     * Retrieve an action.
281
+     *
282
+     * @param int $action_id Action ID.
283
+     *
284
+     * @return ActionScheduler_Action
285
+     */
286
+    public function fetch_action( $action_id ) {
287
+        /** @var \wpdb $wpdb */
288
+        global $wpdb;
289
+        $data = $wpdb->get_row(
290
+            $wpdb->prepare(
291
+                "SELECT a.*, g.slug AS `group` FROM {$wpdb->actionscheduler_actions} a LEFT JOIN {$wpdb->actionscheduler_groups} g ON a.group_id=g.group_id WHERE a.action_id=%d",
292
+                $action_id
293
+            )
294
+        );
295
+
296
+        if ( empty( $data ) ) {
297
+            return $this->get_null_action();
298
+        }
299
+
300
+        if ( ! empty( $data->extended_args ) ) {
301
+            $data->args = $data->extended_args;
302
+            unset( $data->extended_args );
303
+        }
304
+
305
+        // Convert NULL dates to zero dates.
306
+        $date_fields = array(
307
+            'scheduled_date_gmt',
308
+            'scheduled_date_local',
309
+            'last_attempt_gmt',
310
+            'last_attempt_gmt',
311
+        );
312
+        foreach ( $date_fields as $date_field ) {
313
+            if ( $data->$date_field === null ) {
314
+                $data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
315
+            }
316
+        }
317
+
318
+        try {
319
+            $action = $this->make_action_from_db_record( $data );
320
+        } catch ( ActionScheduler_InvalidActionException $exception ) {
321
+            do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
322
+            return $this->get_null_action();
323
+        }
324
+
325
+        return $action;
326
+    }
327
+
328
+    /**
329
+     * Create a null action.
330
+     *
331
+     * @return ActionScheduler_NullAction
332
+     */
333
+    protected function get_null_action() {
334
+        return new ActionScheduler_NullAction();
335
+    }
336
+
337
+    /**
338
+     * Create an action from a database record.
339
+     *
340
+     * @param object $data Action database record.
341
+     *
342
+     * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
343
+     */
344
+    protected function make_action_from_db_record( $data ) {
345
+
346
+        $hook     = $data->hook;
347
+        $args     = json_decode( $data->args, true );
348
+        $schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
349
+
350
+        $this->validate_args( $args, $data->action_id );
351
+        $this->validate_schedule( $schedule, $data->action_id );
352
+
353
+        if ( empty( $schedule ) ) {
354
+            $schedule = new ActionScheduler_NullSchedule();
355
+        }
356
+        $group = $data->group ? $data->group : '';
357
+
358
+        return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
359
+    }
360
+
361
+    /**
362
+     * Returns the SQL statement to query (or count) actions.
363
+     *
364
+     * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
365
+     *
366
+     * @param array  $query Filtering options.
367
+     * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count.
368
+     *
369
+     * @return string SQL statement already properly escaped.
370
+     * @throws InvalidArgumentException If the query is invalid.
371
+     */
372
+    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
373
+
374
+        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
375
+            throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
376
+        }
377
+
378
+        $query = wp_parse_args(
379
+            $query,
380
+            array(
381
+                'hook'                  => '',
382
+                'args'                  => null,
383
+                'partial_args_matching' => 'off', // can be 'like' or 'json'
384
+                'date'                  => null,
385
+                'date_compare'          => '<=',
386
+                'modified'              => null,
387
+                'modified_compare'      => '<=',
388
+                'group'                 => '',
389
+                'status'                => '',
390
+                'claimed'               => null,
391
+                'per_page'              => 5,
392
+                'offset'                => 0,
393
+                'orderby'               => 'date',
394
+                'order'                 => 'ASC',
395
+            )
396
+        );
397
+
398
+        /** @var \wpdb $wpdb */
399
+        global $wpdb;
400
+
401
+        $db_server_info = is_callable( array( $wpdb, 'db_server_info' ) ) ? $wpdb->db_server_info() : $wpdb->db_version();
402
+        if ( false !== strpos( $db_server_info, 'MariaDB' ) ) {
403
+            $supports_json = version_compare(
404
+                PHP_VERSION_ID >= 80016 ? $wpdb->db_version() : preg_replace( '/[^0-9.].*/', '', str_replace( '5.5.5-', '', $db_server_info ) ),
405
+                '10.2',
406
+                '>='
407
+            );
408
+        } else {
409
+            $supports_json = version_compare( $wpdb->db_version(), '5.7', '>=' );
410
+        }
411
+
412
+        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
413
+        $sql       .= " FROM {$wpdb->actionscheduler_actions} a";
414
+        $sql_params = array();
415
+
416
+        if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
417
+            $sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
418
+        }
419
+
420
+        $sql .= ' WHERE 1=1';
421
+
422
+        if ( ! empty( $query['group'] ) ) {
423
+            $sql         .= ' AND g.slug=%s';
424
+            $sql_params[] = $query['group'];
425
+        }
426
+
427
+        if ( ! empty( $query['hook'] ) ) {
428
+            $sql         .= ' AND a.hook=%s';
429
+            $sql_params[] = $query['hook'];
430
+        }
431
+
432
+        if ( $query['args'] !== null ) {
433
+            switch ( $query['partial_args_matching'] ) {
434
+                case 'json':
435
+                    if ( ! $supports_json ) {
436
+                        throw new \RuntimeException( __( 'JSON partial matching not supported in your environment. Please check your MySQL/MariaDB version.', 'action-scheduler' ) );
437
+                    }
438
+                    $supported_types = array(
439
+                        'integer' => '%d',
440
+                        'boolean' => '%s',
441
+                        'double'  => '%f',
442
+                        'string'  => '%s',
443
+                    );
444
+                    foreach ( $query['args'] as $key => $value ) {
445
+                        $value_type = gettype( $value );
446
+                        if ( 'boolean' === $value_type ) {
447
+                            $value = $value ? 'true' : 'false';
448
+                        }
449
+                        $placeholder = isset( $supported_types[ $value_type ] ) ? $supported_types[ $value_type ] : false;
450
+                        if ( ! $placeholder ) {
451
+                            throw new \RuntimeException(
452
+                                sprintf(
453
+                                /* translators: %s: provided value type */
454
+                                    __( 'The value type for the JSON partial matching is not supported. Must be either integer, boolean, double or string. %s type provided.', 'action-scheduler' ),
455
+                                    $value_type
456
+                                )
457
+                            );
458
+                        }
459
+                        $sql         .= ' AND JSON_EXTRACT(a.args, %s)=' . $placeholder;
460
+                        $sql_params[] = '$.' . $key;
461
+                        $sql_params[] = $value;
462
+                    }
463
+                    break;
464
+                case 'like':
465
+                    foreach ( $query['args'] as $key => $value ) {
466
+                        $sql         .= ' AND a.args LIKE %s';
467
+                        $json_partial = $wpdb->esc_like( trim( json_encode( array( $key => $value ) ), '{}' ) );
468
+                        $sql_params[] = "%{$json_partial}%";
469
+                    }
470
+                    break;
471
+                case 'off':
472
+                    $sql         .= ' AND a.args=%s';
473
+                    $sql_params[] = $this->get_args_for_query( $query['args'] );
474
+                    break;
475
+                default:
476
+                    throw new \RuntimeException( __( 'Unknown partial args matching value.', 'action-scheduler' ) );
477
+            }
478
+        }
479
+
480
+        if ( $query['status'] ) {
481
+            $statuses     = (array) $query['status'];
482
+            $placeholders = array_fill( 0, count( $statuses ), '%s' );
483
+            $sql         .= ' AND a.status IN (' . join( ', ', $placeholders ) . ')';
484
+            $sql_params   = array_merge( $sql_params, array_values( $statuses ) );
485
+        }
486
+
487
+        if ( $query['date'] instanceof \DateTime ) {
488
+            $date = clone $query['date'];
489
+            $date->setTimezone( new \DateTimeZone( 'UTC' ) );
490
+            $date_string  = $date->format( 'Y-m-d H:i:s' );
491
+            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
492
+            $sql         .= " AND a.scheduled_date_gmt $comparator %s";
493
+            $sql_params[] = $date_string;
494
+        }
495
+
496
+        if ( $query['modified'] instanceof \DateTime ) {
497
+            $modified = clone $query['modified'];
498
+            $modified->setTimezone( new \DateTimeZone( 'UTC' ) );
499
+            $date_string  = $modified->format( 'Y-m-d H:i:s' );
500
+            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
501
+            $sql         .= " AND a.last_attempt_gmt $comparator %s";
502
+            $sql_params[] = $date_string;
503
+        }
504
+
505
+        if ( true === $query['claimed'] ) {
506
+            $sql .= ' AND a.claim_id != 0';
507
+        } elseif ( false === $query['claimed'] ) {
508
+            $sql .= ' AND a.claim_id = 0';
509
+        } elseif ( $query['claimed'] !== null ) {
510
+            $sql         .= ' AND a.claim_id = %d';
511
+            $sql_params[] = $query['claimed'];
512
+        }
513
+
514
+        if ( ! empty( $query['search'] ) ) {
515
+            $sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s';
516
+            for ( $i = 0; $i < 3; $i++ ) {
517
+                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
518
+            }
519
+
520
+            $search_claim_id = (int) $query['search'];
521
+            if ( $search_claim_id ) {
522
+                $sql         .= ' OR a.claim_id = %d';
523
+                $sql_params[] = $search_claim_id;
524
+            }
525
+
526
+            $sql .= ')';
527
+        }
528
+
529
+        if ( 'select' === $select_or_count ) {
530
+            if ( 'ASC' === strtoupper( $query['order'] ) ) {
531
+                $order = 'ASC';
532
+            } else {
533
+                $order = 'DESC';
534
+            }
535
+            switch ( $query['orderby'] ) {
536
+                case 'hook':
537
+                    $sql .= " ORDER BY a.hook $order";
538
+                    break;
539
+                case 'group':
540
+                    $sql .= " ORDER BY g.slug $order";
541
+                    break;
542
+                case 'modified':
543
+                    $sql .= " ORDER BY a.last_attempt_gmt $order";
544
+                    break;
545
+                case 'none':
546
+                    break;
547
+                case 'action_id':
548
+                    $sql .= " ORDER BY a.action_id $order";
549
+                    break;
550
+                case 'date':
551
+                default:
552
+                    $sql .= " ORDER BY a.scheduled_date_gmt $order";
553
+                    break;
554
+            }
555
+
556
+            if ( $query['per_page'] > 0 ) {
557
+                $sql         .= ' LIMIT %d, %d';
558
+                $sql_params[] = $query['offset'];
559
+                $sql_params[] = $query['per_page'];
560
+            }
561
+        }
562
+
563
+        if ( ! empty( $sql_params ) ) {
564
+            $sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
565
+        }
566
+
567
+        return $sql;
568
+    }
569
+
570
+    /**
571
+     * Query for action count or list of action IDs.
572
+     *
573
+     * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
574
+     *
575
+     * @see ActionScheduler_Store::query_actions for $query arg usage.
576
+     *
577
+     * @param array  $query      Query filtering options.
578
+     * @param string $query_type Whether to select or count the results. Defaults to select.
579
+     *
580
+     * @return string|array|null The IDs of actions matching the query. Null on failure.
581
+     */
582
+    public function query_actions( $query = array(), $query_type = 'select' ) {
583
+        /** @var wpdb $wpdb */
584
+        global $wpdb;
585
+
586
+        $sql = $this->get_query_actions_sql( $query, $query_type );
587
+
588
+        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
589
+    }
590
+
591
+    /**
592
+     * Get a count of all actions in the store, grouped by status.
593
+     *
594
+     * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
595
+     */
596
+    public function action_counts() {
597
+        global $wpdb;
598
+
599
+        $sql  = "SELECT a.status, count(a.status) as 'count'";
600
+        $sql .= " FROM {$wpdb->actionscheduler_actions} a";
601
+        $sql .= ' GROUP BY a.status';
602
+
603
+        $actions_count_by_status = array();
604
+        $action_stati_and_labels = $this->get_status_labels();
605
+
606
+        foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
607
+            // Ignore any actions with invalid status.
608
+            if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
609
+                $actions_count_by_status[ $action_data->status ] = $action_data->count;
610
+            }
611
+        }
612
+
613
+        return $actions_count_by_status;
614
+    }
615
+
616
+    /**
617
+     * Cancel an action.
618
+     *
619
+     * @param int $action_id Action ID.
620
+     *
621
+     * @return void
622
+     * @throws \InvalidArgumentException If the action update failed.
623
+     */
624
+    public function cancel_action( $action_id ) {
625
+        /** @var \wpdb $wpdb */
626
+        global $wpdb;
627
+
628
+        $updated = $wpdb->update(
629
+            $wpdb->actionscheduler_actions,
630
+            array( 'status' => self::STATUS_CANCELED ),
631
+            array( 'action_id' => $action_id ),
632
+            array( '%s' ),
633
+            array( '%d' )
634
+        );
635
+        if ( false === $updated ) {
636
+            /* translators: %s: action ID */
637
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
638
+        }
639
+        do_action( 'action_scheduler_canceled_action', $action_id );
640
+    }
641
+
642
+    /**
643
+     * Cancel pending actions by hook.
644
+     *
645
+     * @since 3.0.0
646
+     *
647
+     * @param string $hook Hook name.
648
+     *
649
+     * @return void
650
+     */
651
+    public function cancel_actions_by_hook( $hook ) {
652
+        $this->bulk_cancel_actions( array( 'hook' => $hook ) );
653
+    }
654
+
655
+    /**
656
+     * Cancel pending actions by group.
657
+     *
658
+     * @param string $group Group slug.
659
+     *
660
+     * @return void
661
+     */
662
+    public function cancel_actions_by_group( $group ) {
663
+        $this->bulk_cancel_actions( array( 'group' => $group ) );
664
+    }
665
+
666
+    /**
667
+     * Bulk cancel actions.
668
+     *
669
+     * @since 3.0.0
670
+     *
671
+     * @param array $query_args Query parameters.
672
+     */
673
+    protected function bulk_cancel_actions( $query_args ) {
674
+        /** @var \wpdb $wpdb */
675
+        global $wpdb;
676
+
677
+        if ( ! is_array( $query_args ) ) {
678
+            return;
679
+        }
680
+
681
+        // Don't cancel actions that are already canceled.
682
+        if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
683
+            return;
684
+        }
685
+
686
+        $action_ids = true;
687
+        $query_args = wp_parse_args(
688
+            $query_args,
689
+            array(
690
+                'per_page' => 1000,
691
+                'status'   => self::STATUS_PENDING,
692
+                'orderby'  => 'action_id',
693
+            )
694
+        );
695
+
696
+        while ( $action_ids ) {
697
+            $action_ids = $this->query_actions( $query_args );
698
+            if ( empty( $action_ids ) ) {
699
+                break;
700
+            }
701
+
702
+            $format     = array_fill( 0, count( $action_ids ), '%d' );
703
+            $query_in   = '(' . implode( ',', $format ) . ')';
704
+            $parameters = $action_ids;
705
+            array_unshift( $parameters, self::STATUS_CANCELED );
706
+
707
+            $wpdb->query(
708
+                $wpdb->prepare(
709
+                    "UPDATE {$wpdb->actionscheduler_actions} SET status = %s WHERE action_id IN {$query_in}", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
710
+                    $parameters
711
+                )
712
+            );
713
+
714
+            do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
715
+        }
716
+    }
717
+
718
+    /**
719
+     * Delete an action.
720
+     *
721
+     * @param int $action_id Action ID.
722
+     * @throws \InvalidArgumentException If the action deletion failed.
723
+     */
724
+    public function delete_action( $action_id ) {
725
+        /** @var \wpdb $wpdb */
726
+        global $wpdb;
727
+        $deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
728
+        if ( empty( $deleted ) ) {
729
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
730
+        }
731
+        do_action( 'action_scheduler_deleted_action', $action_id );
732
+    }
733
+
734
+    /**
735
+     * Get the schedule date for an action.
736
+     *
737
+     * @param string $action_id Action ID.
738
+     *
739
+     * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
740
+     */
741
+    public function get_date( $action_id ) {
742
+        $date = $this->get_date_gmt( $action_id );
743
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
744
+        return $date;
745
+    }
746
+
747
+    /**
748
+     * Get the GMT schedule date for an action.
749
+     *
750
+     * @param int $action_id Action ID.
751
+     *
752
+     * @throws \InvalidArgumentException If action cannot be identified.
753
+     * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
754
+     */
755
+    protected function get_date_gmt( $action_id ) {
756
+        /** @var \wpdb $wpdb */
757
+        global $wpdb;
758
+        $record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
759
+        if ( empty( $record ) ) {
760
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
761
+        }
762
+        if ( self::STATUS_PENDING === $record->status ) {
763
+            return as_get_datetime_object( $record->scheduled_date_gmt );
764
+        } else {
765
+            return as_get_datetime_object( $record->last_attempt_gmt );
766
+        }
767
+    }
768
+
769
+    /**
770
+     * Stake a claim on actions.
771
+     *
772
+     * @param int       $max_actions Maximum number of action to include in claim.
773
+     * @param \DateTime $before_date Jobs must be schedule before this date. Defaults to now.
774
+     * @param array     $hooks Hooks to filter for.
775
+     * @param string    $group Group to filter for.
776
+     *
777
+     * @return ActionScheduler_ActionClaim
778
+     */
779
+    public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
780
+        $claim_id = $this->generate_claim_id();
781
+
782
+        $this->claim_before_date = $before_date;
783
+        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
784
+        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
785
+        $this->claim_before_date = null;
786
+
787
+        return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
788
+    }
789
+
790
+    /**
791
+     * Generate a new action claim.
792
+     *
793
+     * @return int Claim ID.
794
+     */
795
+    protected function generate_claim_id() {
796
+        /** @var \wpdb $wpdb */
797
+        global $wpdb;
798
+        $now = as_get_datetime_object();
799
+        $wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) );
800
+
801
+        return $wpdb->insert_id;
802
+    }
803
+
804
+    /**
805
+     * Mark actions claimed.
806
+     *
807
+     * @param string    $claim_id Claim Id.
808
+     * @param int       $limit Number of action to include in claim.
809
+     * @param \DateTime $before_date Should use UTC timezone.
810
+     * @param array     $hooks Hooks to filter for.
811
+     * @param string    $group Group to filter for.
812
+     *
813
+     * @return int The number of actions that were claimed.
814
+     * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
815
+     * @throws \RuntimeException Throws RuntimeException if unable to claim action.
816
+     */
817
+    protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
818
+        /** @var \wpdb $wpdb */
819
+        global $wpdb;
820
+
821
+        $now  = as_get_datetime_object();
822
+        $date = $before_date === null ? $now : clone $before_date;
823
+
824
+        // can't use $wpdb->update() because of the <= condition.
825
+        $update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
826
+        $params = array(
827
+            $claim_id,
828
+            $now->format( 'Y-m-d H:i:s' ),
829
+            current_time( 'mysql' ),
830
+        );
831
+
832
+        $where    = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s';
833
+        $params[] = $date->format( 'Y-m-d H:i:s' );
834
+        $params[] = self::STATUS_PENDING;
835
+
836
+        if ( ! empty( $hooks ) ) {
837
+            $placeholders = array_fill( 0, count( $hooks ), '%s' );
838
+            $where       .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
839
+            $params       = array_merge( $params, array_values( $hooks ) );
840
+        }
841
+
842
+        if ( ! empty( $group ) ) {
843
+
844
+            $group_id = $this->get_group_id( $group, false );
845
+
846
+            // throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
847
+            if ( empty( $group_id ) ) {
848
+                /* translators: %s: group name */
849
+                throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
850
+            }
851
+
852
+            $where   .= ' AND group_id = %d';
853
+            $params[] = $group_id;
854
+        }
855
+
856
+        /**
857
+         * Sets the order-by clause used in the action claim query.
858
+         *
859
+         * @since 3.4.0
860
+         *
861
+         * @param string $order_by_sql
862
+         */
863
+        $order    = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
864
+        $params[] = $limit;
865
+
866
+        $sql           = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
867
+        $rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
868
+        if ( false === $rows_affected ) {
869
+            throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
870
+        }
871
+
872
+        return (int) $rows_affected;
873
+    }
874
+
875
+    /**
876
+     * Get the number of active claims.
877
+     *
878
+     * @return int
879
+     */
880
+    public function get_claim_count() {
881
+        global $wpdb;
882
+
883
+        $sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
884
+        $sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
885
+
886
+        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
887
+    }
888
+
889
+    /**
890
+     * Return an action's claim ID, as stored in the claim_id column.
891
+     *
892
+     * @param string $action_id Action ID.
893
+     * @return mixed
894
+     */
895
+    public function get_claim_id( $action_id ) {
896
+        /** @var \wpdb $wpdb */
897
+        global $wpdb;
898
+
899
+        $sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
900
+        $sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
901
+
902
+        return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
903
+    }
904
+
905
+    /**
906
+     * Retrieve the action IDs of action in a claim.
907
+     *
908
+     * @param  int $claim_id Claim ID.
909
+     * @return int[]
910
+     */
911
+    public function find_actions_by_claim_id( $claim_id ) {
912
+        /** @var \wpdb $wpdb */
913
+        global $wpdb;
914
+
915
+        $action_ids  = array();
916
+        $before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
917
+        $cut_off     = $before_date->format( 'Y-m-d H:i:s' );
918
+
919
+        $sql = $wpdb->prepare(
920
+            "SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d",
921
+            $claim_id
922
+        );
923
+
924
+        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
925
+        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
926
+        foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
927
+            if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
928
+                $action_ids[] = absint( $claimed_action->action_id );
929
+            }
930
+        }
931
+
932
+        return $action_ids;
933
+    }
934
+
935
+    /**
936
+     * Release actions from a claim and delete the claim.
937
+     *
938
+     * @param ActionScheduler_ActionClaim $claim Claim object.
939
+     */
940
+    public function release_claim( ActionScheduler_ActionClaim $claim ) {
941
+        /** @var \wpdb $wpdb */
942
+        global $wpdb;
943
+        $wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) );
944
+        $wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) );
945
+    }
946
+
947
+    /**
948
+     * Remove the claim from an action.
949
+     *
950
+     * @param int $action_id Action ID.
951
+     *
952
+     * @return void
953
+     */
954
+    public function unclaim_action( $action_id ) {
955
+        /** @var \wpdb $wpdb */
956
+        global $wpdb;
957
+        $wpdb->update(
958
+            $wpdb->actionscheduler_actions,
959
+            array( 'claim_id' => 0 ),
960
+            array( 'action_id' => $action_id ),
961
+            array( '%s' ),
962
+            array( '%d' )
963
+        );
964
+    }
965
+
966
+    /**
967
+     * Mark an action as failed.
968
+     *
969
+     * @param int $action_id Action ID.
970
+     * @throws \InvalidArgumentException Throw an exception if action was not updated.
971
+     */
972
+    public function mark_failure( $action_id ) {
973
+        /** @var \wpdb $wpdb */
974
+        global $wpdb;
975
+        $updated = $wpdb->update(
976
+            $wpdb->actionscheduler_actions,
977
+            array( 'status' => self::STATUS_FAILED ),
978
+            array( 'action_id' => $action_id ),
979
+            array( '%s' ),
980
+            array( '%d' )
981
+        );
982
+        if ( empty( $updated ) ) {
983
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
984
+        }
985
+    }
986
+
987
+    /**
988
+     * Add execution message to action log.
989
+     *
990
+     * @param int $action_id Action ID.
991
+     *
992
+     * @return void
993
+     */
994
+    public function log_execution( $action_id ) {
995
+        /** @var \wpdb $wpdb */
996
+        global $wpdb;
997
+
998
+        $sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
999
+        $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1000
+        $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1001
+    }
1002
+
1003
+    /**
1004
+     * Mark an action as complete.
1005
+     *
1006
+     * @param int $action_id Action ID.
1007
+     *
1008
+     * @return void
1009
+     * @throws \InvalidArgumentException Throw an exception if action was not updated.
1010
+     */
1011
+    public function mark_complete( $action_id ) {
1012
+        /** @var \wpdb $wpdb */
1013
+        global $wpdb;
1014
+        $updated = $wpdb->update(
1015
+            $wpdb->actionscheduler_actions,
1016
+            array(
1017
+                'status'             => self::STATUS_COMPLETE,
1018
+                'last_attempt_gmt'   => current_time( 'mysql', true ),
1019
+                'last_attempt_local' => current_time( 'mysql' ),
1020
+            ),
1021
+            array( 'action_id' => $action_id ),
1022
+            array( '%s' ),
1023
+            array( '%d' )
1024
+        );
1025
+        if ( empty( $updated ) ) {
1026
+            throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
1027
+        }
1028
+
1029
+        /**
1030
+         * Fires after a scheduled action has been completed.
1031
+         *
1032
+         * @since 3.4.2
1033
+         *
1034
+         * @param int $action_id Action ID.
1035
+         */
1036
+        do_action( 'action_scheduler_completed_action', $action_id );
1037
+    }
1038
+
1039
+    /**
1040
+     * Get an action's status.
1041
+     *
1042
+     * @param int $action_id Action ID.
1043
+     *
1044
+     * @return string
1045
+     * @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
1046
+     * @throws \RuntimeException Throw an exception if action status could not be retrieved.
1047
+     */
1048
+    public function get_status( $action_id ) {
1049
+        /** @var \wpdb $wpdb */
1050
+        global $wpdb;
1051
+        $sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
1052
+        $sql    = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1053
+        $status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1054
+
1055
+        if ( null === $status ) {
1056
+            throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
1057
+        } elseif ( empty( $status ) ) {
1058
+            throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
1059
+        } else {
1060
+            return $status;
1061
+        }
1062
+    }
1063 1063
 }
Please login to merge, or discard this patch.
Spacing   +230 added lines, -230 removed lines patch added patch discarded remove patch
@@ -45,8 +45,8 @@  discard block
 block discarded – undo
45 45
 	 * @return int                  Action ID.
46 46
 	 * @throws RuntimeException     Throws exception when saving the action fails.
47 47
 	 */
48
-	public function save_unique_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
49
-		return $this->save_action_to_db( $action, $scheduled_date, true );
48
+	public function save_unique_action(ActionScheduler_Action $action, \DateTime $scheduled_date = null) {
49
+		return $this->save_action_to_db($action, $scheduled_date, true);
50 50
 	}
51 51
 
52 52
 	/**
@@ -58,8 +58,8 @@  discard block
 block discarded – undo
58 58
 	 * @return int Action ID.
59 59
 	 * @throws RuntimeException     Throws exception when saving the action fails.
60 60
 	 */
61
-	public function save_action( ActionScheduler_Action $action, \DateTime $scheduled_date = null ) {
62
-		return $this->save_action_to_db( $action, $scheduled_date, false );
61
+	public function save_action(ActionScheduler_Action $action, \DateTime $scheduled_date = null) {
62
+		return $this->save_action_to_db($action, $scheduled_date, false);
63 63
 	}
64 64
 
65 65
 	/**
@@ -72,50 +72,50 @@  discard block
 block discarded – undo
72 72
 	 * @return int Action ID.
73 73
 	 * @throws RuntimeException     Throws exception when saving the action fails.
74 74
 	 */
75
-	private function save_action_to_db( ActionScheduler_Action $action, DateTime $date = null, $unique = false ) {
75
+	private function save_action_to_db(ActionScheduler_Action $action, DateTime $date = null, $unique = false) {
76 76
 		global $wpdb;
77 77
 
78 78
 		try {
79
-			$this->validate_action( $action );
79
+			$this->validate_action($action);
80 80
 
81 81
 			$data = array(
82 82
 				'hook'                 => $action->get_hook(),
83
-				'status'               => ( $action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING ),
84
-				'scheduled_date_gmt'   => $this->get_scheduled_date_string( $action, $date ),
85
-				'scheduled_date_local' => $this->get_scheduled_date_string_local( $action, $date ),
86
-				'schedule'             => serialize( $action->get_schedule() ), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
87
-				'group_id'             => $this->get_group_id( $action->get_group() ),
83
+				'status'               => ($action->is_finished() ? self::STATUS_COMPLETE : self::STATUS_PENDING),
84
+				'scheduled_date_gmt'   => $this->get_scheduled_date_string($action, $date),
85
+				'scheduled_date_local' => $this->get_scheduled_date_string_local($action, $date),
86
+				'schedule'             => serialize($action->get_schedule()), // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
87
+				'group_id'             => $this->get_group_id($action->get_group()),
88 88
 			);
89 89
 
90
-			$args = wp_json_encode( $action->get_args() );
91
-			if ( strlen( $args ) <= static::$max_index_length ) {
90
+			$args = wp_json_encode($action->get_args());
91
+			if (strlen($args) <= static::$max_index_length) {
92 92
 				$data['args'] = $args;
93 93
 			} else {
94
-				$data['args']          = $this->hash_args( $args );
94
+				$data['args']          = $this->hash_args($args);
95 95
 				$data['extended_args'] = $args;
96 96
 			}
97 97
 
98
-			$insert_sql = $this->build_insert_sql( $data, $unique );
98
+			$insert_sql = $this->build_insert_sql($data, $unique);
99 99
 
100 100
 			// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $insert_sql should be already prepared.
101
-			$wpdb->query( $insert_sql );
101
+			$wpdb->query($insert_sql);
102 102
 			$action_id = $wpdb->insert_id;
103 103
 
104
-			if ( is_wp_error( $action_id ) ) {
105
-				throw new \RuntimeException( $action_id->get_error_message() );
106
-			} elseif ( empty( $action_id ) ) {
107
-				if ( $unique ) {
104
+			if (is_wp_error($action_id)) {
105
+				throw new \RuntimeException($action_id->get_error_message());
106
+			} elseif (empty($action_id)) {
107
+				if ($unique) {
108 108
 					return 0;
109 109
 				}
110
-				throw new \RuntimeException( $wpdb->last_error ? $wpdb->last_error : __( 'Database error.', 'action-scheduler' ) );
110
+				throw new \RuntimeException($wpdb->last_error ? $wpdb->last_error : __('Database error.', 'action-scheduler'));
111 111
 			}
112 112
 
113
-			do_action( 'action_scheduler_stored_action', $action_id );
113
+			do_action('action_scheduler_stored_action', $action_id);
114 114
 
115 115
 			return $action_id;
116
-		} catch ( \Exception $e ) {
116
+		} catch (\Exception $e) {
117 117
 			/* translators: %s: error message */
118
-			throw new \RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
118
+			throw new \RuntimeException(sprintf(__('Error saving action: %s', 'action-scheduler'), $e->getMessage()), 0);
119 119
 		}
120 120
 	}
121 121
 
@@ -127,17 +127,17 @@  discard block
 block discarded – undo
127 127
 	 *
128 128
 	 * @return string Insert query.
129 129
 	 */
130
-	private function build_insert_sql( array $data, $unique ) {
130
+	private function build_insert_sql(array $data, $unique) {
131 131
 		global $wpdb;
132
-		$columns      = array_keys( $data );
133
-		$values       = array_values( $data );
134
-		$placeholders = array_map( array( $this, 'get_placeholder_for_column' ), $columns );
132
+		$columns      = array_keys($data);
133
+		$values       = array_values($data);
134
+		$placeholders = array_map(array($this, 'get_placeholder_for_column'), $columns);
135 135
 
136
-		$table_name = ! empty( $wpdb->actionscheduler_actions ) ? $wpdb->actionscheduler_actions : $wpdb->prefix . 'actionscheduler_actions';
136
+		$table_name = ! empty($wpdb->actionscheduler_actions) ? $wpdb->actionscheduler_actions : $wpdb->prefix.'actionscheduler_actions';
137 137
 
138
-		$column_sql      = '`' . implode( '`, `', $columns ) . '`';
139
-		$placeholder_sql = implode( ', ', $placeholders );
140
-		$where_clause    = $this->build_where_clause_for_insert( $data, $table_name, $unique );
138
+		$column_sql      = '`'.implode('`, `', $columns).'`';
139
+		$placeholder_sql = implode(', ', $placeholders);
140
+		$where_clause    = $this->build_where_clause_for_insert($data, $table_name, $unique);
141 141
 		// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $column_sql and $where_clause are already prepared. $placeholder_sql is hardcoded.
142 142
 		$insert_query = $wpdb->prepare(
143 143
 			"
@@ -160,18 +160,18 @@  discard block
 block discarded – undo
160 160
 	 *
161 161
 	 * @return string Where clause to be used with insert.
162 162
 	 */
163
-	private function build_where_clause_for_insert( $data, $table_name, $unique ) {
163
+	private function build_where_clause_for_insert($data, $table_name, $unique) {
164 164
 		global $wpdb;
165 165
 
166
-		if ( ! $unique ) {
166
+		if ( ! $unique) {
167 167
 			return 'SELECT NULL FROM DUAL';
168 168
 		}
169 169
 
170
-		$pending_statuses            = array(
170
+		$pending_statuses = array(
171 171
 			ActionScheduler_Store::STATUS_PENDING,
172 172
 			ActionScheduler_Store::STATUS_RUNNING,
173 173
 		);
174
-		$pending_status_placeholders = implode( ', ', array_fill( 0, count( $pending_statuses ), '%s' ) );
174
+		$pending_status_placeholders = implode(', ', array_fill(0, count($pending_statuses), '%s'));
175 175
 		// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $pending_status_placeholders is hardcoded.
176 176
 		$where_clause = $wpdb->prepare(
177 177
 			"
@@ -190,7 +190,7 @@  discard block
 block discarded – undo
190 190
 		);
191 191
 		// phpcs:enable
192 192
 
193
-		return "$where_clause" . ' LIMIT 1';
193
+		return "$where_clause".' LIMIT 1';
194 194
 	}
195 195
 
196 196
 	/**
@@ -200,7 +200,7 @@  discard block
 block discarded – undo
200 200
 	 *
201 201
 	 * @return string Placeholder to use for given column.
202 202
 	 */
203
-	private function get_placeholder_for_column( $column_name ) {
203
+	private function get_placeholder_for_column($column_name) {
204 204
 		$string_columns = array(
205 205
 			'hook',
206 206
 			'status',
@@ -213,7 +213,7 @@  discard block
 block discarded – undo
213 213
 			'extended_args',
214 214
 		);
215 215
 
216
-		return in_array( $column_name, $string_columns ) ? '%s' : '%d';
216
+		return in_array($column_name, $string_columns) ? '%s' : '%d';
217 217
 	}
218 218
 
219 219
 	/**
@@ -222,8 +222,8 @@  discard block
 block discarded – undo
222 222
 	 * @param string $args JSON encoded action args.
223 223
 	 * @return string
224 224
 	 */
225
-	protected function hash_args( $args ) {
226
-		return md5( $args );
225
+	protected function hash_args($args) {
226
+		return md5($args);
227 227
 	}
228 228
 
229 229
 	/**
@@ -232,12 +232,12 @@  discard block
 block discarded – undo
232 232
 	 * @param array $args Action args.
233 233
 	 * @return string
234 234
 	 */
235
-	protected function get_args_for_query( $args ) {
236
-		$encoded = wp_json_encode( $args );
237
-		if ( strlen( $encoded ) <= static::$max_index_length ) {
235
+	protected function get_args_for_query($args) {
236
+		$encoded = wp_json_encode($args);
237
+		if (strlen($encoded) <= static::$max_index_length) {
238 238
 			return $encoded;
239 239
 		}
240
-		return $this->hash_args( $encoded );
240
+		return $this->hash_args($encoded);
241 241
 	}
242 242
 	/**
243 243
 	 * Get a group's ID based on its name/slug.
@@ -247,15 +247,15 @@  discard block
 block discarded – undo
247 247
 	 *
248 248
 	 * @return int The group's ID, if it exists or is created, or 0 if it does not exist and is not created.
249 249
 	 */
250
-	protected function get_group_id( $slug, $create_if_not_exists = true ) {
251
-		if ( empty( $slug ) ) {
250
+	protected function get_group_id($slug, $create_if_not_exists = true) {
251
+		if (empty($slug)) {
252 252
 			return 0;
253 253
 		}
254 254
 		/** @var \wpdb $wpdb */
255 255
 		global $wpdb;
256
-		$group_id = (int) $wpdb->get_var( $wpdb->prepare( "SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug ) );
257
-		if ( empty( $group_id ) && $create_if_not_exists ) {
258
-			$group_id = $this->create_group( $slug );
256
+		$group_id = (int) $wpdb->get_var($wpdb->prepare("SELECT group_id FROM {$wpdb->actionscheduler_groups} WHERE slug=%s", $slug));
257
+		if (empty($group_id) && $create_if_not_exists) {
258
+			$group_id = $this->create_group($slug);
259 259
 		}
260 260
 
261 261
 		return $group_id;
@@ -268,10 +268,10 @@  discard block
 block discarded – undo
268 268
 	 *
269 269
 	 * @return int Group ID.
270 270
 	 */
271
-	protected function create_group( $slug ) {
271
+	protected function create_group($slug) {
272 272
 		/** @var \wpdb $wpdb */
273 273
 		global $wpdb;
274
-		$wpdb->insert( $wpdb->actionscheduler_groups, array( 'slug' => $slug ) );
274
+		$wpdb->insert($wpdb->actionscheduler_groups, array('slug' => $slug));
275 275
 
276 276
 		return (int) $wpdb->insert_id;
277 277
 	}
@@ -283,7 +283,7 @@  discard block
 block discarded – undo
283 283
 	 *
284 284
 	 * @return ActionScheduler_Action
285 285
 	 */
286
-	public function fetch_action( $action_id ) {
286
+	public function fetch_action($action_id) {
287 287
 		/** @var \wpdb $wpdb */
288 288
 		global $wpdb;
289 289
 		$data = $wpdb->get_row(
@@ -293,13 +293,13 @@  discard block
 block discarded – undo
293 293
 			)
294 294
 		);
295 295
 
296
-		if ( empty( $data ) ) {
296
+		if (empty($data)) {
297 297
 			return $this->get_null_action();
298 298
 		}
299 299
 
300
-		if ( ! empty( $data->extended_args ) ) {
300
+		if ( ! empty($data->extended_args)) {
301 301
 			$data->args = $data->extended_args;
302
-			unset( $data->extended_args );
302
+			unset($data->extended_args);
303 303
 		}
304 304
 
305 305
 		// Convert NULL dates to zero dates.
@@ -309,16 +309,16 @@  discard block
 block discarded – undo
309 309
 			'last_attempt_gmt',
310 310
 			'last_attempt_gmt',
311 311
 		);
312
-		foreach ( $date_fields as $date_field ) {
313
-			if ( $data->$date_field === null ) {
312
+		foreach ($date_fields as $date_field) {
313
+			if ($data->$date_field === null) {
314 314
 				$data->$date_field = ActionScheduler_StoreSchema::DEFAULT_DATE;
315 315
 			}
316 316
 		}
317 317
 
318 318
 		try {
319
-			$action = $this->make_action_from_db_record( $data );
320
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
321
-			do_action( 'action_scheduler_failed_fetch_action', $action_id, $exception );
319
+			$action = $this->make_action_from_db_record($data);
320
+		} catch (ActionScheduler_InvalidActionException $exception) {
321
+			do_action('action_scheduler_failed_fetch_action', $action_id, $exception);
322 322
 			return $this->get_null_action();
323 323
 		}
324 324
 
@@ -341,21 +341,21 @@  discard block
 block discarded – undo
341 341
 	 *
342 342
 	 * @return ActionScheduler_Action|ActionScheduler_CanceledAction|ActionScheduler_FinishedAction
343 343
 	 */
344
-	protected function make_action_from_db_record( $data ) {
344
+	protected function make_action_from_db_record($data) {
345 345
 
346 346
 		$hook     = $data->hook;
347
-		$args     = json_decode( $data->args, true );
348
-		$schedule = unserialize( $data->schedule ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
347
+		$args     = json_decode($data->args, true);
348
+		$schedule = unserialize($data->schedule); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_unserialize
349 349
 
350
-		$this->validate_args( $args, $data->action_id );
351
-		$this->validate_schedule( $schedule, $data->action_id );
350
+		$this->validate_args($args, $data->action_id);
351
+		$this->validate_schedule($schedule, $data->action_id);
352 352
 
353
-		if ( empty( $schedule ) ) {
353
+		if (empty($schedule)) {
354 354
 			$schedule = new ActionScheduler_NullSchedule();
355 355
 		}
356 356
 		$group = $data->group ? $data->group : '';
357 357
 
358
-		return ActionScheduler::factory()->get_stored_action( $data->status, $data->hook, $args, $schedule, $group );
358
+		return ActionScheduler::factory()->get_stored_action($data->status, $data->hook, $args, $schedule, $group);
359 359
 	}
360 360
 
361 361
 	/**
@@ -369,10 +369,10 @@  discard block
 block discarded – undo
369 369
 	 * @return string SQL statement already properly escaped.
370 370
 	 * @throws InvalidArgumentException If the query is invalid.
371 371
 	 */
372
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
372
+	protected function get_query_actions_sql(array $query, $select_or_count = 'select') {
373 373
 
374
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
375
-			throw new InvalidArgumentException( __( 'Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler' ) );
374
+		if ( ! in_array($select_or_count, array('select', 'count'), true)) {
375
+			throw new InvalidArgumentException(__('Invalid value for select or count parameter. Cannot query actions.', 'action-scheduler'));
376 376
 		}
377 377
 
378 378
 		$query = wp_parse_args(
@@ -398,42 +398,42 @@  discard block
 block discarded – undo
398 398
 		/** @var \wpdb $wpdb */
399 399
 		global $wpdb;
400 400
 
401
-		$db_server_info = is_callable( array( $wpdb, 'db_server_info' ) ) ? $wpdb->db_server_info() : $wpdb->db_version();
402
-		if ( false !== strpos( $db_server_info, 'MariaDB' ) ) {
401
+		$db_server_info = is_callable(array($wpdb, 'db_server_info')) ? $wpdb->db_server_info() : $wpdb->db_version();
402
+		if (false !== strpos($db_server_info, 'MariaDB')) {
403 403
 			$supports_json = version_compare(
404
-				PHP_VERSION_ID >= 80016 ? $wpdb->db_version() : preg_replace( '/[^0-9.].*/', '', str_replace( '5.5.5-', '', $db_server_info ) ),
404
+				PHP_VERSION_ID >= 80016 ? $wpdb->db_version() : preg_replace('/[^0-9.].*/', '', str_replace('5.5.5-', '', $db_server_info)),
405 405
 				'10.2',
406 406
 				'>='
407 407
 			);
408 408
 		} else {
409
-			$supports_json = version_compare( $wpdb->db_version(), '5.7', '>=' );
409
+			$supports_json = version_compare($wpdb->db_version(), '5.7', '>=');
410 410
 		}
411 411
 
412
-		$sql        = ( 'count' === $select_or_count ) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
412
+		$sql        = ('count' === $select_or_count) ? 'SELECT count(a.action_id)' : 'SELECT a.action_id';
413 413
 		$sql       .= " FROM {$wpdb->actionscheduler_actions} a";
414 414
 		$sql_params = array();
415 415
 
416
-		if ( ! empty( $query['group'] ) || 'group' === $query['orderby'] ) {
416
+		if ( ! empty($query['group']) || 'group' === $query['orderby']) {
417 417
 			$sql .= " LEFT JOIN {$wpdb->actionscheduler_groups} g ON g.group_id=a.group_id";
418 418
 		}
419 419
 
420 420
 		$sql .= ' WHERE 1=1';
421 421
 
422
-		if ( ! empty( $query['group'] ) ) {
422
+		if ( ! empty($query['group'])) {
423 423
 			$sql         .= ' AND g.slug=%s';
424 424
 			$sql_params[] = $query['group'];
425 425
 		}
426 426
 
427
-		if ( ! empty( $query['hook'] ) ) {
427
+		if ( ! empty($query['hook'])) {
428 428
 			$sql         .= ' AND a.hook=%s';
429 429
 			$sql_params[] = $query['hook'];
430 430
 		}
431 431
 
432
-		if ( $query['args'] !== null ) {
433
-			switch ( $query['partial_args_matching'] ) {
432
+		if ($query['args'] !== null) {
433
+			switch ($query['partial_args_matching']) {
434 434
 				case 'json':
435
-					if ( ! $supports_json ) {
436
-						throw new \RuntimeException( __( 'JSON partial matching not supported in your environment. Please check your MySQL/MariaDB version.', 'action-scheduler' ) );
435
+					if ( ! $supports_json) {
436
+						throw new \RuntimeException(__('JSON partial matching not supported in your environment. Please check your MySQL/MariaDB version.', 'action-scheduler'));
437 437
 					}
438 438
 					$supported_types = array(
439 439
 						'integer' => '%d',
@@ -441,84 +441,84 @@  discard block
 block discarded – undo
441 441
 						'double'  => '%f',
442 442
 						'string'  => '%s',
443 443
 					);
444
-					foreach ( $query['args'] as $key => $value ) {
445
-						$value_type = gettype( $value );
446
-						if ( 'boolean' === $value_type ) {
444
+					foreach ($query['args'] as $key => $value) {
445
+						$value_type = gettype($value);
446
+						if ('boolean' === $value_type) {
447 447
 							$value = $value ? 'true' : 'false';
448 448
 						}
449
-						$placeholder = isset( $supported_types[ $value_type ] ) ? $supported_types[ $value_type ] : false;
450
-						if ( ! $placeholder ) {
449
+						$placeholder = isset($supported_types[$value_type]) ? $supported_types[$value_type] : false;
450
+						if ( ! $placeholder) {
451 451
 							throw new \RuntimeException(
452 452
 								sprintf(
453 453
 								/* translators: %s: provided value type */
454
-									__( 'The value type for the JSON partial matching is not supported. Must be either integer, boolean, double or string. %s type provided.', 'action-scheduler' ),
454
+									__('The value type for the JSON partial matching is not supported. Must be either integer, boolean, double or string. %s type provided.', 'action-scheduler'),
455 455
 									$value_type
456 456
 								)
457 457
 							);
458 458
 						}
459
-						$sql         .= ' AND JSON_EXTRACT(a.args, %s)=' . $placeholder;
460
-						$sql_params[] = '$.' . $key;
459
+						$sql         .= ' AND JSON_EXTRACT(a.args, %s)='.$placeholder;
460
+						$sql_params[] = '$.'.$key;
461 461
 						$sql_params[] = $value;
462 462
 					}
463 463
 					break;
464 464
 				case 'like':
465
-					foreach ( $query['args'] as $key => $value ) {
465
+					foreach ($query['args'] as $key => $value) {
466 466
 						$sql         .= ' AND a.args LIKE %s';
467
-						$json_partial = $wpdb->esc_like( trim( json_encode( array( $key => $value ) ), '{}' ) );
467
+						$json_partial = $wpdb->esc_like(trim(json_encode(array($key => $value)), '{}'));
468 468
 						$sql_params[] = "%{$json_partial}%";
469 469
 					}
470 470
 					break;
471 471
 				case 'off':
472 472
 					$sql         .= ' AND a.args=%s';
473
-					$sql_params[] = $this->get_args_for_query( $query['args'] );
473
+					$sql_params[] = $this->get_args_for_query($query['args']);
474 474
 					break;
475 475
 				default:
476
-					throw new \RuntimeException( __( 'Unknown partial args matching value.', 'action-scheduler' ) );
476
+					throw new \RuntimeException(__('Unknown partial args matching value.', 'action-scheduler'));
477 477
 			}
478 478
 		}
479 479
 
480
-		if ( $query['status'] ) {
480
+		if ($query['status']) {
481 481
 			$statuses     = (array) $query['status'];
482
-			$placeholders = array_fill( 0, count( $statuses ), '%s' );
483
-			$sql         .= ' AND a.status IN (' . join( ', ', $placeholders ) . ')';
484
-			$sql_params   = array_merge( $sql_params, array_values( $statuses ) );
482
+			$placeholders = array_fill(0, count($statuses), '%s');
483
+			$sql         .= ' AND a.status IN ('.join(', ', $placeholders).')';
484
+			$sql_params   = array_merge($sql_params, array_values($statuses));
485 485
 		}
486 486
 
487
-		if ( $query['date'] instanceof \DateTime ) {
487
+		if ($query['date'] instanceof \DateTime) {
488 488
 			$date = clone $query['date'];
489
-			$date->setTimezone( new \DateTimeZone( 'UTC' ) );
490
-			$date_string  = $date->format( 'Y-m-d H:i:s' );
491
-			$comparator   = $this->validate_sql_comparator( $query['date_compare'] );
489
+			$date->setTimezone(new \DateTimeZone('UTC'));
490
+			$date_string  = $date->format('Y-m-d H:i:s');
491
+			$comparator   = $this->validate_sql_comparator($query['date_compare']);
492 492
 			$sql         .= " AND a.scheduled_date_gmt $comparator %s";
493 493
 			$sql_params[] = $date_string;
494 494
 		}
495 495
 
496
-		if ( $query['modified'] instanceof \DateTime ) {
496
+		if ($query['modified'] instanceof \DateTime) {
497 497
 			$modified = clone $query['modified'];
498
-			$modified->setTimezone( new \DateTimeZone( 'UTC' ) );
499
-			$date_string  = $modified->format( 'Y-m-d H:i:s' );
500
-			$comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
498
+			$modified->setTimezone(new \DateTimeZone('UTC'));
499
+			$date_string  = $modified->format('Y-m-d H:i:s');
500
+			$comparator   = $this->validate_sql_comparator($query['modified_compare']);
501 501
 			$sql         .= " AND a.last_attempt_gmt $comparator %s";
502 502
 			$sql_params[] = $date_string;
503 503
 		}
504 504
 
505
-		if ( true === $query['claimed'] ) {
505
+		if (true === $query['claimed']) {
506 506
 			$sql .= ' AND a.claim_id != 0';
507
-		} elseif ( false === $query['claimed'] ) {
507
+		} elseif (false === $query['claimed']) {
508 508
 			$sql .= ' AND a.claim_id = 0';
509
-		} elseif ( $query['claimed'] !== null ) {
509
+		} elseif ($query['claimed'] !== null) {
510 510
 			$sql         .= ' AND a.claim_id = %d';
511 511
 			$sql_params[] = $query['claimed'];
512 512
 		}
513 513
 
514
-		if ( ! empty( $query['search'] ) ) {
514
+		if ( ! empty($query['search'])) {
515 515
 			$sql .= ' AND (a.hook LIKE %s OR (a.extended_args IS NULL AND a.args LIKE %s) OR a.extended_args LIKE %s';
516
-			for ( $i = 0; $i < 3; $i++ ) {
517
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
516
+			for ($i = 0; $i < 3; $i++) {
517
+				$sql_params[] = sprintf('%%%s%%', $query['search']);
518 518
 			}
519 519
 
520 520
 			$search_claim_id = (int) $query['search'];
521
-			if ( $search_claim_id ) {
521
+			if ($search_claim_id) {
522 522
 				$sql         .= ' OR a.claim_id = %d';
523 523
 				$sql_params[] = $search_claim_id;
524 524
 			}
@@ -526,13 +526,13 @@  discard block
 block discarded – undo
526 526
 			$sql .= ')';
527 527
 		}
528 528
 
529
-		if ( 'select' === $select_or_count ) {
530
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
529
+		if ('select' === $select_or_count) {
530
+			if ('ASC' === strtoupper($query['order'])) {
531 531
 				$order = 'ASC';
532 532
 			} else {
533 533
 				$order = 'DESC';
534 534
 			}
535
-			switch ( $query['orderby'] ) {
535
+			switch ($query['orderby']) {
536 536
 				case 'hook':
537 537
 					$sql .= " ORDER BY a.hook $order";
538 538
 					break;
@@ -553,15 +553,15 @@  discard block
 block discarded – undo
553 553
 					break;
554 554
 			}
555 555
 
556
-			if ( $query['per_page'] > 0 ) {
556
+			if ($query['per_page'] > 0) {
557 557
 				$sql         .= ' LIMIT %d, %d';
558 558
 				$sql_params[] = $query['offset'];
559 559
 				$sql_params[] = $query['per_page'];
560 560
 			}
561 561
 		}
562 562
 
563
-		if ( ! empty( $sql_params ) ) {
564
-			$sql = $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
563
+		if ( ! empty($sql_params)) {
564
+			$sql = $wpdb->prepare($sql, $sql_params); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
565 565
 		}
566 566
 
567 567
 		return $sql;
@@ -579,13 +579,13 @@  discard block
 block discarded – undo
579 579
 	 *
580 580
 	 * @return string|array|null The IDs of actions matching the query. Null on failure.
581 581
 	 */
582
-	public function query_actions( $query = array(), $query_type = 'select' ) {
582
+	public function query_actions($query = array(), $query_type = 'select') {
583 583
 		/** @var wpdb $wpdb */
584 584
 		global $wpdb;
585 585
 
586
-		$sql = $this->get_query_actions_sql( $query, $query_type );
586
+		$sql = $this->get_query_actions_sql($query, $query_type);
587 587
 
588
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
588
+		return ('count' === $query_type) ? $wpdb->get_var($sql) : $wpdb->get_col($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoSql, WordPress.DB.DirectDatabaseQuery.NoCaching
589 589
 	}
590 590
 
591 591
 	/**
@@ -603,10 +603,10 @@  discard block
 block discarded – undo
603 603
 		$actions_count_by_status = array();
604 604
 		$action_stati_and_labels = $this->get_status_labels();
605 605
 
606
-		foreach ( $wpdb->get_results( $sql ) as $action_data ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
606
+		foreach ($wpdb->get_results($sql) as $action_data) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
607 607
 			// Ignore any actions with invalid status.
608
-			if ( array_key_exists( $action_data->status, $action_stati_and_labels ) ) {
609
-				$actions_count_by_status[ $action_data->status ] = $action_data->count;
608
+			if (array_key_exists($action_data->status, $action_stati_and_labels)) {
609
+				$actions_count_by_status[$action_data->status] = $action_data->count;
610 610
 			}
611 611
 		}
612 612
 
@@ -621,22 +621,22 @@  discard block
 block discarded – undo
621 621
 	 * @return void
622 622
 	 * @throws \InvalidArgumentException If the action update failed.
623 623
 	 */
624
-	public function cancel_action( $action_id ) {
624
+	public function cancel_action($action_id) {
625 625
 		/** @var \wpdb $wpdb */
626 626
 		global $wpdb;
627 627
 
628 628
 		$updated = $wpdb->update(
629 629
 			$wpdb->actionscheduler_actions,
630
-			array( 'status' => self::STATUS_CANCELED ),
631
-			array( 'action_id' => $action_id ),
632
-			array( '%s' ),
633
-			array( '%d' )
630
+			array('status' => self::STATUS_CANCELED),
631
+			array('action_id' => $action_id),
632
+			array('%s'),
633
+			array('%d')
634 634
 		);
635
-		if ( false === $updated ) {
635
+		if (false === $updated) {
636 636
 			/* translators: %s: action ID */
637
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
637
+			throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
638 638
 		}
639
-		do_action( 'action_scheduler_canceled_action', $action_id );
639
+		do_action('action_scheduler_canceled_action', $action_id);
640 640
 	}
641 641
 
642 642
 	/**
@@ -648,8 +648,8 @@  discard block
 block discarded – undo
648 648
 	 *
649 649
 	 * @return void
650 650
 	 */
651
-	public function cancel_actions_by_hook( $hook ) {
652
-		$this->bulk_cancel_actions( array( 'hook' => $hook ) );
651
+	public function cancel_actions_by_hook($hook) {
652
+		$this->bulk_cancel_actions(array('hook' => $hook));
653 653
 	}
654 654
 
655 655
 	/**
@@ -659,8 +659,8 @@  discard block
 block discarded – undo
659 659
 	 *
660 660
 	 * @return void
661 661
 	 */
662
-	public function cancel_actions_by_group( $group ) {
663
-		$this->bulk_cancel_actions( array( 'group' => $group ) );
662
+	public function cancel_actions_by_group($group) {
663
+		$this->bulk_cancel_actions(array('group' => $group));
664 664
 	}
665 665
 
666 666
 	/**
@@ -670,16 +670,16 @@  discard block
 block discarded – undo
670 670
 	 *
671 671
 	 * @param array $query_args Query parameters.
672 672
 	 */
673
-	protected function bulk_cancel_actions( $query_args ) {
673
+	protected function bulk_cancel_actions($query_args) {
674 674
 		/** @var \wpdb $wpdb */
675 675
 		global $wpdb;
676 676
 
677
-		if ( ! is_array( $query_args ) ) {
677
+		if ( ! is_array($query_args)) {
678 678
 			return;
679 679
 		}
680 680
 
681 681
 		// Don't cancel actions that are already canceled.
682
-		if ( isset( $query_args['status'] ) && self::STATUS_CANCELED === $query_args['status'] ) {
682
+		if (isset($query_args['status']) && self::STATUS_CANCELED === $query_args['status']) {
683 683
 			return;
684 684
 		}
685 685
 
@@ -693,16 +693,16 @@  discard block
 block discarded – undo
693 693
 			)
694 694
 		);
695 695
 
696
-		while ( $action_ids ) {
697
-			$action_ids = $this->query_actions( $query_args );
698
-			if ( empty( $action_ids ) ) {
696
+		while ($action_ids) {
697
+			$action_ids = $this->query_actions($query_args);
698
+			if (empty($action_ids)) {
699 699
 				break;
700 700
 			}
701 701
 
702
-			$format     = array_fill( 0, count( $action_ids ), '%d' );
703
-			$query_in   = '(' . implode( ',', $format ) . ')';
702
+			$format     = array_fill(0, count($action_ids), '%d');
703
+			$query_in   = '('.implode(',', $format).')';
704 704
 			$parameters = $action_ids;
705
-			array_unshift( $parameters, self::STATUS_CANCELED );
705
+			array_unshift($parameters, self::STATUS_CANCELED);
706 706
 
707 707
 			$wpdb->query(
708 708
 				$wpdb->prepare(
@@ -711,7 +711,7 @@  discard block
 block discarded – undo
711 711
 				)
712 712
 			);
713 713
 
714
-			do_action( 'action_scheduler_bulk_cancel_actions', $action_ids );
714
+			do_action('action_scheduler_bulk_cancel_actions', $action_ids);
715 715
 		}
716 716
 	}
717 717
 
@@ -721,14 +721,14 @@  discard block
 block discarded – undo
721 721
 	 * @param int $action_id Action ID.
722 722
 	 * @throws \InvalidArgumentException If the action deletion failed.
723 723
 	 */
724
-	public function delete_action( $action_id ) {
724
+	public function delete_action($action_id) {
725 725
 		/** @var \wpdb $wpdb */
726 726
 		global $wpdb;
727
-		$deleted = $wpdb->delete( $wpdb->actionscheduler_actions, array( 'action_id' => $action_id ), array( '%d' ) );
728
-		if ( empty( $deleted ) ) {
729
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
727
+		$deleted = $wpdb->delete($wpdb->actionscheduler_actions, array('action_id' => $action_id), array('%d'));
728
+		if (empty($deleted)) {
729
+			throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
730 730
 		}
731
-		do_action( 'action_scheduler_deleted_action', $action_id );
731
+		do_action('action_scheduler_deleted_action', $action_id);
732 732
 	}
733 733
 
734 734
 	/**
@@ -738,9 +738,9 @@  discard block
 block discarded – undo
738 738
 	 *
739 739
 	 * @return \DateTime The local date the action is scheduled to run, or the date that it ran.
740 740
 	 */
741
-	public function get_date( $action_id ) {
742
-		$date = $this->get_date_gmt( $action_id );
743
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
741
+	public function get_date($action_id) {
742
+		$date = $this->get_date_gmt($action_id);
743
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
744 744
 		return $date;
745 745
 	}
746 746
 
@@ -752,17 +752,17 @@  discard block
 block discarded – undo
752 752
 	 * @throws \InvalidArgumentException If action cannot be identified.
753 753
 	 * @return \DateTime The GMT date the action is scheduled to run, or the date that it ran.
754 754
 	 */
755
-	protected function get_date_gmt( $action_id ) {
755
+	protected function get_date_gmt($action_id) {
756 756
 		/** @var \wpdb $wpdb */
757 757
 		global $wpdb;
758
-		$record = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id ) );
759
-		if ( empty( $record ) ) {
760
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
758
+		$record = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d", $action_id));
759
+		if (empty($record)) {
760
+			throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
761 761
 		}
762
-		if ( self::STATUS_PENDING === $record->status ) {
763
-			return as_get_datetime_object( $record->scheduled_date_gmt );
762
+		if (self::STATUS_PENDING === $record->status) {
763
+			return as_get_datetime_object($record->scheduled_date_gmt);
764 764
 		} else {
765
-			return as_get_datetime_object( $record->last_attempt_gmt );
765
+			return as_get_datetime_object($record->last_attempt_gmt);
766 766
 		}
767 767
 	}
768 768
 
@@ -776,15 +776,15 @@  discard block
 block discarded – undo
776 776
 	 *
777 777
 	 * @return ActionScheduler_ActionClaim
778 778
 	 */
779
-	public function stake_claim( $max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
779
+	public function stake_claim($max_actions = 10, \DateTime $before_date = null, $hooks = array(), $group = '') {
780 780
 		$claim_id = $this->generate_claim_id();
781 781
 
782 782
 		$this->claim_before_date = $before_date;
783
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
784
-		$action_ids              = $this->find_actions_by_claim_id( $claim_id );
783
+		$this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group);
784
+		$action_ids              = $this->find_actions_by_claim_id($claim_id);
785 785
 		$this->claim_before_date = null;
786 786
 
787
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
787
+		return new ActionScheduler_ActionClaim($claim_id, $action_ids);
788 788
 	}
789 789
 
790 790
 	/**
@@ -796,7 +796,7 @@  discard block
 block discarded – undo
796 796
 		/** @var \wpdb $wpdb */
797 797
 		global $wpdb;
798 798
 		$now = as_get_datetime_object();
799
-		$wpdb->insert( $wpdb->actionscheduler_claims, array( 'date_created_gmt' => $now->format( 'Y-m-d H:i:s' ) ) );
799
+		$wpdb->insert($wpdb->actionscheduler_claims, array('date_created_gmt' => $now->format('Y-m-d H:i:s')));
800 800
 
801 801
 		return $wpdb->insert_id;
802 802
 	}
@@ -814,7 +814,7 @@  discard block
 block discarded – undo
814 814
 	 * @throws \InvalidArgumentException Throws InvalidArgumentException if group doesn't exist.
815 815
 	 * @throws \RuntimeException Throws RuntimeException if unable to claim action.
816 816
 	 */
817
-	protected function claim_actions( $claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '' ) {
817
+	protected function claim_actions($claim_id, $limit, \DateTime $before_date = null, $hooks = array(), $group = '') {
818 818
 		/** @var \wpdb $wpdb */
819 819
 		global $wpdb;
820 820
 
@@ -825,28 +825,28 @@  discard block
 block discarded – undo
825 825
 		$update = "UPDATE {$wpdb->actionscheduler_actions} SET claim_id=%d, last_attempt_gmt=%s, last_attempt_local=%s";
826 826
 		$params = array(
827 827
 			$claim_id,
828
-			$now->format( 'Y-m-d H:i:s' ),
829
-			current_time( 'mysql' ),
828
+			$now->format('Y-m-d H:i:s'),
829
+			current_time('mysql'),
830 830
 		);
831 831
 
832 832
 		$where    = 'WHERE claim_id = 0 AND scheduled_date_gmt <= %s AND status=%s';
833
-		$params[] = $date->format( 'Y-m-d H:i:s' );
833
+		$params[] = $date->format('Y-m-d H:i:s');
834 834
 		$params[] = self::STATUS_PENDING;
835 835
 
836
-		if ( ! empty( $hooks ) ) {
837
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
838
-			$where       .= ' AND hook IN (' . join( ', ', $placeholders ) . ')';
839
-			$params       = array_merge( $params, array_values( $hooks ) );
836
+		if ( ! empty($hooks)) {
837
+			$placeholders = array_fill(0, count($hooks), '%s');
838
+			$where       .= ' AND hook IN ('.join(', ', $placeholders).')';
839
+			$params       = array_merge($params, array_values($hooks));
840 840
 		}
841 841
 
842
-		if ( ! empty( $group ) ) {
842
+		if ( ! empty($group)) {
843 843
 
844
-			$group_id = $this->get_group_id( $group, false );
844
+			$group_id = $this->get_group_id($group, false);
845 845
 
846 846
 			// throw exception if no matching group found, this matches ActionScheduler_wpPostStore's behaviour.
847
-			if ( empty( $group_id ) ) {
847
+			if (empty($group_id)) {
848 848
 				/* translators: %s: group name */
849
-				throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
849
+				throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'action-scheduler'), $group));
850 850
 			}
851 851
 
852 852
 			$where   .= ' AND group_id = %d';
@@ -860,13 +860,13 @@  discard block
 block discarded – undo
860 860
 		 *
861 861
 		 * @param string $order_by_sql
862 862
 		 */
863
-		$order    = apply_filters( 'action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC' );
863
+		$order    = apply_filters('action_scheduler_claim_actions_order_by', 'ORDER BY attempts ASC, scheduled_date_gmt ASC, action_id ASC');
864 864
 		$params[] = $limit;
865 865
 
866
-		$sql           = $wpdb->prepare( "{$update} {$where} {$order} LIMIT %d", $params ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
867
-		$rows_affected = $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
868
-		if ( false === $rows_affected ) {
869
-			throw new \RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
866
+		$sql           = $wpdb->prepare("{$update} {$where} {$order} LIMIT %d", $params); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders
867
+		$rows_affected = $wpdb->query($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
868
+		if (false === $rows_affected) {
869
+			throw new \RuntimeException(__('Unable to claim actions. Database error.', 'action-scheduler'));
870 870
 		}
871 871
 
872 872
 		return (int) $rows_affected;
@@ -881,9 +881,9 @@  discard block
 block discarded – undo
881 881
 		global $wpdb;
882 882
 
883 883
 		$sql = "SELECT COUNT(DISTINCT claim_id) FROM {$wpdb->actionscheduler_actions} WHERE claim_id != 0 AND status IN ( %s, %s)";
884
-		$sql = $wpdb->prepare( $sql, array( self::STATUS_PENDING, self::STATUS_RUNNING ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
884
+		$sql = $wpdb->prepare($sql, array(self::STATUS_PENDING, self::STATUS_RUNNING)); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
885 885
 
886
-		return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
886
+		return (int) $wpdb->get_var($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
887 887
 	}
888 888
 
889 889
 	/**
@@ -892,14 +892,14 @@  discard block
 block discarded – undo
892 892
 	 * @param string $action_id Action ID.
893 893
 	 * @return mixed
894 894
 	 */
895
-	public function get_claim_id( $action_id ) {
895
+	public function get_claim_id($action_id) {
896 896
 		/** @var \wpdb $wpdb */
897 897
 		global $wpdb;
898 898
 
899 899
 		$sql = "SELECT claim_id FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
900
-		$sql = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
900
+		$sql = $wpdb->prepare($sql, $action_id); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
901 901
 
902
-		return (int) $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
902
+		return (int) $wpdb->get_var($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
903 903
 	}
904 904
 
905 905
 	/**
@@ -908,13 +908,13 @@  discard block
 block discarded – undo
908 908
 	 * @param  int $claim_id Claim ID.
909 909
 	 * @return int[]
910 910
 	 */
911
-	public function find_actions_by_claim_id( $claim_id ) {
911
+	public function find_actions_by_claim_id($claim_id) {
912 912
 		/** @var \wpdb $wpdb */
913 913
 		global $wpdb;
914 914
 
915 915
 		$action_ids  = array();
916
-		$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
917
-		$cut_off     = $before_date->format( 'Y-m-d H:i:s' );
916
+		$before_date = isset($this->claim_before_date) ? $this->claim_before_date : as_get_datetime_object();
917
+		$cut_off     = $before_date->format('Y-m-d H:i:s');
918 918
 
919 919
 		$sql = $wpdb->prepare(
920 920
 			"SELECT action_id, scheduled_date_gmt FROM {$wpdb->actionscheduler_actions} WHERE claim_id = %d",
@@ -923,9 +923,9 @@  discard block
 block discarded – undo
923 923
 
924 924
 		// Verify that the scheduled date for each action is within the expected bounds (in some unusual
925 925
 		// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
926
-		foreach ( $wpdb->get_results( $sql ) as $claimed_action ) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
927
-			if ( $claimed_action->scheduled_date_gmt <= $cut_off ) {
928
-				$action_ids[] = absint( $claimed_action->action_id );
926
+		foreach ($wpdb->get_results($sql) as $claimed_action) { // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
927
+			if ($claimed_action->scheduled_date_gmt <= $cut_off) {
928
+				$action_ids[] = absint($claimed_action->action_id);
929 929
 			}
930 930
 		}
931 931
 
@@ -937,11 +937,11 @@  discard block
 block discarded – undo
937 937
 	 *
938 938
 	 * @param ActionScheduler_ActionClaim $claim Claim object.
939 939
 	 */
940
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
940
+	public function release_claim(ActionScheduler_ActionClaim $claim) {
941 941
 		/** @var \wpdb $wpdb */
942 942
 		global $wpdb;
943
-		$wpdb->update( $wpdb->actionscheduler_actions, array( 'claim_id' => 0 ), array( 'claim_id' => $claim->get_id() ), array( '%d' ), array( '%d' ) );
944
-		$wpdb->delete( $wpdb->actionscheduler_claims, array( 'claim_id' => $claim->get_id() ), array( '%d' ) );
943
+		$wpdb->update($wpdb->actionscheduler_actions, array('claim_id' => 0), array('claim_id' => $claim->get_id()), array('%d'), array('%d'));
944
+		$wpdb->delete($wpdb->actionscheduler_claims, array('claim_id' => $claim->get_id()), array('%d'));
945 945
 	}
946 946
 
947 947
 	/**
@@ -951,15 +951,15 @@  discard block
 block discarded – undo
951 951
 	 *
952 952
 	 * @return void
953 953
 	 */
954
-	public function unclaim_action( $action_id ) {
954
+	public function unclaim_action($action_id) {
955 955
 		/** @var \wpdb $wpdb */
956 956
 		global $wpdb;
957 957
 		$wpdb->update(
958 958
 			$wpdb->actionscheduler_actions,
959
-			array( 'claim_id' => 0 ),
960
-			array( 'action_id' => $action_id ),
961
-			array( '%s' ),
962
-			array( '%d' )
959
+			array('claim_id' => 0),
960
+			array('action_id' => $action_id),
961
+			array('%s'),
962
+			array('%d')
963 963
 		);
964 964
 	}
965 965
 
@@ -969,18 +969,18 @@  discard block
 block discarded – undo
969 969
 	 * @param int $action_id Action ID.
970 970
 	 * @throws \InvalidArgumentException Throw an exception if action was not updated.
971 971
 	 */
972
-	public function mark_failure( $action_id ) {
972
+	public function mark_failure($action_id) {
973 973
 		/** @var \wpdb $wpdb */
974 974
 		global $wpdb;
975 975
 		$updated = $wpdb->update(
976 976
 			$wpdb->actionscheduler_actions,
977
-			array( 'status' => self::STATUS_FAILED ),
978
-			array( 'action_id' => $action_id ),
979
-			array( '%s' ),
980
-			array( '%d' )
977
+			array('status' => self::STATUS_FAILED),
978
+			array('action_id' => $action_id),
979
+			array('%s'),
980
+			array('%d')
981 981
 		);
982
-		if ( empty( $updated ) ) {
983
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
982
+		if (empty($updated)) {
983
+			throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
984 984
 		}
985 985
 	}
986 986
 
@@ -991,13 +991,13 @@  discard block
 block discarded – undo
991 991
 	 *
992 992
 	 * @return void
993 993
 	 */
994
-	public function log_execution( $action_id ) {
994
+	public function log_execution($action_id) {
995 995
 		/** @var \wpdb $wpdb */
996 996
 		global $wpdb;
997 997
 
998 998
 		$sql = "UPDATE {$wpdb->actionscheduler_actions} SET attempts = attempts+1, status=%s, last_attempt_gmt = %s, last_attempt_local = %s WHERE action_id = %d";
999
-		$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time( 'mysql', true ), current_time( 'mysql' ), $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1000
-		$wpdb->query( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
999
+		$sql = $wpdb->prepare($sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1000
+		$wpdb->query($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1001 1001
 	}
1002 1002
 
1003 1003
 	/**
@@ -1008,22 +1008,22 @@  discard block
 block discarded – undo
1008 1008
 	 * @return void
1009 1009
 	 * @throws \InvalidArgumentException Throw an exception if action was not updated.
1010 1010
 	 */
1011
-	public function mark_complete( $action_id ) {
1011
+	public function mark_complete($action_id) {
1012 1012
 		/** @var \wpdb $wpdb */
1013 1013
 		global $wpdb;
1014 1014
 		$updated = $wpdb->update(
1015 1015
 			$wpdb->actionscheduler_actions,
1016 1016
 			array(
1017 1017
 				'status'             => self::STATUS_COMPLETE,
1018
-				'last_attempt_gmt'   => current_time( 'mysql', true ),
1019
-				'last_attempt_local' => current_time( 'mysql' ),
1018
+				'last_attempt_gmt'   => current_time('mysql', true),
1019
+				'last_attempt_local' => current_time('mysql'),
1020 1020
 			),
1021
-			array( 'action_id' => $action_id ),
1022
-			array( '%s' ),
1023
-			array( '%d' )
1021
+			array('action_id' => $action_id),
1022
+			array('%s'),
1023
+			array('%d')
1024 1024
 		);
1025
-		if ( empty( $updated ) ) {
1026
-			throw new \InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) ); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
1025
+		if (empty($updated)) {
1026
+			throw new \InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id)); //phpcs:ignore WordPress.WP.I18n.MissingTranslatorsComment
1027 1027
 		}
1028 1028
 
1029 1029
 		/**
@@ -1033,7 +1033,7 @@  discard block
 block discarded – undo
1033 1033
 		 *
1034 1034
 		 * @param int $action_id Action ID.
1035 1035
 		 */
1036
-		do_action( 'action_scheduler_completed_action', $action_id );
1036
+		do_action('action_scheduler_completed_action', $action_id);
1037 1037
 	}
1038 1038
 
1039 1039
 	/**
@@ -1045,17 +1045,17 @@  discard block
 block discarded – undo
1045 1045
 	 * @throws \InvalidArgumentException Throw an exception if not status was found for action_id.
1046 1046
 	 * @throws \RuntimeException Throw an exception if action status could not be retrieved.
1047 1047
 	 */
1048
-	public function get_status( $action_id ) {
1048
+	public function get_status($action_id) {
1049 1049
 		/** @var \wpdb $wpdb */
1050 1050
 		global $wpdb;
1051 1051
 		$sql    = "SELECT status FROM {$wpdb->actionscheduler_actions} WHERE action_id=%d";
1052
-		$sql    = $wpdb->prepare( $sql, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1053
-		$status = $wpdb->get_var( $sql ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1052
+		$sql    = $wpdb->prepare($sql, $action_id); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1053
+		$status = $wpdb->get_var($sql); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
1054 1054
 
1055
-		if ( null === $status ) {
1056
-			throw new \InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
1057
-		} elseif ( empty( $status ) ) {
1058
-			throw new \RuntimeException( __( 'Unknown status found for action.', 'action-scheduler' ) );
1055
+		if (null === $status) {
1056
+			throw new \InvalidArgumentException(__('Invalid action ID. No status found.', 'action-scheduler'));
1057
+		} elseif (empty($status)) {
1058
+			throw new \RuntimeException(__('Unknown status found for action.', 'action-scheduler'));
1059 1059
 		} else {
1060 1060
 			return $status;
1061 1061
 		}
Please login to merge, or discard this patch.
action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php 2 patches
Indentation   +238 added lines, -238 removed lines patch added patch discarded remove patch
@@ -4,243 +4,243 @@
 block discarded – undo
4 4
  * Class ActionScheduler_wpCommentLogger
5 5
  */
6 6
 class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
7
-	const AGENT = 'ActionScheduler';
8
-	const TYPE  = 'action_log';
9
-
10
-	/**
11
-	 * @param string   $action_id
12
-	 * @param string   $message
13
-	 * @param DateTime $date
14
-	 *
15
-	 * @return string The log entry ID
16
-	 */
17
-	public function log( $action_id, $message, DateTime $date = null ) {
18
-		if ( empty( $date ) ) {
19
-			$date = as_get_datetime_object();
20
-		} else {
21
-			$date = as_get_datetime_object( clone $date );
22
-		}
23
-		$comment_id = $this->create_wp_comment( $action_id, $message, $date );
24
-		return $comment_id;
25
-	}
26
-
27
-	protected function create_wp_comment( $action_id, $message, DateTime $date ) {
28
-
29
-		$comment_date_gmt = $date->format( 'Y-m-d H:i:s' );
30
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
31
-		$comment_data = array(
32
-			'comment_post_ID'  => $action_id,
33
-			'comment_date'     => $date->format( 'Y-m-d H:i:s' ),
34
-			'comment_date_gmt' => $comment_date_gmt,
35
-			'comment_author'   => self::AGENT,
36
-			'comment_content'  => $message,
37
-			'comment_agent'    => self::AGENT,
38
-			'comment_type'     => self::TYPE,
39
-		);
40
-		return wp_insert_comment( $comment_data );
41
-	}
42
-
43
-	/**
44
-	 * @param string $entry_id
45
-	 *
46
-	 * @return ActionScheduler_LogEntry
47
-	 */
48
-	public function get_entry( $entry_id ) {
49
-		$comment = $this->get_comment( $entry_id );
50
-		if ( empty( $comment ) || $comment->comment_type != self::TYPE ) {
51
-			return new ActionScheduler_NullLogEntry();
52
-		}
53
-
54
-		$date = as_get_datetime_object( $comment->comment_date_gmt );
55
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
56
-		return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date );
57
-	}
58
-
59
-	/**
60
-	 * @param string $action_id
61
-	 *
62
-	 * @return ActionScheduler_LogEntry[]
63
-	 */
64
-	public function get_logs( $action_id ) {
65
-		$status = 'all';
66
-		if ( get_post_status( $action_id ) == 'trash' ) {
67
-			$status = 'post-trashed';
68
-		}
69
-		$comments = get_comments(
70
-			array(
71
-				'post_id' => $action_id,
72
-				'orderby' => 'comment_date_gmt',
73
-				'order'   => 'ASC',
74
-				'type'    => self::TYPE,
75
-				'status'  => $status,
76
-			)
77
-		);
78
-		$logs     = array();
79
-		foreach ( $comments as $c ) {
80
-			$entry = $this->get_entry( $c );
81
-			if ( ! empty( $entry ) ) {
82
-				$logs[] = $entry;
83
-			}
84
-		}
85
-		return $logs;
86
-	}
87
-
88
-	protected function get_comment( $comment_id ) {
89
-		return get_comment( $comment_id );
90
-	}
91
-
92
-	/**
93
-	 * @param WP_Comment_Query $query
94
-	 */
95
-	public function filter_comment_queries( $query ) {
96
-		foreach ( array( 'ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID' ) as $key ) {
97
-			if ( ! empty( $query->query_vars[ $key ] ) ) {
98
-				return; // don't slow down queries that wouldn't include action_log comments anyway
99
-			}
100
-		}
101
-		$query->query_vars['action_log_filter'] = true;
102
-		add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
103
-	}
104
-
105
-	/**
106
-	 * @param array            $clauses
107
-	 * @param WP_Comment_Query $query
108
-	 *
109
-	 * @return array
110
-	 */
111
-	public function filter_comment_query_clauses( $clauses, $query ) {
112
-		if ( ! empty( $query->query_vars['action_log_filter'] ) ) {
113
-			$clauses['where'] .= $this->get_where_clause();
114
-		}
115
-		return $clauses;
116
-	}
117
-
118
-	/**
119
-	 * Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not
120
-	 * the WP_Comment_Query class handled by @see self::filter_comment_queries().
121
-	 *
122
-	 * @param string   $where
123
-	 * @param WP_Query $query
124
-	 *
125
-	 * @return string
126
-	 */
127
-	public function filter_comment_feed( $where, $query ) {
128
-		if ( is_comment_feed() ) {
129
-			$where .= $this->get_where_clause();
130
-		}
131
-		return $where;
132
-	}
133
-
134
-	/**
135
-	 * Return a SQL clause to exclude Action Scheduler comments.
136
-	 *
137
-	 * @return string
138
-	 */
139
-	protected function get_where_clause() {
140
-		global $wpdb;
141
-		return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE );
142
-	}
143
-
144
-	/**
145
-	 * Remove action log entries from wp_count_comments()
146
-	 *
147
-	 * @param array $stats
148
-	 * @param int   $post_id
149
-	 *
150
-	 * @return object
151
-	 */
152
-	public function filter_comment_count( $stats, $post_id ) {
153
-		global $wpdb;
154
-
155
-		if ( 0 === $post_id ) {
156
-			$stats = $this->get_comment_count();
157
-		}
158
-
159
-		return $stats;
160
-	}
161
-
162
-	/**
163
-	 * Retrieve the comment counts from our cache, or the database if the cached version isn't set.
164
-	 *
165
-	 * @return object
166
-	 */
167
-	protected function get_comment_count() {
168
-		global $wpdb;
169
-
170
-		$stats = get_transient( 'as_comment_count' );
171
-
172
-		if ( ! $stats ) {
173
-			$stats = array();
174
-
175
-			$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
176
-
177
-			$total    = 0;
178
-			$stats    = array();
179
-			$approved = array(
180
-				'0'            => 'moderated',
181
-				'1'            => 'approved',
182
-				'spam'         => 'spam',
183
-				'trash'        => 'trash',
184
-				'post-trashed' => 'post-trashed',
185
-			);
186
-
187
-			foreach ( (array) $count as $row ) {
188
-				// Don't count post-trashed toward totals
189
-				if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
190
-					$total += $row['num_comments'];
191
-				}
192
-				if ( isset( $approved[ $row['comment_approved'] ] ) ) {
193
-					$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
194
-				}
195
-			}
196
-
197
-			$stats['total_comments'] = $total;
198
-			$stats['all']            = $total;
199
-
200
-			foreach ( $approved as $key ) {
201
-				if ( empty( $stats[ $key ] ) ) {
202
-					$stats[ $key ] = 0;
203
-				}
204
-			}
205
-
206
-			$stats = (object) $stats;
207
-			set_transient( 'as_comment_count', $stats );
208
-		}
209
-
210
-		return $stats;
211
-	}
212
-
213
-	/**
214
-	 * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache
215
-	 * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
216
-	 */
217
-	public function delete_comment_count_cache() {
218
-		delete_transient( 'as_comment_count' );
219
-	}
220
-
221
-	/**
222
-	 * @codeCoverageIgnore
223
-	 */
224
-	public function init() {
225
-		add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
226
-		add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
227
-
228
-		parent::init();
229
-
230
-		add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
231
-		add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
232
-		add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
233
-
234
-		// Delete comments count cache whenever there is a new comment or a comment status changes
235
-		add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
236
-		add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
237
-	}
238
-
239
-	public function disable_comment_counting() {
240
-		wp_defer_comment_counting( true );
241
-	}
242
-	public function enable_comment_counting() {
243
-		wp_defer_comment_counting( false );
244
-	}
7
+    const AGENT = 'ActionScheduler';
8
+    const TYPE  = 'action_log';
9
+
10
+    /**
11
+     * @param string   $action_id
12
+     * @param string   $message
13
+     * @param DateTime $date
14
+     *
15
+     * @return string The log entry ID
16
+     */
17
+    public function log( $action_id, $message, DateTime $date = null ) {
18
+        if ( empty( $date ) ) {
19
+            $date = as_get_datetime_object();
20
+        } else {
21
+            $date = as_get_datetime_object( clone $date );
22
+        }
23
+        $comment_id = $this->create_wp_comment( $action_id, $message, $date );
24
+        return $comment_id;
25
+    }
26
+
27
+    protected function create_wp_comment( $action_id, $message, DateTime $date ) {
28
+
29
+        $comment_date_gmt = $date->format( 'Y-m-d H:i:s' );
30
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
31
+        $comment_data = array(
32
+            'comment_post_ID'  => $action_id,
33
+            'comment_date'     => $date->format( 'Y-m-d H:i:s' ),
34
+            'comment_date_gmt' => $comment_date_gmt,
35
+            'comment_author'   => self::AGENT,
36
+            'comment_content'  => $message,
37
+            'comment_agent'    => self::AGENT,
38
+            'comment_type'     => self::TYPE,
39
+        );
40
+        return wp_insert_comment( $comment_data );
41
+    }
42
+
43
+    /**
44
+     * @param string $entry_id
45
+     *
46
+     * @return ActionScheduler_LogEntry
47
+     */
48
+    public function get_entry( $entry_id ) {
49
+        $comment = $this->get_comment( $entry_id );
50
+        if ( empty( $comment ) || $comment->comment_type != self::TYPE ) {
51
+            return new ActionScheduler_NullLogEntry();
52
+        }
53
+
54
+        $date = as_get_datetime_object( $comment->comment_date_gmt );
55
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
56
+        return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date );
57
+    }
58
+
59
+    /**
60
+     * @param string $action_id
61
+     *
62
+     * @return ActionScheduler_LogEntry[]
63
+     */
64
+    public function get_logs( $action_id ) {
65
+        $status = 'all';
66
+        if ( get_post_status( $action_id ) == 'trash' ) {
67
+            $status = 'post-trashed';
68
+        }
69
+        $comments = get_comments(
70
+            array(
71
+                'post_id' => $action_id,
72
+                'orderby' => 'comment_date_gmt',
73
+                'order'   => 'ASC',
74
+                'type'    => self::TYPE,
75
+                'status'  => $status,
76
+            )
77
+        );
78
+        $logs     = array();
79
+        foreach ( $comments as $c ) {
80
+            $entry = $this->get_entry( $c );
81
+            if ( ! empty( $entry ) ) {
82
+                $logs[] = $entry;
83
+            }
84
+        }
85
+        return $logs;
86
+    }
87
+
88
+    protected function get_comment( $comment_id ) {
89
+        return get_comment( $comment_id );
90
+    }
91
+
92
+    /**
93
+     * @param WP_Comment_Query $query
94
+     */
95
+    public function filter_comment_queries( $query ) {
96
+        foreach ( array( 'ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID' ) as $key ) {
97
+            if ( ! empty( $query->query_vars[ $key ] ) ) {
98
+                return; // don't slow down queries that wouldn't include action_log comments anyway
99
+            }
100
+        }
101
+        $query->query_vars['action_log_filter'] = true;
102
+        add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
103
+    }
104
+
105
+    /**
106
+     * @param array            $clauses
107
+     * @param WP_Comment_Query $query
108
+     *
109
+     * @return array
110
+     */
111
+    public function filter_comment_query_clauses( $clauses, $query ) {
112
+        if ( ! empty( $query->query_vars['action_log_filter'] ) ) {
113
+            $clauses['where'] .= $this->get_where_clause();
114
+        }
115
+        return $clauses;
116
+    }
117
+
118
+    /**
119
+     * Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not
120
+     * the WP_Comment_Query class handled by @see self::filter_comment_queries().
121
+     *
122
+     * @param string   $where
123
+     * @param WP_Query $query
124
+     *
125
+     * @return string
126
+     */
127
+    public function filter_comment_feed( $where, $query ) {
128
+        if ( is_comment_feed() ) {
129
+            $where .= $this->get_where_clause();
130
+        }
131
+        return $where;
132
+    }
133
+
134
+    /**
135
+     * Return a SQL clause to exclude Action Scheduler comments.
136
+     *
137
+     * @return string
138
+     */
139
+    protected function get_where_clause() {
140
+        global $wpdb;
141
+        return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE );
142
+    }
143
+
144
+    /**
145
+     * Remove action log entries from wp_count_comments()
146
+     *
147
+     * @param array $stats
148
+     * @param int   $post_id
149
+     *
150
+     * @return object
151
+     */
152
+    public function filter_comment_count( $stats, $post_id ) {
153
+        global $wpdb;
154
+
155
+        if ( 0 === $post_id ) {
156
+            $stats = $this->get_comment_count();
157
+        }
158
+
159
+        return $stats;
160
+    }
161
+
162
+    /**
163
+     * Retrieve the comment counts from our cache, or the database if the cached version isn't set.
164
+     *
165
+     * @return object
166
+     */
167
+    protected function get_comment_count() {
168
+        global $wpdb;
169
+
170
+        $stats = get_transient( 'as_comment_count' );
171
+
172
+        if ( ! $stats ) {
173
+            $stats = array();
174
+
175
+            $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
176
+
177
+            $total    = 0;
178
+            $stats    = array();
179
+            $approved = array(
180
+                '0'            => 'moderated',
181
+                '1'            => 'approved',
182
+                'spam'         => 'spam',
183
+                'trash'        => 'trash',
184
+                'post-trashed' => 'post-trashed',
185
+            );
186
+
187
+            foreach ( (array) $count as $row ) {
188
+                // Don't count post-trashed toward totals
189
+                if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
190
+                    $total += $row['num_comments'];
191
+                }
192
+                if ( isset( $approved[ $row['comment_approved'] ] ) ) {
193
+                    $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
194
+                }
195
+            }
196
+
197
+            $stats['total_comments'] = $total;
198
+            $stats['all']            = $total;
199
+
200
+            foreach ( $approved as $key ) {
201
+                if ( empty( $stats[ $key ] ) ) {
202
+                    $stats[ $key ] = 0;
203
+                }
204
+            }
205
+
206
+            $stats = (object) $stats;
207
+            set_transient( 'as_comment_count', $stats );
208
+        }
209
+
210
+        return $stats;
211
+    }
212
+
213
+    /**
214
+     * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache
215
+     * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
216
+     */
217
+    public function delete_comment_count_cache() {
218
+        delete_transient( 'as_comment_count' );
219
+    }
220
+
221
+    /**
222
+     * @codeCoverageIgnore
223
+     */
224
+    public function init() {
225
+        add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
226
+        add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
227
+
228
+        parent::init();
229
+
230
+        add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
231
+        add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
232
+        add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
233
+
234
+        // Delete comments count cache whenever there is a new comment or a comment status changes
235
+        add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
236
+        add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
237
+    }
238
+
239
+    public function disable_comment_counting() {
240
+        wp_defer_comment_counting( true );
241
+    }
242
+    public function enable_comment_counting() {
243
+        wp_defer_comment_counting( false );
244
+    }
245 245
 
246 246
 }
Please login to merge, or discard this patch.
Spacing   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -14,30 +14,30 @@  discard block
 block discarded – undo
14 14
 	 *
15 15
 	 * @return string The log entry ID
16 16
 	 */
17
-	public function log( $action_id, $message, DateTime $date = null ) {
18
-		if ( empty( $date ) ) {
17
+	public function log($action_id, $message, DateTime $date = null) {
18
+		if (empty($date)) {
19 19
 			$date = as_get_datetime_object();
20 20
 		} else {
21
-			$date = as_get_datetime_object( clone $date );
21
+			$date = as_get_datetime_object(clone $date);
22 22
 		}
23
-		$comment_id = $this->create_wp_comment( $action_id, $message, $date );
23
+		$comment_id = $this->create_wp_comment($action_id, $message, $date);
24 24
 		return $comment_id;
25 25
 	}
26 26
 
27
-	protected function create_wp_comment( $action_id, $message, DateTime $date ) {
27
+	protected function create_wp_comment($action_id, $message, DateTime $date) {
28 28
 
29
-		$comment_date_gmt = $date->format( 'Y-m-d H:i:s' );
30
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
29
+		$comment_date_gmt = $date->format('Y-m-d H:i:s');
30
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
31 31
 		$comment_data = array(
32 32
 			'comment_post_ID'  => $action_id,
33
-			'comment_date'     => $date->format( 'Y-m-d H:i:s' ),
33
+			'comment_date'     => $date->format('Y-m-d H:i:s'),
34 34
 			'comment_date_gmt' => $comment_date_gmt,
35 35
 			'comment_author'   => self::AGENT,
36 36
 			'comment_content'  => $message,
37 37
 			'comment_agent'    => self::AGENT,
38 38
 			'comment_type'     => self::TYPE,
39 39
 		);
40
-		return wp_insert_comment( $comment_data );
40
+		return wp_insert_comment($comment_data);
41 41
 	}
42 42
 
43 43
 	/**
@@ -45,15 +45,15 @@  discard block
 block discarded – undo
45 45
 	 *
46 46
 	 * @return ActionScheduler_LogEntry
47 47
 	 */
48
-	public function get_entry( $entry_id ) {
49
-		$comment = $this->get_comment( $entry_id );
50
-		if ( empty( $comment ) || $comment->comment_type != self::TYPE ) {
48
+	public function get_entry($entry_id) {
49
+		$comment = $this->get_comment($entry_id);
50
+		if (empty($comment) || $comment->comment_type != self::TYPE) {
51 51
 			return new ActionScheduler_NullLogEntry();
52 52
 		}
53 53
 
54
-		$date = as_get_datetime_object( $comment->comment_date_gmt );
55
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
56
-		return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date );
54
+		$date = as_get_datetime_object($comment->comment_date_gmt);
55
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
56
+		return new ActionScheduler_LogEntry($comment->comment_post_ID, $comment->comment_content, $date);
57 57
 	}
58 58
 
59 59
 	/**
@@ -61,9 +61,9 @@  discard block
 block discarded – undo
61 61
 	 *
62 62
 	 * @return ActionScheduler_LogEntry[]
63 63
 	 */
64
-	public function get_logs( $action_id ) {
64
+	public function get_logs($action_id) {
65 65
 		$status = 'all';
66
-		if ( get_post_status( $action_id ) == 'trash' ) {
66
+		if (get_post_status($action_id) == 'trash') {
67 67
 			$status = 'post-trashed';
68 68
 		}
69 69
 		$comments = get_comments(
@@ -75,31 +75,31 @@  discard block
 block discarded – undo
75 75
 				'status'  => $status,
76 76
 			)
77 77
 		);
78
-		$logs     = array();
79
-		foreach ( $comments as $c ) {
80
-			$entry = $this->get_entry( $c );
81
-			if ( ! empty( $entry ) ) {
78
+		$logs = array();
79
+		foreach ($comments as $c) {
80
+			$entry = $this->get_entry($c);
81
+			if ( ! empty($entry)) {
82 82
 				$logs[] = $entry;
83 83
 			}
84 84
 		}
85 85
 		return $logs;
86 86
 	}
87 87
 
88
-	protected function get_comment( $comment_id ) {
89
-		return get_comment( $comment_id );
88
+	protected function get_comment($comment_id) {
89
+		return get_comment($comment_id);
90 90
 	}
91 91
 
92 92
 	/**
93 93
 	 * @param WP_Comment_Query $query
94 94
 	 */
95
-	public function filter_comment_queries( $query ) {
96
-		foreach ( array( 'ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID' ) as $key ) {
97
-			if ( ! empty( $query->query_vars[ $key ] ) ) {
95
+	public function filter_comment_queries($query) {
96
+		foreach (array('ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID') as $key) {
97
+			if ( ! empty($query->query_vars[$key])) {
98 98
 				return; // don't slow down queries that wouldn't include action_log comments anyway
99 99
 			}
100 100
 		}
101 101
 		$query->query_vars['action_log_filter'] = true;
102
-		add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
102
+		add_filter('comments_clauses', array($this, 'filter_comment_query_clauses'), 10, 2);
103 103
 	}
104 104
 
105 105
 	/**
@@ -108,8 +108,8 @@  discard block
 block discarded – undo
108 108
 	 *
109 109
 	 * @return array
110 110
 	 */
111
-	public function filter_comment_query_clauses( $clauses, $query ) {
112
-		if ( ! empty( $query->query_vars['action_log_filter'] ) ) {
111
+	public function filter_comment_query_clauses($clauses, $query) {
112
+		if ( ! empty($query->query_vars['action_log_filter'])) {
113 113
 			$clauses['where'] .= $this->get_where_clause();
114 114
 		}
115 115
 		return $clauses;
@@ -124,8 +124,8 @@  discard block
 block discarded – undo
124 124
 	 *
125 125
 	 * @return string
126 126
 	 */
127
-	public function filter_comment_feed( $where, $query ) {
128
-		if ( is_comment_feed() ) {
127
+	public function filter_comment_feed($where, $query) {
128
+		if (is_comment_feed()) {
129 129
 			$where .= $this->get_where_clause();
130 130
 		}
131 131
 		return $where;
@@ -138,7 +138,7 @@  discard block
 block discarded – undo
138 138
 	 */
139 139
 	protected function get_where_clause() {
140 140
 		global $wpdb;
141
-		return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE );
141
+		return sprintf(" AND {$wpdb->comments}.comment_type != '%s'", self::TYPE);
142 142
 	}
143 143
 
144 144
 	/**
@@ -149,10 +149,10 @@  discard block
 block discarded – undo
149 149
 	 *
150 150
 	 * @return object
151 151
 	 */
152
-	public function filter_comment_count( $stats, $post_id ) {
152
+	public function filter_comment_count($stats, $post_id) {
153 153
 		global $wpdb;
154 154
 
155
-		if ( 0 === $post_id ) {
155
+		if (0 === $post_id) {
156 156
 			$stats = $this->get_comment_count();
157 157
 		}
158 158
 
@@ -167,12 +167,12 @@  discard block
 block discarded – undo
167 167
 	protected function get_comment_count() {
168 168
 		global $wpdb;
169 169
 
170
-		$stats = get_transient( 'as_comment_count' );
170
+		$stats = get_transient('as_comment_count');
171 171
 
172
-		if ( ! $stats ) {
172
+		if ( ! $stats) {
173 173
 			$stats = array();
174 174
 
175
-			$count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
175
+			$count = $wpdb->get_results("SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A);
176 176
 
177 177
 			$total    = 0;
178 178
 			$stats    = array();
@@ -184,27 +184,27 @@  discard block
 block discarded – undo
184 184
 				'post-trashed' => 'post-trashed',
185 185
 			);
186 186
 
187
-			foreach ( (array) $count as $row ) {
187
+			foreach ((array) $count as $row) {
188 188
 				// Don't count post-trashed toward totals
189
-				if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
189
+				if ('post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved']) {
190 190
 					$total += $row['num_comments'];
191 191
 				}
192
-				if ( isset( $approved[ $row['comment_approved'] ] ) ) {
193
-					$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
192
+				if (isset($approved[$row['comment_approved']])) {
193
+					$stats[$approved[$row['comment_approved']]] = $row['num_comments'];
194 194
 				}
195 195
 			}
196 196
 
197 197
 			$stats['total_comments'] = $total;
198 198
 			$stats['all']            = $total;
199 199
 
200
-			foreach ( $approved as $key ) {
201
-				if ( empty( $stats[ $key ] ) ) {
202
-					$stats[ $key ] = 0;
200
+			foreach ($approved as $key) {
201
+				if (empty($stats[$key])) {
202
+					$stats[$key] = 0;
203 203
 				}
204 204
 			}
205 205
 
206 206
 			$stats = (object) $stats;
207
-			set_transient( 'as_comment_count', $stats );
207
+			set_transient('as_comment_count', $stats);
208 208
 		}
209 209
 
210 210
 		return $stats;
@@ -215,32 +215,32 @@  discard block
 block discarded – undo
215 215
 	 * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
216 216
 	 */
217 217
 	public function delete_comment_count_cache() {
218
-		delete_transient( 'as_comment_count' );
218
+		delete_transient('as_comment_count');
219 219
 	}
220 220
 
221 221
 	/**
222 222
 	 * @codeCoverageIgnore
223 223
 	 */
224 224
 	public function init() {
225
-		add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
226
-		add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
225
+		add_action('action_scheduler_before_process_queue', array($this, 'disable_comment_counting'), 10, 0);
226
+		add_action('action_scheduler_after_process_queue', array($this, 'enable_comment_counting'), 10, 0);
227 227
 
228 228
 		parent::init();
229 229
 
230
-		add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
231
-		add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
232
-		add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
230
+		add_action('pre_get_comments', array($this, 'filter_comment_queries'), 10, 1);
231
+		add_action('wp_count_comments', array($this, 'filter_comment_count'), 20, 2); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
232
+		add_action('comment_feed_where', array($this, 'filter_comment_feed'), 10, 2);
233 233
 
234 234
 		// Delete comments count cache whenever there is a new comment or a comment status changes
235
-		add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
236
-		add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
235
+		add_action('wp_insert_comment', array($this, 'delete_comment_count_cache'));
236
+		add_action('wp_set_comment_status', array($this, 'delete_comment_count_cache'));
237 237
 	}
238 238
 
239 239
 	public function disable_comment_counting() {
240
-		wp_defer_comment_counting( true );
240
+		wp_defer_comment_counting(true);
241 241
 	}
242 242
 	public function enable_comment_counting() {
243
-		wp_defer_comment_counting( false );
243
+		wp_defer_comment_counting(false);
244 244
 	}
245 245
 
246 246
 }
Please login to merge, or discard this patch.
src/ext/action-scheduler/classes/data-stores/ActionScheduler_DBLogger.php 2 patches
Indentation   +142 added lines, -142 removed lines patch added patch discarded remove patch
@@ -9,146 +9,146 @@
 block discarded – undo
9 9
  */
10 10
 class ActionScheduler_DBLogger extends ActionScheduler_Logger {
11 11
 
12
-	/**
13
-	 * Add a record to an action log.
14
-	 *
15
-	 * @param int      $action_id Action ID.
16
-	 * @param string   $message Message to be saved in the log entry.
17
-	 * @param DateTime $date Timestamp of the log entry.
18
-	 *
19
-	 * @return int     The log entry ID.
20
-	 */
21
-	public function log( $action_id, $message, DateTime $date = null ) {
22
-		if ( empty( $date ) ) {
23
-			$date = as_get_datetime_object();
24
-		} else {
25
-			$date = clone $date;
26
-		}
27
-
28
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
29
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
-		$date_local = $date->format( 'Y-m-d H:i:s' );
31
-
32
-		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
33
-		global $wpdb;
34
-		$wpdb->insert(
35
-			$wpdb->actionscheduler_logs,
36
-			array(
37
-				'action_id'      => $action_id,
38
-				'message'        => $message,
39
-				'log_date_gmt'   => $date_gmt,
40
-				'log_date_local' => $date_local,
41
-			),
42
-			array( '%d', '%s', '%s', '%s' )
43
-		);
44
-
45
-		return $wpdb->insert_id;
46
-	}
47
-
48
-	/**
49
-	 * Retrieve an action log entry.
50
-	 *
51
-	 * @param int $entry_id Log entry ID.
52
-	 *
53
-	 * @return ActionScheduler_LogEntry
54
-	 */
55
-	public function get_entry( $entry_id ) {
56
-		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
57
-		global $wpdb;
58
-		$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
59
-
60
-		return $this->create_entry_from_db_record( $entry );
61
-	}
62
-
63
-	/**
64
-	 * Create an action log entry from a database record.
65
-	 *
66
-	 * @param object $record Log entry database record object.
67
-	 *
68
-	 * @return ActionScheduler_LogEntry
69
-	 */
70
-	private function create_entry_from_db_record( $record ) {
71
-		if ( empty( $record ) ) {
72
-			return new ActionScheduler_NullLogEntry();
73
-		}
74
-
75
-		if ( $record->log_date_gmt === null ) {
76
-			$date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE );
77
-		} else {
78
-			$date = as_get_datetime_object( $record->log_date_gmt );
79
-		}
80
-
81
-		return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
82
-	}
83
-
84
-	/**
85
-	 * Retrieve the an action's log entries from the database.
86
-	 *
87
-	 * @param int $action_id Action ID.
88
-	 *
89
-	 * @return ActionScheduler_LogEntry[]
90
-	 */
91
-	public function get_logs( $action_id ) {
92
-		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
93
-		global $wpdb;
94
-
95
-		$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
96
-
97
-		return array_map( array( $this, 'create_entry_from_db_record' ), $records );
98
-	}
99
-
100
-	/**
101
-	 * Initialize the data store.
102
-	 *
103
-	 * @codeCoverageIgnore
104
-	 */
105
-	public function init() {
106
-		$table_maker = new ActionScheduler_LoggerSchema();
107
-		$table_maker->init();
108
-		$table_maker->register_tables();
109
-
110
-		parent::init();
111
-
112
-		add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );
113
-	}
114
-
115
-	/**
116
-	 * Delete the action logs for an action.
117
-	 *
118
-	 * @param int $action_id Action ID.
119
-	 */
120
-	public function clear_deleted_action_logs( $action_id ) {
121
-		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
122
-		global $wpdb;
123
-		$wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
124
-	}
125
-
126
-	/**
127
-	 * Bulk add cancel action log entries.
128
-	 *
129
-	 * @param array $action_ids List of action ID.
130
-	 */
131
-	public function bulk_log_cancel_actions( $action_ids ) {
132
-		if ( empty( $action_ids ) ) {
133
-			return;
134
-		}
135
-
136
-		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
137
-		global $wpdb;
138
-		$date     = as_get_datetime_object();
139
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
140
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
141
-		$date_local = $date->format( 'Y-m-d H:i:s' );
142
-		$message    = __( 'action canceled', 'action-scheduler' );
143
-		$format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
144
-		$sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
145
-		$value_rows = array();
146
-
147
-		foreach ( $action_ids as $action_id ) {
148
-			$value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
149
-		}
150
-		$sql_query .= implode( ',', $value_rows );
151
-
152
-		$wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
153
-	}
12
+    /**
13
+     * Add a record to an action log.
14
+     *
15
+     * @param int      $action_id Action ID.
16
+     * @param string   $message Message to be saved in the log entry.
17
+     * @param DateTime $date Timestamp of the log entry.
18
+     *
19
+     * @return int     The log entry ID.
20
+     */
21
+    public function log( $action_id, $message, DateTime $date = null ) {
22
+        if ( empty( $date ) ) {
23
+            $date = as_get_datetime_object();
24
+        } else {
25
+            $date = clone $date;
26
+        }
27
+
28
+        $date_gmt = $date->format( 'Y-m-d H:i:s' );
29
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
+        $date_local = $date->format( 'Y-m-d H:i:s' );
31
+
32
+        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
33
+        global $wpdb;
34
+        $wpdb->insert(
35
+            $wpdb->actionscheduler_logs,
36
+            array(
37
+                'action_id'      => $action_id,
38
+                'message'        => $message,
39
+                'log_date_gmt'   => $date_gmt,
40
+                'log_date_local' => $date_local,
41
+            ),
42
+            array( '%d', '%s', '%s', '%s' )
43
+        );
44
+
45
+        return $wpdb->insert_id;
46
+    }
47
+
48
+    /**
49
+     * Retrieve an action log entry.
50
+     *
51
+     * @param int $entry_id Log entry ID.
52
+     *
53
+     * @return ActionScheduler_LogEntry
54
+     */
55
+    public function get_entry( $entry_id ) {
56
+        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
57
+        global $wpdb;
58
+        $entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
59
+
60
+        return $this->create_entry_from_db_record( $entry );
61
+    }
62
+
63
+    /**
64
+     * Create an action log entry from a database record.
65
+     *
66
+     * @param object $record Log entry database record object.
67
+     *
68
+     * @return ActionScheduler_LogEntry
69
+     */
70
+    private function create_entry_from_db_record( $record ) {
71
+        if ( empty( $record ) ) {
72
+            return new ActionScheduler_NullLogEntry();
73
+        }
74
+
75
+        if ( $record->log_date_gmt === null ) {
76
+            $date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE );
77
+        } else {
78
+            $date = as_get_datetime_object( $record->log_date_gmt );
79
+        }
80
+
81
+        return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
82
+    }
83
+
84
+    /**
85
+     * Retrieve the an action's log entries from the database.
86
+     *
87
+     * @param int $action_id Action ID.
88
+     *
89
+     * @return ActionScheduler_LogEntry[]
90
+     */
91
+    public function get_logs( $action_id ) {
92
+        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
93
+        global $wpdb;
94
+
95
+        $records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
96
+
97
+        return array_map( array( $this, 'create_entry_from_db_record' ), $records );
98
+    }
99
+
100
+    /**
101
+     * Initialize the data store.
102
+     *
103
+     * @codeCoverageIgnore
104
+     */
105
+    public function init() {
106
+        $table_maker = new ActionScheduler_LoggerSchema();
107
+        $table_maker->init();
108
+        $table_maker->register_tables();
109
+
110
+        parent::init();
111
+
112
+        add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );
113
+    }
114
+
115
+    /**
116
+     * Delete the action logs for an action.
117
+     *
118
+     * @param int $action_id Action ID.
119
+     */
120
+    public function clear_deleted_action_logs( $action_id ) {
121
+        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
122
+        global $wpdb;
123
+        $wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
124
+    }
125
+
126
+    /**
127
+     * Bulk add cancel action log entries.
128
+     *
129
+     * @param array $action_ids List of action ID.
130
+     */
131
+    public function bulk_log_cancel_actions( $action_ids ) {
132
+        if ( empty( $action_ids ) ) {
133
+            return;
134
+        }
135
+
136
+        /** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
137
+        global $wpdb;
138
+        $date     = as_get_datetime_object();
139
+        $date_gmt = $date->format( 'Y-m-d H:i:s' );
140
+        ActionScheduler_TimezoneHelper::set_local_timezone( $date );
141
+        $date_local = $date->format( 'Y-m-d H:i:s' );
142
+        $message    = __( 'action canceled', 'action-scheduler' );
143
+        $format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
144
+        $sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
145
+        $value_rows = array();
146
+
147
+        foreach ( $action_ids as $action_id ) {
148
+            $value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
149
+        }
150
+        $sql_query .= implode( ',', $value_rows );
151
+
152
+        $wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
153
+    }
154 154
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -18,16 +18,16 @@  discard block
 block discarded – undo
18 18
 	 *
19 19
 	 * @return int     The log entry ID.
20 20
 	 */
21
-	public function log( $action_id, $message, DateTime $date = null ) {
22
-		if ( empty( $date ) ) {
21
+	public function log($action_id, $message, DateTime $date = null) {
22
+		if (empty($date)) {
23 23
 			$date = as_get_datetime_object();
24 24
 		} else {
25 25
 			$date = clone $date;
26 26
 		}
27 27
 
28
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
29
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
-		$date_local = $date->format( 'Y-m-d H:i:s' );
28
+		$date_gmt = $date->format('Y-m-d H:i:s');
29
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
30
+		$date_local = $date->format('Y-m-d H:i:s');
31 31
 
32 32
 		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
33 33
 		global $wpdb;
@@ -39,7 +39,7 @@  discard block
 block discarded – undo
39 39
 				'log_date_gmt'   => $date_gmt,
40 40
 				'log_date_local' => $date_local,
41 41
 			),
42
-			array( '%d', '%s', '%s', '%s' )
42
+			array('%d', '%s', '%s', '%s')
43 43
 		);
44 44
 
45 45
 		return $wpdb->insert_id;
@@ -52,12 +52,12 @@  discard block
 block discarded – undo
52 52
 	 *
53 53
 	 * @return ActionScheduler_LogEntry
54 54
 	 */
55
-	public function get_entry( $entry_id ) {
55
+	public function get_entry($entry_id) {
56 56
 		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
57 57
 		global $wpdb;
58
-		$entry = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id ) );
58
+		$entry = $wpdb->get_row($wpdb->prepare("SELECT * FROM {$wpdb->actionscheduler_logs} WHERE log_id=%d", $entry_id));
59 59
 
60
-		return $this->create_entry_from_db_record( $entry );
60
+		return $this->create_entry_from_db_record($entry);
61 61
 	}
62 62
 
63 63
 	/**
@@ -67,18 +67,18 @@  discard block
 block discarded – undo
67 67
 	 *
68 68
 	 * @return ActionScheduler_LogEntry
69 69
 	 */
70
-	private function create_entry_from_db_record( $record ) {
71
-		if ( empty( $record ) ) {
70
+	private function create_entry_from_db_record($record) {
71
+		if (empty($record)) {
72 72
 			return new ActionScheduler_NullLogEntry();
73 73
 		}
74 74
 
75
-		if ( $record->log_date_gmt === null ) {
76
-			$date = as_get_datetime_object( ActionScheduler_StoreSchema::DEFAULT_DATE );
75
+		if ($record->log_date_gmt === null) {
76
+			$date = as_get_datetime_object(ActionScheduler_StoreSchema::DEFAULT_DATE);
77 77
 		} else {
78
-			$date = as_get_datetime_object( $record->log_date_gmt );
78
+			$date = as_get_datetime_object($record->log_date_gmt);
79 79
 		}
80 80
 
81
-		return new ActionScheduler_LogEntry( $record->action_id, $record->message, $date );
81
+		return new ActionScheduler_LogEntry($record->action_id, $record->message, $date);
82 82
 	}
83 83
 
84 84
 	/**
@@ -88,13 +88,13 @@  discard block
 block discarded – undo
88 88
 	 *
89 89
 	 * @return ActionScheduler_LogEntry[]
90 90
 	 */
91
-	public function get_logs( $action_id ) {
91
+	public function get_logs($action_id) {
92 92
 		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
93 93
 		global $wpdb;
94 94
 
95
-		$records = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id ) );
95
+		$records = $wpdb->get_results($wpdb->prepare("SELECT * FROM {$wpdb->actionscheduler_logs} WHERE action_id=%d", $action_id));
96 96
 
97
-		return array_map( array( $this, 'create_entry_from_db_record' ), $records );
97
+		return array_map(array($this, 'create_entry_from_db_record'), $records);
98 98
 	}
99 99
 
100 100
 	/**
@@ -109,7 +109,7 @@  discard block
 block discarded – undo
109 109
 
110 110
 		parent::init();
111 111
 
112
-		add_action( 'action_scheduler_deleted_action', array( $this, 'clear_deleted_action_logs' ), 10, 1 );
112
+		add_action('action_scheduler_deleted_action', array($this, 'clear_deleted_action_logs'), 10, 1);
113 113
 	}
114 114
 
115 115
 	/**
@@ -117,10 +117,10 @@  discard block
 block discarded – undo
117 117
 	 *
118 118
 	 * @param int $action_id Action ID.
119 119
 	 */
120
-	public function clear_deleted_action_logs( $action_id ) {
120
+	public function clear_deleted_action_logs($action_id) {
121 121
 		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
122 122
 		global $wpdb;
123
-		$wpdb->delete( $wpdb->actionscheduler_logs, array( 'action_id' => $action_id ), array( '%d' ) );
123
+		$wpdb->delete($wpdb->actionscheduler_logs, array('action_id' => $action_id), array('%d'));
124 124
 	}
125 125
 
126 126
 	/**
@@ -128,27 +128,27 @@  discard block
 block discarded – undo
128 128
 	 *
129 129
 	 * @param array $action_ids List of action ID.
130 130
 	 */
131
-	public function bulk_log_cancel_actions( $action_ids ) {
132
-		if ( empty( $action_ids ) ) {
131
+	public function bulk_log_cancel_actions($action_ids) {
132
+		if (empty($action_ids)) {
133 133
 			return;
134 134
 		}
135 135
 
136 136
 		/** @var \wpdb $wpdb */ //phpcs:ignore Generic.Commenting.DocComment.MissingShort
137 137
 		global $wpdb;
138 138
 		$date     = as_get_datetime_object();
139
-		$date_gmt = $date->format( 'Y-m-d H:i:s' );
140
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
141
-		$date_local = $date->format( 'Y-m-d H:i:s' );
142
-		$message    = __( 'action canceled', 'action-scheduler' );
143
-		$format     = '(%d, ' . $wpdb->prepare( '%s, %s, %s', $message, $date_gmt, $date_local ) . ')';
139
+		$date_gmt = $date->format('Y-m-d H:i:s');
140
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
141
+		$date_local = $date->format('Y-m-d H:i:s');
142
+		$message    = __('action canceled', 'action-scheduler');
143
+		$format     = '(%d, '.$wpdb->prepare('%s, %s, %s', $message, $date_gmt, $date_local).')';
144 144
 		$sql_query  = "INSERT {$wpdb->actionscheduler_logs} (action_id, message, log_date_gmt, log_date_local) VALUES ";
145 145
 		$value_rows = array();
146 146
 
147
-		foreach ( $action_ids as $action_id ) {
148
-			$value_rows[] = $wpdb->prepare( $format, $action_id ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
147
+		foreach ($action_ids as $action_id) {
148
+			$value_rows[] = $wpdb->prepare($format, $action_id); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
149 149
 		}
150
-		$sql_query .= implode( ',', $value_rows );
150
+		$sql_query .= implode(',', $value_rows);
151 151
 
152
-		$wpdb->query( $sql_query ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
152
+		$wpdb->query($sql_query); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
153 153
 	}
154 154
 }
Please login to merge, or discard this patch.
ext/action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php 2 patches
Indentation   +1059 added lines, -1059 removed lines patch added patch discarded remove patch
@@ -4,1072 +4,1072 @@
 block discarded – undo
4 4
  * Class ActionScheduler_wpPostStore
5 5
  */
6 6
 class ActionScheduler_wpPostStore extends ActionScheduler_Store {
7
-	const POST_TYPE         = 'scheduled-action';
8
-	const GROUP_TAXONOMY    = 'action-group';
9
-	const SCHEDULE_META_KEY = '_action_manager_schedule';
10
-	const DEPENDENCIES_MET  = 'as-post-store-dependencies-met';
11
-
12
-	/**
13
-	 * Used to share information about the before_date property of claims internally.
14
-	 *
15
-	 * This is used in preference to passing the same information as a method param
16
-	 * for backwards-compatibility reasons.
17
-	 *
18
-	 * @var DateTime|null
19
-	 */
20
-	private $claim_before_date = null;
21
-
22
-	/**
23
-	 * Local Timezone.
24
-	 *
25
-	 * @var DateTimeZone
26
-	 */
27
-	protected $local_timezone = null;
28
-
29
-	/**
30
-	 * Save action.
31
-	 *
32
-	 * @param ActionScheduler_Action $action Scheduled Action.
33
-	 * @param DateTime               $scheduled_date Scheduled Date.
34
-	 *
35
-	 * @throws RuntimeException Throws an exception if the action could not be saved.
36
-	 * @return int
37
-	 */
38
-	public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
39
-		try {
40
-			$this->validate_action( $action );
41
-			$post_array = $this->create_post_array( $action, $scheduled_date );
42
-			$post_id    = $this->save_post_array( $post_array );
43
-			$this->save_post_schedule( $post_id, $action->get_schedule() );
44
-			$this->save_action_group( $post_id, $action->get_group() );
45
-			do_action( 'action_scheduler_stored_action', $post_id );
46
-			return $post_id;
47
-		} catch ( Exception $e ) {
48
-			/* translators: %s: action error message */
49
-			throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
50
-		}
51
-	}
52
-
53
-	/**
54
-	 * Create post array.
55
-	 *
56
-	 * @param ActionScheduler_Action $action Scheduled Action.
57
-	 * @param DateTime               $scheduled_date Scheduled Date.
58
-	 *
59
-	 * @return array Returns an array of post data.
60
-	 */
61
-	protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
62
-		$post = array(
63
-			'post_type'     => self::POST_TYPE,
64
-			'post_title'    => $action->get_hook(),
65
-			'post_content'  => wp_json_encode( $action->get_args() ),
66
-			'post_status'   => ( $action->is_finished() ? 'publish' : 'pending' ),
67
-			'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
68
-			'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
69
-		);
70
-		return $post;
71
-	}
72
-
73
-	/**
74
-	 * Save post array.
75
-	 *
76
-	 * @param array $post_array Post array.
77
-	 * @return int Returns the post ID.
78
-	 * @throws RuntimeException Throws an exception if the action could not be saved.
79
-	 */
80
-	protected function save_post_array( $post_array ) {
81
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
82
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
83
-
84
-		$has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
85
-
86
-		if ( $has_kses ) {
87
-			// Prevent KSES from corrupting JSON in post_content.
88
-			kses_remove_filters();
89
-		}
90
-
91
-		$post_id = wp_insert_post( $post_array );
92
-
93
-		if ( $has_kses ) {
94
-			kses_init_filters();
95
-		}
96
-
97
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
98
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
99
-
100
-		if ( is_wp_error( $post_id ) || empty( $post_id ) ) {
101
-			throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
102
-		}
103
-		return $post_id;
104
-	}
105
-
106
-	/**
107
-	 * Filter insert post data.
108
-	 *
109
-	 * @param array $postdata Post data to filter.
110
-	 *
111
-	 * @return array
112
-	 */
113
-	public function filter_insert_post_data( $postdata ) {
114
-		if ( self::POST_TYPE === $postdata['post_type'] ) {
115
-			$postdata['post_author'] = 0;
116
-			if ( 'future' === $postdata['post_status'] ) {
117
-				$postdata['post_status'] = 'publish';
118
-			}
119
-		}
120
-		return $postdata;
121
-	}
122
-
123
-	/**
124
-	 * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug().
125
-	 *
126
-	 * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish'
127
-	 * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug()
128
-	 * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing
129
-	 * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a
130
-	 * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a
131
-	 * database containing thousands of related post_name values.
132
-	 *
133
-	 * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue.
134
-	 *
135
-	 * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This
136
-	 * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a
137
-	 * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an
138
-	 * action's slug, being probably unique is good enough.
139
-	 *
140
-	 * For more backstory on this issue, see:
141
-	 * - https://github.com/woocommerce/action-scheduler/issues/44 and
142
-	 * - https://core.trac.wordpress.org/ticket/21112
143
-	 *
144
-	 * @param string $override_slug Short-circuit return value.
145
-	 * @param string $slug          The desired slug (post_name).
146
-	 * @param int    $post_ID       Post ID.
147
-	 * @param string $post_status   The post status.
148
-	 * @param string $post_type     Post type.
149
-	 * @return string
150
-	 */
151
-	public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
152
-		if ( self::POST_TYPE === $post_type ) {
153
-			$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
154
-		}
155
-		return $override_slug;
156
-	}
157
-
158
-	/**
159
-	 * Save post schedule.
160
-	 *
161
-	 * @param int    $post_id  Post ID of the scheduled action.
162
-	 * @param string $schedule Schedule to save.
163
-	 *
164
-	 * @return void
165
-	 */
166
-	protected function save_post_schedule( $post_id, $schedule ) {
167
-		update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
168
-	}
169
-
170
-	/**
171
-	 * Save action group.
172
-	 *
173
-	 * @param int    $post_id Post ID.
174
-	 * @param string $group   Group to save.
175
-	 * @return void
176
-	 */
177
-	protected function save_action_group( $post_id, $group ) {
178
-		if ( empty( $group ) ) {
179
-			wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
180
-		} else {
181
-			wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false );
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * Fetch actions.
187
-	 *
188
-	 * @param int $action_id Action ID.
189
-	 * @return object
190
-	 */
191
-	public function fetch_action( $action_id ) {
192
-		$post = $this->get_post( $action_id );
193
-		if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
194
-			return $this->get_null_action();
195
-		}
196
-
197
-		try {
198
-			$action = $this->make_action_from_post( $post );
199
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
200
-			do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
201
-			return $this->get_null_action();
202
-		}
203
-
204
-		return $action;
205
-	}
206
-
207
-	/**
208
-	 * Get post.
209
-	 *
210
-	 * @param string $action_id - Action ID.
211
-	 * @return WP_Post|null
212
-	 */
213
-	protected function get_post( $action_id ) {
214
-		if ( empty( $action_id ) ) {
215
-			return null;
216
-		}
217
-		return get_post( $action_id );
218
-	}
219
-
220
-	/**
221
-	 * Get NULL action.
222
-	 *
223
-	 * @return ActionScheduler_NullAction
224
-	 */
225
-	protected function get_null_action() {
226
-		return new ActionScheduler_NullAction();
227
-	}
228
-
229
-	/**
230
-	 * Make action from post.
231
-	 *
232
-	 * @param WP_Post $post Post object.
233
-	 * @return WP_Post
234
-	 */
235
-	protected function make_action_from_post( $post ) {
236
-		$hook = $post->post_title;
237
-
238
-		$args = json_decode( $post->post_content, true );
239
-		$this->validate_args( $args, $post->ID );
240
-
241
-		$schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
242
-		$this->validate_schedule( $schedule, $post->ID );
243
-
244
-		$group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) );
245
-		$group = empty( $group ) ? '' : reset( $group );
246
-
247
-		return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
248
-	}
249
-
250
-	/**
251
-	 * Get action status by post status.
252
-	 *
253
-	 * @param string $post_status Post status.
254
-	 *
255
-	 * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
256
-	 * @return string
257
-	 */
258
-	protected function get_action_status_by_post_status( $post_status ) {
259
-
260
-		switch ( $post_status ) {
261
-			case 'publish':
262
-				$action_status = self::STATUS_COMPLETE;
263
-				break;
264
-			case 'trash':
265
-				$action_status = self::STATUS_CANCELED;
266
-				break;
267
-			default:
268
-				if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
269
-					throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
270
-				}
271
-				$action_status = $post_status;
272
-				break;
273
-		}
274
-
275
-		return $action_status;
276
-	}
277
-
278
-	/**
279
-	 * Get post status by action status.
280
-	 *
281
-	 * @param string $action_status Action status.
282
-	 *
283
-	 * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
284
-	 * @return string
285
-	 */
286
-	protected function get_post_status_by_action_status( $action_status ) {
287
-
288
-		switch ( $action_status ) {
289
-			case self::STATUS_COMPLETE:
290
-				$post_status = 'publish';
291
-				break;
292
-			case self::STATUS_CANCELED:
293
-				$post_status = 'trash';
294
-				break;
295
-			default:
296
-				if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
297
-					throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
298
-				}
299
-				$post_status = $action_status;
300
-				break;
301
-		}
302
-
303
-		return $post_status;
304
-	}
305
-
306
-	/**
307
-	 * Returns the SQL statement to query (or count) actions.
308
-	 *
309
-	 * @param array  $query            - Filtering options.
310
-	 * @param string $select_or_count  - Whether the SQL should select and return the IDs or just the row count.
311
-	 *
312
-	 * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
313
-	 * @return string SQL statement. The returned SQL is already properly escaped.
314
-	 */
315
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
316
-
317
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
318
-			throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
319
-		}
320
-
321
-		$query = wp_parse_args(
322
-			$query,
323
-			array(
324
-				'hook'             => '',
325
-				'args'             => null,
326
-				'date'             => null,
327
-				'date_compare'     => '<=',
328
-				'modified'         => null,
329
-				'modified_compare' => '<=',
330
-				'group'            => '',
331
-				'status'           => '',
332
-				'claimed'          => null,
333
-				'per_page'         => 5,
334
-				'offset'           => 0,
335
-				'orderby'          => 'date',
336
-				'order'            => 'ASC',
337
-				'search'           => '',
338
-			)
339
-		);
340
-
341
-		/**
342
-		 * Global wpdb object.
343
-		 *
344
-		 * @var wpdb $wpdb
345
-		 */
346
-		global $wpdb;
347
-		$sql        = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
348
-		$sql       .= "FROM {$wpdb->posts} p";
349
-		$sql_params = array();
350
-		if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
351
-			$sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
352
-			$sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
353
-			$sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
354
-		} elseif ( ! empty( $query['group'] ) ) {
355
-			$sql         .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
356
-			$sql         .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
357
-			$sql         .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
358
-			$sql         .= ' AND t.slug=%s';
359
-			$sql_params[] = $query['group'];
360
-		}
361
-		$sql         .= ' WHERE post_type=%s';
362
-		$sql_params[] = self::POST_TYPE;
363
-		if ( $query['hook'] ) {
364
-			$sql         .= ' AND p.post_title=%s';
365
-			$sql_params[] = $query['hook'];
366
-		}
367
-		if ( $query['args'] !== null ) {
368
-			$sql         .= ' AND p.post_content=%s';
369
-			$sql_params[] = wp_json_encode( $query['args'] );
370
-		}
371
-
372
-		if ( $query['status'] ) {
373
-			$post_statuses = array_map( array( $this, 'get_post_status_by_action_status' ), (array) $query['status'] );
374
-			$placeholders  = array_fill( 0, count( $post_statuses ), '%s' );
375
-			$sql          .= ' AND p.post_status IN (' . join( ', ', $placeholders ) . ')';
376
-			$sql_params    = array_merge( $sql_params, array_values( $post_statuses ) );
377
-		}
378
-
379
-		if ( $query['date'] instanceof DateTime ) {
380
-			$date = clone $query['date'];
381
-			$date->setTimezone( new DateTimeZone( 'UTC' ) );
382
-			$date_string  = $date->format( 'Y-m-d H:i:s' );
383
-			$comparator   = $this->validate_sql_comparator( $query['date_compare'] );
384
-			$sql         .= " AND p.post_date_gmt $comparator %s";
385
-			$sql_params[] = $date_string;
386
-		}
387
-
388
-		if ( $query['modified'] instanceof DateTime ) {
389
-			$modified = clone $query['modified'];
390
-			$modified->setTimezone( new DateTimeZone( 'UTC' ) );
391
-			$date_string  = $modified->format( 'Y-m-d H:i:s' );
392
-			$comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
393
-			$sql         .= " AND p.post_modified_gmt $comparator %s";
394
-			$sql_params[] = $date_string;
395
-		}
396
-
397
-		if ( true === $query['claimed'] ) {
398
-			$sql .= " AND p.post_password != ''";
399
-		} elseif ( false === $query['claimed'] ) {
400
-			$sql .= " AND p.post_password = ''";
401
-		} elseif ( $query['claimed'] !== null ) {
402
-			$sql         .= ' AND p.post_password = %s';
403
-			$sql_params[] = $query['claimed'];
404
-		}
405
-
406
-		if ( ! empty( $query['search'] ) ) {
407
-			$sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)';
408
-			for ( $i = 0; $i < 3; $i++ ) {
409
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
410
-			}
411
-		}
412
-
413
-		if ( 'select' === $select_or_count ) {
414
-			switch ( $query['orderby'] ) {
415
-				case 'hook':
416
-					$orderby = 'p.post_title';
417
-					break;
418
-				case 'group':
419
-					$orderby = 't.name';
420
-					break;
421
-				case 'status':
422
-					$orderby = 'p.post_status';
423
-					break;
424
-				case 'modified':
425
-					$orderby = 'p.post_modified';
426
-					break;
427
-				case 'claim_id':
428
-					$orderby = 'p.post_password';
429
-					break;
430
-				case 'schedule':
431
-				case 'date':
432
-				default:
433
-					$orderby = 'p.post_date_gmt';
434
-					break;
435
-			}
436
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
437
-				$order = 'ASC';
438
-			} else {
439
-				$order = 'DESC';
440
-			}
441
-			$sql .= " ORDER BY $orderby $order";
442
-			if ( $query['per_page'] > 0 ) {
443
-				$sql         .= ' LIMIT %d, %d';
444
-				$sql_params[] = $query['offset'];
445
-				$sql_params[] = $query['per_page'];
446
-			}
447
-		}
448
-
449
-		return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
450
-	}
451
-
452
-	/**
453
-	 * Query for action count or list of action IDs.
454
-	 *
455
-	 * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
456
-	 *
457
-	 * @see ActionScheduler_Store::query_actions for $query arg usage.
458
-	 *
459
-	 * @param array  $query      Query filtering options.
460
-	 * @param string $query_type Whether to select or count the results. Defaults to select.
461
-	 *
462
-	 * @return string|array|null The IDs of actions matching the query. Null on failure.
463
-	 */
464
-	public function query_actions( $query = array(), $query_type = 'select' ) {
465
-		/**
466
-		 * Global $wpdb object.
467
-		 *
468
-		 * @var wpdb $wpdb
469
-		 */
470
-		global $wpdb;
471
-
472
-		$sql = $this->get_query_actions_sql( $query, $query_type );
473
-
474
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
475
-	}
476
-
477
-	/**
478
-	 * Get a count of all actions in the store, grouped by status
479
-	 *
480
-	 * @return array
481
-	 */
482
-	public function action_counts() {
483
-
484
-		$action_counts_by_status = array();
485
-		$action_stati_and_labels = $this->get_status_labels();
486
-		$posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
487
-
488
-		foreach ( $posts_count_by_status as $post_status_name => $count ) {
489
-
490
-			try {
491
-				$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
492
-			} catch ( Exception $e ) {
493
-				// Ignore any post statuses that aren't for actions.
494
-				continue;
495
-			}
496
-			if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
497
-				$action_counts_by_status[ $action_status_name ] = $count;
498
-			}
499
-		}
500
-
501
-		return $action_counts_by_status;
502
-	}
503
-
504
-	/**
505
-	 * Cancel action.
506
-	 *
507
-	 * @param int $action_id Action ID.
508
-	 *
509
-	 * @throws InvalidArgumentException If $action_id is not identified.
510
-	 */
511
-	public function cancel_action( $action_id ) {
512
-		$post = get_post( $action_id );
513
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
514
-			/* translators: %s is the action ID */
515
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
516
-		}
517
-		do_action( 'action_scheduler_canceled_action', $action_id );
518
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
519
-		wp_trash_post( $action_id );
520
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
521
-	}
522
-
523
-	/**
524
-	 * Delete action.
525
-	 *
526
-	 * @param int $action_id Action ID.
527
-	 * @return void
528
-	 * @throws InvalidArgumentException If action is not identified.
529
-	 */
530
-	public function delete_action( $action_id ) {
531
-		$post = get_post( $action_id );
532
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
533
-			/* translators: %s is the action ID */
534
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
535
-		}
536
-		do_action( 'action_scheduler_deleted_action', $action_id );
537
-
538
-		wp_delete_post( $action_id, true );
539
-	}
540
-
541
-	/**
542
-	 * Get date for claim id.
543
-	 *
544
-	 * @param int $action_id Action ID.
545
-	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
546
-	 */
547
-	public function get_date( $action_id ) {
548
-		$next = $this->get_date_gmt( $action_id );
549
-		return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
550
-	}
551
-
552
-	/**
553
-	 * Get Date GMT.
554
-	 *
555
-	 * @param int $action_id Action ID.
556
-	 *
557
-	 * @throws InvalidArgumentException If $action_id is not identified.
558
-	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
559
-	 */
560
-	public function get_date_gmt( $action_id ) {
561
-		$post = get_post( $action_id );
562
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
563
-			/* translators: %s is the action ID */
564
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
565
-		}
566
-		if ( 'publish' === $post->post_status ) {
567
-			return as_get_datetime_object( $post->post_modified_gmt );
568
-		} else {
569
-			return as_get_datetime_object( $post->post_date_gmt );
570
-		}
571
-	}
572
-
573
-	/**
574
-	 * Stake claim.
575
-	 *
576
-	 * @param int      $max_actions Maximum number of actions.
577
-	 * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
578
-	 * @param array    $hooks       Claim only actions with a hook or hooks.
579
-	 * @param string   $group       Claim only actions in the given group.
580
-	 *
581
-	 * @return ActionScheduler_ActionClaim
582
-	 * @throws RuntimeException When there is an error staking a claim.
583
-	 * @throws InvalidArgumentException When the given group is not valid.
584
-	 */
585
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
586
-		$this->claim_before_date = $before_date;
587
-		$claim_id                = $this->generate_claim_id();
588
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
589
-		$action_ids              = $this->find_actions_by_claim_id( $claim_id );
590
-		$this->claim_before_date = null;
591
-
592
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
593
-	}
594
-
595
-	/**
596
-	 * Get claim count.
597
-	 *
598
-	 * @return int
599
-	 */
600
-	public function get_claim_count() {
601
-		global $wpdb;
602
-
603
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
604
-		return $wpdb->get_var(
605
-			$wpdb->prepare(
606
-				"SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
607
-				array( self::POST_TYPE )
608
-			)
609
-		);
610
-	}
611
-
612
-	/**
613
-	 * Generate claim id.
614
-	 *
615
-	 * @return string
616
-	 */
617
-	protected function generate_claim_id() {
618
-		$claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
619
-		return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
620
-	}
621
-
622
-	/**
623
-	 * Claim actions.
624
-	 *
625
-	 * @param string   $claim_id    Claim ID.
626
-	 * @param int      $limit       Limit.
627
-	 * @param DateTime $before_date Should use UTC timezone.
628
-	 * @param array    $hooks       Claim only actions with a hook or hooks.
629
-	 * @param string   $group       Claim only actions in the given group.
630
-	 *
631
-	 * @return int The number of actions that were claimed.
632
-	 * @throws RuntimeException  When there is a database error.
633
-	 */
634
-	protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
635
-		// Set up initial variables.
636
-		$date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
637
-		$limit_ids = ! empty( $group );
638
-		$ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
639
-
640
-		// If limiting by IDs and no posts found, then return early since we have nothing to update.
641
-		if ( $limit_ids && 0 === count( $ids ) ) {
642
-			return 0;
643
-		}
644
-
645
-		/**
646
-		 * Global wpdb object.
647
-		 *
648
-		 * @var wpdb $wpdb
649
-		 */
650
-		global $wpdb;
651
-
652
-		/*
7
+    const POST_TYPE         = 'scheduled-action';
8
+    const GROUP_TAXONOMY    = 'action-group';
9
+    const SCHEDULE_META_KEY = '_action_manager_schedule';
10
+    const DEPENDENCIES_MET  = 'as-post-store-dependencies-met';
11
+
12
+    /**
13
+     * Used to share information about the before_date property of claims internally.
14
+     *
15
+     * This is used in preference to passing the same information as a method param
16
+     * for backwards-compatibility reasons.
17
+     *
18
+     * @var DateTime|null
19
+     */
20
+    private $claim_before_date = null;
21
+
22
+    /**
23
+     * Local Timezone.
24
+     *
25
+     * @var DateTimeZone
26
+     */
27
+    protected $local_timezone = null;
28
+
29
+    /**
30
+     * Save action.
31
+     *
32
+     * @param ActionScheduler_Action $action Scheduled Action.
33
+     * @param DateTime               $scheduled_date Scheduled Date.
34
+     *
35
+     * @throws RuntimeException Throws an exception if the action could not be saved.
36
+     * @return int
37
+     */
38
+    public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
39
+        try {
40
+            $this->validate_action( $action );
41
+            $post_array = $this->create_post_array( $action, $scheduled_date );
42
+            $post_id    = $this->save_post_array( $post_array );
43
+            $this->save_post_schedule( $post_id, $action->get_schedule() );
44
+            $this->save_action_group( $post_id, $action->get_group() );
45
+            do_action( 'action_scheduler_stored_action', $post_id );
46
+            return $post_id;
47
+        } catch ( Exception $e ) {
48
+            /* translators: %s: action error message */
49
+            throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
50
+        }
51
+    }
52
+
53
+    /**
54
+     * Create post array.
55
+     *
56
+     * @param ActionScheduler_Action $action Scheduled Action.
57
+     * @param DateTime               $scheduled_date Scheduled Date.
58
+     *
59
+     * @return array Returns an array of post data.
60
+     */
61
+    protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
62
+        $post = array(
63
+            'post_type'     => self::POST_TYPE,
64
+            'post_title'    => $action->get_hook(),
65
+            'post_content'  => wp_json_encode( $action->get_args() ),
66
+            'post_status'   => ( $action->is_finished() ? 'publish' : 'pending' ),
67
+            'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
68
+            'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
69
+        );
70
+        return $post;
71
+    }
72
+
73
+    /**
74
+     * Save post array.
75
+     *
76
+     * @param array $post_array Post array.
77
+     * @return int Returns the post ID.
78
+     * @throws RuntimeException Throws an exception if the action could not be saved.
79
+     */
80
+    protected function save_post_array( $post_array ) {
81
+        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
82
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
83
+
84
+        $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
85
+
86
+        if ( $has_kses ) {
87
+            // Prevent KSES from corrupting JSON in post_content.
88
+            kses_remove_filters();
89
+        }
90
+
91
+        $post_id = wp_insert_post( $post_array );
92
+
93
+        if ( $has_kses ) {
94
+            kses_init_filters();
95
+        }
96
+
97
+        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
98
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
99
+
100
+        if ( is_wp_error( $post_id ) || empty( $post_id ) ) {
101
+            throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
102
+        }
103
+        return $post_id;
104
+    }
105
+
106
+    /**
107
+     * Filter insert post data.
108
+     *
109
+     * @param array $postdata Post data to filter.
110
+     *
111
+     * @return array
112
+     */
113
+    public function filter_insert_post_data( $postdata ) {
114
+        if ( self::POST_TYPE === $postdata['post_type'] ) {
115
+            $postdata['post_author'] = 0;
116
+            if ( 'future' === $postdata['post_status'] ) {
117
+                $postdata['post_status'] = 'publish';
118
+            }
119
+        }
120
+        return $postdata;
121
+    }
122
+
123
+    /**
124
+     * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug().
125
+     *
126
+     * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish'
127
+     * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug()
128
+     * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing
129
+     * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a
130
+     * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a
131
+     * database containing thousands of related post_name values.
132
+     *
133
+     * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue.
134
+     *
135
+     * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This
136
+     * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a
137
+     * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an
138
+     * action's slug, being probably unique is good enough.
139
+     *
140
+     * For more backstory on this issue, see:
141
+     * - https://github.com/woocommerce/action-scheduler/issues/44 and
142
+     * - https://core.trac.wordpress.org/ticket/21112
143
+     *
144
+     * @param string $override_slug Short-circuit return value.
145
+     * @param string $slug          The desired slug (post_name).
146
+     * @param int    $post_ID       Post ID.
147
+     * @param string $post_status   The post status.
148
+     * @param string $post_type     Post type.
149
+     * @return string
150
+     */
151
+    public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
152
+        if ( self::POST_TYPE === $post_type ) {
153
+            $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
154
+        }
155
+        return $override_slug;
156
+    }
157
+
158
+    /**
159
+     * Save post schedule.
160
+     *
161
+     * @param int    $post_id  Post ID of the scheduled action.
162
+     * @param string $schedule Schedule to save.
163
+     *
164
+     * @return void
165
+     */
166
+    protected function save_post_schedule( $post_id, $schedule ) {
167
+        update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
168
+    }
169
+
170
+    /**
171
+     * Save action group.
172
+     *
173
+     * @param int    $post_id Post ID.
174
+     * @param string $group   Group to save.
175
+     * @return void
176
+     */
177
+    protected function save_action_group( $post_id, $group ) {
178
+        if ( empty( $group ) ) {
179
+            wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
180
+        } else {
181
+            wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false );
182
+        }
183
+    }
184
+
185
+    /**
186
+     * Fetch actions.
187
+     *
188
+     * @param int $action_id Action ID.
189
+     * @return object
190
+     */
191
+    public function fetch_action( $action_id ) {
192
+        $post = $this->get_post( $action_id );
193
+        if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
194
+            return $this->get_null_action();
195
+        }
196
+
197
+        try {
198
+            $action = $this->make_action_from_post( $post );
199
+        } catch ( ActionScheduler_InvalidActionException $exception ) {
200
+            do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
201
+            return $this->get_null_action();
202
+        }
203
+
204
+        return $action;
205
+    }
206
+
207
+    /**
208
+     * Get post.
209
+     *
210
+     * @param string $action_id - Action ID.
211
+     * @return WP_Post|null
212
+     */
213
+    protected function get_post( $action_id ) {
214
+        if ( empty( $action_id ) ) {
215
+            return null;
216
+        }
217
+        return get_post( $action_id );
218
+    }
219
+
220
+    /**
221
+     * Get NULL action.
222
+     *
223
+     * @return ActionScheduler_NullAction
224
+     */
225
+    protected function get_null_action() {
226
+        return new ActionScheduler_NullAction();
227
+    }
228
+
229
+    /**
230
+     * Make action from post.
231
+     *
232
+     * @param WP_Post $post Post object.
233
+     * @return WP_Post
234
+     */
235
+    protected function make_action_from_post( $post ) {
236
+        $hook = $post->post_title;
237
+
238
+        $args = json_decode( $post->post_content, true );
239
+        $this->validate_args( $args, $post->ID );
240
+
241
+        $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
242
+        $this->validate_schedule( $schedule, $post->ID );
243
+
244
+        $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) );
245
+        $group = empty( $group ) ? '' : reset( $group );
246
+
247
+        return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
248
+    }
249
+
250
+    /**
251
+     * Get action status by post status.
252
+     *
253
+     * @param string $post_status Post status.
254
+     *
255
+     * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
256
+     * @return string
257
+     */
258
+    protected function get_action_status_by_post_status( $post_status ) {
259
+
260
+        switch ( $post_status ) {
261
+            case 'publish':
262
+                $action_status = self::STATUS_COMPLETE;
263
+                break;
264
+            case 'trash':
265
+                $action_status = self::STATUS_CANCELED;
266
+                break;
267
+            default:
268
+                if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
269
+                    throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
270
+                }
271
+                $action_status = $post_status;
272
+                break;
273
+        }
274
+
275
+        return $action_status;
276
+    }
277
+
278
+    /**
279
+     * Get post status by action status.
280
+     *
281
+     * @param string $action_status Action status.
282
+     *
283
+     * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
284
+     * @return string
285
+     */
286
+    protected function get_post_status_by_action_status( $action_status ) {
287
+
288
+        switch ( $action_status ) {
289
+            case self::STATUS_COMPLETE:
290
+                $post_status = 'publish';
291
+                break;
292
+            case self::STATUS_CANCELED:
293
+                $post_status = 'trash';
294
+                break;
295
+            default:
296
+                if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
297
+                    throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
298
+                }
299
+                $post_status = $action_status;
300
+                break;
301
+        }
302
+
303
+        return $post_status;
304
+    }
305
+
306
+    /**
307
+     * Returns the SQL statement to query (or count) actions.
308
+     *
309
+     * @param array  $query            - Filtering options.
310
+     * @param string $select_or_count  - Whether the SQL should select and return the IDs or just the row count.
311
+     *
312
+     * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
313
+     * @return string SQL statement. The returned SQL is already properly escaped.
314
+     */
315
+    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
316
+
317
+        if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
318
+            throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
319
+        }
320
+
321
+        $query = wp_parse_args(
322
+            $query,
323
+            array(
324
+                'hook'             => '',
325
+                'args'             => null,
326
+                'date'             => null,
327
+                'date_compare'     => '<=',
328
+                'modified'         => null,
329
+                'modified_compare' => '<=',
330
+                'group'            => '',
331
+                'status'           => '',
332
+                'claimed'          => null,
333
+                'per_page'         => 5,
334
+                'offset'           => 0,
335
+                'orderby'          => 'date',
336
+                'order'            => 'ASC',
337
+                'search'           => '',
338
+            )
339
+        );
340
+
341
+        /**
342
+         * Global wpdb object.
343
+         *
344
+         * @var wpdb $wpdb
345
+         */
346
+        global $wpdb;
347
+        $sql        = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
348
+        $sql       .= "FROM {$wpdb->posts} p";
349
+        $sql_params = array();
350
+        if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
351
+            $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
352
+            $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
353
+            $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
354
+        } elseif ( ! empty( $query['group'] ) ) {
355
+            $sql         .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
356
+            $sql         .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
357
+            $sql         .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
358
+            $sql         .= ' AND t.slug=%s';
359
+            $sql_params[] = $query['group'];
360
+        }
361
+        $sql         .= ' WHERE post_type=%s';
362
+        $sql_params[] = self::POST_TYPE;
363
+        if ( $query['hook'] ) {
364
+            $sql         .= ' AND p.post_title=%s';
365
+            $sql_params[] = $query['hook'];
366
+        }
367
+        if ( $query['args'] !== null ) {
368
+            $sql         .= ' AND p.post_content=%s';
369
+            $sql_params[] = wp_json_encode( $query['args'] );
370
+        }
371
+
372
+        if ( $query['status'] ) {
373
+            $post_statuses = array_map( array( $this, 'get_post_status_by_action_status' ), (array) $query['status'] );
374
+            $placeholders  = array_fill( 0, count( $post_statuses ), '%s' );
375
+            $sql          .= ' AND p.post_status IN (' . join( ', ', $placeholders ) . ')';
376
+            $sql_params    = array_merge( $sql_params, array_values( $post_statuses ) );
377
+        }
378
+
379
+        if ( $query['date'] instanceof DateTime ) {
380
+            $date = clone $query['date'];
381
+            $date->setTimezone( new DateTimeZone( 'UTC' ) );
382
+            $date_string  = $date->format( 'Y-m-d H:i:s' );
383
+            $comparator   = $this->validate_sql_comparator( $query['date_compare'] );
384
+            $sql         .= " AND p.post_date_gmt $comparator %s";
385
+            $sql_params[] = $date_string;
386
+        }
387
+
388
+        if ( $query['modified'] instanceof DateTime ) {
389
+            $modified = clone $query['modified'];
390
+            $modified->setTimezone( new DateTimeZone( 'UTC' ) );
391
+            $date_string  = $modified->format( 'Y-m-d H:i:s' );
392
+            $comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
393
+            $sql         .= " AND p.post_modified_gmt $comparator %s";
394
+            $sql_params[] = $date_string;
395
+        }
396
+
397
+        if ( true === $query['claimed'] ) {
398
+            $sql .= " AND p.post_password != ''";
399
+        } elseif ( false === $query['claimed'] ) {
400
+            $sql .= " AND p.post_password = ''";
401
+        } elseif ( $query['claimed'] !== null ) {
402
+            $sql         .= ' AND p.post_password = %s';
403
+            $sql_params[] = $query['claimed'];
404
+        }
405
+
406
+        if ( ! empty( $query['search'] ) ) {
407
+            $sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)';
408
+            for ( $i = 0; $i < 3; $i++ ) {
409
+                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
410
+            }
411
+        }
412
+
413
+        if ( 'select' === $select_or_count ) {
414
+            switch ( $query['orderby'] ) {
415
+                case 'hook':
416
+                    $orderby = 'p.post_title';
417
+                    break;
418
+                case 'group':
419
+                    $orderby = 't.name';
420
+                    break;
421
+                case 'status':
422
+                    $orderby = 'p.post_status';
423
+                    break;
424
+                case 'modified':
425
+                    $orderby = 'p.post_modified';
426
+                    break;
427
+                case 'claim_id':
428
+                    $orderby = 'p.post_password';
429
+                    break;
430
+                case 'schedule':
431
+                case 'date':
432
+                default:
433
+                    $orderby = 'p.post_date_gmt';
434
+                    break;
435
+            }
436
+            if ( 'ASC' === strtoupper( $query['order'] ) ) {
437
+                $order = 'ASC';
438
+            } else {
439
+                $order = 'DESC';
440
+            }
441
+            $sql .= " ORDER BY $orderby $order";
442
+            if ( $query['per_page'] > 0 ) {
443
+                $sql         .= ' LIMIT %d, %d';
444
+                $sql_params[] = $query['offset'];
445
+                $sql_params[] = $query['per_page'];
446
+            }
447
+        }
448
+
449
+        return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
450
+    }
451
+
452
+    /**
453
+     * Query for action count or list of action IDs.
454
+     *
455
+     * @since 3.3.0 $query['status'] accepts array of statuses instead of a single status.
456
+     *
457
+     * @see ActionScheduler_Store::query_actions for $query arg usage.
458
+     *
459
+     * @param array  $query      Query filtering options.
460
+     * @param string $query_type Whether to select or count the results. Defaults to select.
461
+     *
462
+     * @return string|array|null The IDs of actions matching the query. Null on failure.
463
+     */
464
+    public function query_actions( $query = array(), $query_type = 'select' ) {
465
+        /**
466
+         * Global $wpdb object.
467
+         *
468
+         * @var wpdb $wpdb
469
+         */
470
+        global $wpdb;
471
+
472
+        $sql = $this->get_query_actions_sql( $query, $query_type );
473
+
474
+        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
475
+    }
476
+
477
+    /**
478
+     * Get a count of all actions in the store, grouped by status
479
+     *
480
+     * @return array
481
+     */
482
+    public function action_counts() {
483
+
484
+        $action_counts_by_status = array();
485
+        $action_stati_and_labels = $this->get_status_labels();
486
+        $posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
487
+
488
+        foreach ( $posts_count_by_status as $post_status_name => $count ) {
489
+
490
+            try {
491
+                $action_status_name = $this->get_action_status_by_post_status( $post_status_name );
492
+            } catch ( Exception $e ) {
493
+                // Ignore any post statuses that aren't for actions.
494
+                continue;
495
+            }
496
+            if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
497
+                $action_counts_by_status[ $action_status_name ] = $count;
498
+            }
499
+        }
500
+
501
+        return $action_counts_by_status;
502
+    }
503
+
504
+    /**
505
+     * Cancel action.
506
+     *
507
+     * @param int $action_id Action ID.
508
+     *
509
+     * @throws InvalidArgumentException If $action_id is not identified.
510
+     */
511
+    public function cancel_action( $action_id ) {
512
+        $post = get_post( $action_id );
513
+        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
514
+            /* translators: %s is the action ID */
515
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
516
+        }
517
+        do_action( 'action_scheduler_canceled_action', $action_id );
518
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
519
+        wp_trash_post( $action_id );
520
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
521
+    }
522
+
523
+    /**
524
+     * Delete action.
525
+     *
526
+     * @param int $action_id Action ID.
527
+     * @return void
528
+     * @throws InvalidArgumentException If action is not identified.
529
+     */
530
+    public function delete_action( $action_id ) {
531
+        $post = get_post( $action_id );
532
+        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
533
+            /* translators: %s is the action ID */
534
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
535
+        }
536
+        do_action( 'action_scheduler_deleted_action', $action_id );
537
+
538
+        wp_delete_post( $action_id, true );
539
+    }
540
+
541
+    /**
542
+     * Get date for claim id.
543
+     *
544
+     * @param int $action_id Action ID.
545
+     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
546
+     */
547
+    public function get_date( $action_id ) {
548
+        $next = $this->get_date_gmt( $action_id );
549
+        return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
550
+    }
551
+
552
+    /**
553
+     * Get Date GMT.
554
+     *
555
+     * @param int $action_id Action ID.
556
+     *
557
+     * @throws InvalidArgumentException If $action_id is not identified.
558
+     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
559
+     */
560
+    public function get_date_gmt( $action_id ) {
561
+        $post = get_post( $action_id );
562
+        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
563
+            /* translators: %s is the action ID */
564
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
565
+        }
566
+        if ( 'publish' === $post->post_status ) {
567
+            return as_get_datetime_object( $post->post_modified_gmt );
568
+        } else {
569
+            return as_get_datetime_object( $post->post_date_gmt );
570
+        }
571
+    }
572
+
573
+    /**
574
+     * Stake claim.
575
+     *
576
+     * @param int      $max_actions Maximum number of actions.
577
+     * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
578
+     * @param array    $hooks       Claim only actions with a hook or hooks.
579
+     * @param string   $group       Claim only actions in the given group.
580
+     *
581
+     * @return ActionScheduler_ActionClaim
582
+     * @throws RuntimeException When there is an error staking a claim.
583
+     * @throws InvalidArgumentException When the given group is not valid.
584
+     */
585
+    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
586
+        $this->claim_before_date = $before_date;
587
+        $claim_id                = $this->generate_claim_id();
588
+        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
589
+        $action_ids              = $this->find_actions_by_claim_id( $claim_id );
590
+        $this->claim_before_date = null;
591
+
592
+        return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
593
+    }
594
+
595
+    /**
596
+     * Get claim count.
597
+     *
598
+     * @return int
599
+     */
600
+    public function get_claim_count() {
601
+        global $wpdb;
602
+
603
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
604
+        return $wpdb->get_var(
605
+            $wpdb->prepare(
606
+                "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
607
+                array( self::POST_TYPE )
608
+            )
609
+        );
610
+    }
611
+
612
+    /**
613
+     * Generate claim id.
614
+     *
615
+     * @return string
616
+     */
617
+    protected function generate_claim_id() {
618
+        $claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
619
+        return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
620
+    }
621
+
622
+    /**
623
+     * Claim actions.
624
+     *
625
+     * @param string   $claim_id    Claim ID.
626
+     * @param int      $limit       Limit.
627
+     * @param DateTime $before_date Should use UTC timezone.
628
+     * @param array    $hooks       Claim only actions with a hook or hooks.
629
+     * @param string   $group       Claim only actions in the given group.
630
+     *
631
+     * @return int The number of actions that were claimed.
632
+     * @throws RuntimeException  When there is a database error.
633
+     */
634
+    protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
635
+        // Set up initial variables.
636
+        $date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
637
+        $limit_ids = ! empty( $group );
638
+        $ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
639
+
640
+        // If limiting by IDs and no posts found, then return early since we have nothing to update.
641
+        if ( $limit_ids && 0 === count( $ids ) ) {
642
+            return 0;
643
+        }
644
+
645
+        /**
646
+         * Global wpdb object.
647
+         *
648
+         * @var wpdb $wpdb
649
+         */
650
+        global $wpdb;
651
+
652
+        /*
653 653
 		 * Build up custom query to update the affected posts. Parameters are built as a separate array
654 654
 		 * to make it easier to identify where they are in the query.
655 655
 		 *
656 656
 		 * We can't use $wpdb->update() here because of the "ID IN ..." clause.
657 657
 		 */
658
-		$update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
659
-		$params = array(
660
-			$claim_id,
661
-			current_time( 'mysql', true ),
662
-			current_time( 'mysql' ),
663
-		);
664
-
665
-		// Build initial WHERE clause.
666
-		$where    = "WHERE post_type = %s AND post_status = %s AND post_password = ''";
667
-		$params[] = self::POST_TYPE;
668
-		$params[] = ActionScheduler_Store::STATUS_PENDING;
669
-
670
-		if ( ! empty( $hooks ) ) {
671
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
672
-			$where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
673
-			$params       = array_merge( $params, array_values( $hooks ) );
674
-		}
675
-
676
-		/*
658
+        $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
659
+        $params = array(
660
+            $claim_id,
661
+            current_time( 'mysql', true ),
662
+            current_time( 'mysql' ),
663
+        );
664
+
665
+        // Build initial WHERE clause.
666
+        $where    = "WHERE post_type = %s AND post_status = %s AND post_password = ''";
667
+        $params[] = self::POST_TYPE;
668
+        $params[] = ActionScheduler_Store::STATUS_PENDING;
669
+
670
+        if ( ! empty( $hooks ) ) {
671
+            $placeholders = array_fill( 0, count( $hooks ), '%s' );
672
+            $where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
673
+            $params       = array_merge( $params, array_values( $hooks ) );
674
+        }
675
+
676
+        /*
677 677
 		 * Add the IDs to the WHERE clause. IDs not escaped because they came directly from a prior DB query.
678 678
 		 *
679 679
 		 * If we're not limiting by IDs, then include the post_date_gmt clause.
680 680
 		 */
681
-		if ( $limit_ids ) {
682
-			$where .= ' AND ID IN (' . join( ',', $ids ) . ')';
683
-		} else {
684
-			$where   .= ' AND post_date_gmt <= %s';
685
-			$params[] = $date->format( 'Y-m-d H:i:s' );
686
-		}
687
-
688
-		// Add the ORDER BY clause and,ms limit.
689
-		$order    = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d';
690
-		$params[] = $limit;
691
-
692
-		// Run the query and gather results.
693
-		$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
694
-
695
-		if ( false === $rows_affected ) {
696
-			throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
697
-		}
698
-
699
-		return (int) $rows_affected;
700
-	}
701
-
702
-	/**
703
-	 * Get IDs of actions within a certain group and up to a certain date/time.
704
-	 *
705
-	 * @param string   $group The group to use in finding actions.
706
-	 * @param int      $limit The number of actions to retrieve.
707
-	 * @param DateTime $date  DateTime object representing cutoff time for actions. Actions retrieved will be
708
-	 *                        up to and including this DateTime.
709
-	 *
710
-	 * @return array IDs of actions in the appropriate group and before the appropriate time.
711
-	 * @throws InvalidArgumentException When the group does not exist.
712
-	 */
713
-	protected function get_actions_by_group( $group, $limit, DateTime $date ) {
714
-		// Ensure the group exists before continuing.
715
-		if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
716
-			/* translators: %s is the group name */
717
-			throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
718
-		}
719
-
720
-		// Set up a query for post IDs to use later.
721
-		$query      = new WP_Query();
722
-		$query_args = array(
723
-			'fields'           => 'ids',
724
-			'post_type'        => self::POST_TYPE,
725
-			'post_status'      => ActionScheduler_Store::STATUS_PENDING,
726
-			'has_password'     => false,
727
-			'posts_per_page'   => $limit * 3,
728
-			'suppress_filters' => true,
729
-			'no_found_rows'    => true,
730
-			'orderby'          => array(
731
-				'menu_order' => 'ASC',
732
-				'date'       => 'ASC',
733
-				'ID'         => 'ASC',
734
-			),
735
-			'date_query'       => array(
736
-				'column'    => 'post_date_gmt',
737
-				'before'    => $date->format( 'Y-m-d H:i' ),
738
-				'inclusive' => true,
739
-			),
740
-			'tax_query'        => array( // phpcs:ignore WordPress.DB.SlowDBQuery
741
-				array(
742
-					'taxonomy'         => self::GROUP_TAXONOMY,
743
-					'field'            => 'slug',
744
-					'terms'            => $group,
745
-					'include_children' => false,
746
-				),
747
-			),
748
-		);
749
-
750
-		return $query->query( $query_args );
751
-	}
752
-
753
-	/**
754
-	 * Find actions by claim ID.
755
-	 *
756
-	 * @param string $claim_id Claim ID.
757
-	 * @return array
758
-	 */
759
-	public function find_actions_by_claim_id( $claim_id ) {
760
-		/**
761
-		 * Global wpdb object.
762
-		 *
763
-		 * @var wpdb $wpdb
764
-		 */
765
-		global $wpdb;
766
-
767
-		$action_ids  = array();
768
-		$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
769
-		$cut_off     = $before_date->format( 'Y-m-d H:i:s' );
770
-
771
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
772
-		$results = $wpdb->get_results(
773
-			$wpdb->prepare(
774
-				"SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s",
775
-				array(
776
-					self::POST_TYPE,
777
-					$claim_id,
778
-				)
779
-			)
780
-		);
781
-
782
-		// Verify that the scheduled date for each action is within the expected bounds (in some unusual
783
-		// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
784
-		foreach ( $results as $claimed_action ) {
785
-			if ( $claimed_action->post_date_gmt <= $cut_off ) {
786
-				$action_ids[] = absint( $claimed_action->ID );
787
-			}
788
-		}
789
-
790
-		return $action_ids;
791
-	}
792
-
793
-	/**
794
-	 * Release claim.
795
-	 *
796
-	 * @param ActionScheduler_ActionClaim $claim Claim object to release.
797
-	 * @return void
798
-	 * @throws RuntimeException When the claim is not unlocked.
799
-	 */
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
-		/**
807
-		 * Global wpdb object.
808
-		 *
809
-		 * @var wpdb $wpdb
810
-		 */
811
-		global $wpdb;
812
-
813
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
814
-		$result = $wpdb->query(
815
-			$wpdb->prepare(
816
-				"UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore
817
-				array(
818
-					$claim->get_id(),
819
-				)
820
-			)
821
-		);
822
-		if ( false === $result ) {
823
-			/* translators: %s: claim ID */
824
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
825
-		}
826
-	}
827
-
828
-	/**
829
-	 * Unclaim action.
830
-	 *
831
-	 * @param string $action_id Action ID.
832
-	 * @throws RuntimeException When unable to unlock claim on action ID.
833
-	 */
834
-	public function unclaim_action( $action_id ) {
835
-		/**
836
-		 * Global wpdb object.
837
-		 *
838
-		 * @var wpdb $wpdb
839
-		 */
840
-		global $wpdb;
841
-
842
-		//phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
843
-		$result = $wpdb->query(
844
-			$wpdb->prepare(
845
-				"UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s",
846
-				$action_id,
847
-				self::POST_TYPE
848
-			)
849
-		);
850
-		if ( false === $result ) {
851
-			/* translators: %s: action ID */
852
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
853
-		}
854
-	}
855
-
856
-	/**
857
-	 * Mark failure on action.
858
-	 *
859
-	 * @param int $action_id Action ID.
860
-	 *
861
-	 * @return void
862
-	 * @throws RuntimeException When unable to mark failure on action ID.
863
-	 */
864
-	public function mark_failure( $action_id ) {
865
-		/**
866
-		 * Global wpdb object.
867
-		 *
868
-		 * @var wpdb $wpdb
869
-		 */
870
-		global $wpdb;
871
-
872
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
873
-		$result = $wpdb->query(
874
-			$wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
875
-		);
876
-		if ( false === $result ) {
877
-			/* translators: %s: action ID */
878
-			throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
879
-		}
880
-	}
881
-
882
-	/**
883
-	 * Return an action's claim ID, as stored in the post password column
884
-	 *
885
-	 * @param int $action_id Action ID.
886
-	 * @return mixed
887
-	 */
888
-	public function get_claim_id( $action_id ) {
889
-		return $this->get_post_column( $action_id, 'post_password' );
890
-	}
891
-
892
-	/**
893
-	 * Return an action's status, as stored in the post status column
894
-	 *
895
-	 * @param int $action_id Action ID.
896
-	 *
897
-	 * @return mixed
898
-	 * @throws InvalidArgumentException When the action ID is invalid.
899
-	 */
900
-	public function get_status( $action_id ) {
901
-		$status = $this->get_post_column( $action_id, 'post_status' );
902
-
903
-		if ( null === $status ) {
904
-			throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
905
-		}
906
-
907
-		return $this->get_action_status_by_post_status( $status );
908
-	}
909
-
910
-	/**
911
-	 * Get post column
912
-	 *
913
-	 * @param string $action_id Action ID.
914
-	 * @param string $column_name Column Name.
915
-	 *
916
-	 * @return string|null
917
-	 */
918
-	private function get_post_column( $action_id, $column_name ) {
919
-		/**
920
-		 * Global wpdb object.
921
-		 *
922
-		 * @var wpdb $wpdb
923
-		 */
924
-		global $wpdb;
925
-
926
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
927
-		return $wpdb->get_var(
928
-			$wpdb->prepare(
929
-				"SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore
930
-				$action_id,
931
-				self::POST_TYPE
932
-			)
933
-		);
934
-	}
935
-
936
-	/**
937
-	 * Log Execution.
938
-	 *
939
-	 * @param string $action_id Action ID.
940
-	 */
941
-	public function log_execution( $action_id ) {
942
-		/**
943
-		 * Global wpdb object.
944
-		 *
945
-		 * @var wpdb $wpdb
946
-		 */
947
-		global $wpdb;
948
-
949
-		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
950
-		$wpdb->query(
951
-			$wpdb->prepare(
952
-				"UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s",
953
-				self::STATUS_RUNNING,
954
-				current_time( 'mysql', true ),
955
-				current_time( 'mysql' ),
956
-				$action_id,
957
-				self::POST_TYPE
958
-			)
959
-		);
960
-	}
961
-
962
-	/**
963
-	 * Record that an action was completed.
964
-	 *
965
-	 * @param string $action_id ID of the completed action.
966
-	 *
967
-	 * @throws InvalidArgumentException When the action ID is invalid.
968
-	 * @throws RuntimeException         When there was an error executing the action.
969
-	 */
970
-	public function mark_complete( $action_id ) {
971
-		$post = get_post( $action_id );
972
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
973
-			/* translators: %s is the action ID */
974
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
975
-		}
976
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
977
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
978
-		$result = wp_update_post(
979
-			array(
980
-				'ID'          => $action_id,
981
-				'post_status' => 'publish',
982
-			),
983
-			true
984
-		);
985
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
986
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
987
-		if ( is_wp_error( $result ) ) {
988
-			throw new RuntimeException( $result->get_error_message() );
989
-		}
990
-
991
-		/**
992
-		 * Fires after a scheduled action has been completed.
993
-		 *
994
-		 * @since 3.4.2
995
-		 *
996
-		 * @param int $action_id Action ID.
997
-		 */
998
-		do_action( 'action_scheduler_completed_action', $action_id );
999
-	}
1000
-
1001
-	/**
1002
-	 * Mark action as migrated when there is an error deleting the action.
1003
-	 *
1004
-	 * @param int $action_id Action ID.
1005
-	 */
1006
-	public function mark_migrated( $action_id ) {
1007
-		wp_update_post(
1008
-			array(
1009
-				'ID'          => $action_id,
1010
-				'post_status' => 'migrated',
1011
-			)
1012
-		);
1013
-	}
1014
-
1015
-	/**
1016
-	 * Determine whether the post store can be migrated.
1017
-	 *
1018
-	 * @param [type] $setting - Setting value.
1019
-	 * @return bool
1020
-	 */
1021
-	public function migration_dependencies_met( $setting ) {
1022
-		global $wpdb;
1023
-
1024
-		$dependencies_met = get_transient( self::DEPENDENCIES_MET );
1025
-		if ( empty( $dependencies_met ) ) {
1026
-			$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
1027
-			$found_action        = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1028
-				$wpdb->prepare(
1029
-					"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
1030
-					$maximum_args_length,
1031
-					self::POST_TYPE
1032
-				)
1033
-			);
1034
-			$dependencies_met    = $found_action ? 'no' : 'yes';
1035
-			set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
1036
-		}
1037
-
1038
-		return 'yes' === $dependencies_met ? $setting : false;
1039
-	}
1040
-
1041
-	/**
1042
-	 * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
1043
-	 *
1044
-	 * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However,
1045
-	 * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
1046
-	 * developers of this impending requirement.
1047
-	 *
1048
-	 * @param ActionScheduler_Action $action Action object.
1049
-	 */
1050
-	protected function validate_action( ActionScheduler_Action $action ) {
1051
-		try {
1052
-			parent::validate_action( $action );
1053
-		} catch ( Exception $e ) {
1054
-			/* translators: %s is the error message */
1055
-			$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
1056
-			_doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
1057
-		}
1058
-	}
1059
-
1060
-	/**
1061
-	 * (@codeCoverageIgnore)
1062
-	 */
1063
-	public function init() {
1064
-		add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
1065
-
1066
-		$post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
1067
-		$post_type_registrar->register();
1068
-
1069
-		$post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar();
1070
-		$post_status_registrar->register();
1071
-
1072
-		$taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
1073
-		$taxonomy_registrar->register();
1074
-	}
681
+        if ( $limit_ids ) {
682
+            $where .= ' AND ID IN (' . join( ',', $ids ) . ')';
683
+        } else {
684
+            $where   .= ' AND post_date_gmt <= %s';
685
+            $params[] = $date->format( 'Y-m-d H:i:s' );
686
+        }
687
+
688
+        // Add the ORDER BY clause and,ms limit.
689
+        $order    = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d';
690
+        $params[] = $limit;
691
+
692
+        // Run the query and gather results.
693
+        $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
694
+
695
+        if ( false === $rows_affected ) {
696
+            throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
697
+        }
698
+
699
+        return (int) $rows_affected;
700
+    }
701
+
702
+    /**
703
+     * Get IDs of actions within a certain group and up to a certain date/time.
704
+     *
705
+     * @param string   $group The group to use in finding actions.
706
+     * @param int      $limit The number of actions to retrieve.
707
+     * @param DateTime $date  DateTime object representing cutoff time for actions. Actions retrieved will be
708
+     *                        up to and including this DateTime.
709
+     *
710
+     * @return array IDs of actions in the appropriate group and before the appropriate time.
711
+     * @throws InvalidArgumentException When the group does not exist.
712
+     */
713
+    protected function get_actions_by_group( $group, $limit, DateTime $date ) {
714
+        // Ensure the group exists before continuing.
715
+        if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
716
+            /* translators: %s is the group name */
717
+            throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
718
+        }
719
+
720
+        // Set up a query for post IDs to use later.
721
+        $query      = new WP_Query();
722
+        $query_args = array(
723
+            'fields'           => 'ids',
724
+            'post_type'        => self::POST_TYPE,
725
+            'post_status'      => ActionScheduler_Store::STATUS_PENDING,
726
+            'has_password'     => false,
727
+            'posts_per_page'   => $limit * 3,
728
+            'suppress_filters' => true,
729
+            'no_found_rows'    => true,
730
+            'orderby'          => array(
731
+                'menu_order' => 'ASC',
732
+                'date'       => 'ASC',
733
+                'ID'         => 'ASC',
734
+            ),
735
+            'date_query'       => array(
736
+                'column'    => 'post_date_gmt',
737
+                'before'    => $date->format( 'Y-m-d H:i' ),
738
+                'inclusive' => true,
739
+            ),
740
+            'tax_query'        => array( // phpcs:ignore WordPress.DB.SlowDBQuery
741
+                array(
742
+                    'taxonomy'         => self::GROUP_TAXONOMY,
743
+                    'field'            => 'slug',
744
+                    'terms'            => $group,
745
+                    'include_children' => false,
746
+                ),
747
+            ),
748
+        );
749
+
750
+        return $query->query( $query_args );
751
+    }
752
+
753
+    /**
754
+     * Find actions by claim ID.
755
+     *
756
+     * @param string $claim_id Claim ID.
757
+     * @return array
758
+     */
759
+    public function find_actions_by_claim_id( $claim_id ) {
760
+        /**
761
+         * Global wpdb object.
762
+         *
763
+         * @var wpdb $wpdb
764
+         */
765
+        global $wpdb;
766
+
767
+        $action_ids  = array();
768
+        $before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
769
+        $cut_off     = $before_date->format( 'Y-m-d H:i:s' );
770
+
771
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
772
+        $results = $wpdb->get_results(
773
+            $wpdb->prepare(
774
+                "SELECT ID, post_date_gmt FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s",
775
+                array(
776
+                    self::POST_TYPE,
777
+                    $claim_id,
778
+                )
779
+            )
780
+        );
781
+
782
+        // Verify that the scheduled date for each action is within the expected bounds (in some unusual
783
+        // cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
784
+        foreach ( $results as $claimed_action ) {
785
+            if ( $claimed_action->post_date_gmt <= $cut_off ) {
786
+                $action_ids[] = absint( $claimed_action->ID );
787
+            }
788
+        }
789
+
790
+        return $action_ids;
791
+    }
792
+
793
+    /**
794
+     * Release claim.
795
+     *
796
+     * @param ActionScheduler_ActionClaim $claim Claim object to release.
797
+     * @return void
798
+     * @throws RuntimeException When the claim is not unlocked.
799
+     */
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
+        /**
807
+         * Global wpdb object.
808
+         *
809
+         * @var wpdb $wpdb
810
+         */
811
+        global $wpdb;
812
+
813
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
814
+        $result = $wpdb->query(
815
+            $wpdb->prepare(
816
+                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s", //phpcs:ignore
817
+                array(
818
+                    $claim->get_id(),
819
+                )
820
+            )
821
+        );
822
+        if ( false === $result ) {
823
+            /* translators: %s: claim ID */
824
+            throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
825
+        }
826
+    }
827
+
828
+    /**
829
+     * Unclaim action.
830
+     *
831
+     * @param string $action_id Action ID.
832
+     * @throws RuntimeException When unable to unlock claim on action ID.
833
+     */
834
+    public function unclaim_action( $action_id ) {
835
+        /**
836
+         * Global wpdb object.
837
+         *
838
+         * @var wpdb $wpdb
839
+         */
840
+        global $wpdb;
841
+
842
+        //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
843
+        $result = $wpdb->query(
844
+            $wpdb->prepare(
845
+                "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s",
846
+                $action_id,
847
+                self::POST_TYPE
848
+            )
849
+        );
850
+        if ( false === $result ) {
851
+            /* translators: %s: action ID */
852
+            throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
853
+        }
854
+    }
855
+
856
+    /**
857
+     * Mark failure on action.
858
+     *
859
+     * @param int $action_id Action ID.
860
+     *
861
+     * @return void
862
+     * @throws RuntimeException When unable to mark failure on action ID.
863
+     */
864
+    public function mark_failure( $action_id ) {
865
+        /**
866
+         * Global wpdb object.
867
+         *
868
+         * @var wpdb $wpdb
869
+         */
870
+        global $wpdb;
871
+
872
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
873
+        $result = $wpdb->query(
874
+            $wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
875
+        );
876
+        if ( false === $result ) {
877
+            /* translators: %s: action ID */
878
+            throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
879
+        }
880
+    }
881
+
882
+    /**
883
+     * Return an action's claim ID, as stored in the post password column
884
+     *
885
+     * @param int $action_id Action ID.
886
+     * @return mixed
887
+     */
888
+    public function get_claim_id( $action_id ) {
889
+        return $this->get_post_column( $action_id, 'post_password' );
890
+    }
891
+
892
+    /**
893
+     * Return an action's status, as stored in the post status column
894
+     *
895
+     * @param int $action_id Action ID.
896
+     *
897
+     * @return mixed
898
+     * @throws InvalidArgumentException When the action ID is invalid.
899
+     */
900
+    public function get_status( $action_id ) {
901
+        $status = $this->get_post_column( $action_id, 'post_status' );
902
+
903
+        if ( null === $status ) {
904
+            throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
905
+        }
906
+
907
+        return $this->get_action_status_by_post_status( $status );
908
+    }
909
+
910
+    /**
911
+     * Get post column
912
+     *
913
+     * @param string $action_id Action ID.
914
+     * @param string $column_name Column Name.
915
+     *
916
+     * @return string|null
917
+     */
918
+    private function get_post_column( $action_id, $column_name ) {
919
+        /**
920
+         * Global wpdb object.
921
+         *
922
+         * @var wpdb $wpdb
923
+         */
924
+        global $wpdb;
925
+
926
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
927
+        return $wpdb->get_var(
928
+            $wpdb->prepare(
929
+                "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", // phpcs:ignore
930
+                $action_id,
931
+                self::POST_TYPE
932
+            )
933
+        );
934
+    }
935
+
936
+    /**
937
+     * Log Execution.
938
+     *
939
+     * @param string $action_id Action ID.
940
+     */
941
+    public function log_execution( $action_id ) {
942
+        /**
943
+         * Global wpdb object.
944
+         *
945
+         * @var wpdb $wpdb
946
+         */
947
+        global $wpdb;
948
+
949
+        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
950
+        $wpdb->query(
951
+            $wpdb->prepare(
952
+                "UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s",
953
+                self::STATUS_RUNNING,
954
+                current_time( 'mysql', true ),
955
+                current_time( 'mysql' ),
956
+                $action_id,
957
+                self::POST_TYPE
958
+            )
959
+        );
960
+    }
961
+
962
+    /**
963
+     * Record that an action was completed.
964
+     *
965
+     * @param string $action_id ID of the completed action.
966
+     *
967
+     * @throws InvalidArgumentException When the action ID is invalid.
968
+     * @throws RuntimeException         When there was an error executing the action.
969
+     */
970
+    public function mark_complete( $action_id ) {
971
+        $post = get_post( $action_id );
972
+        if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
973
+            /* translators: %s is the action ID */
974
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
975
+        }
976
+        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
977
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
978
+        $result = wp_update_post(
979
+            array(
980
+                'ID'          => $action_id,
981
+                'post_status' => 'publish',
982
+            ),
983
+            true
984
+        );
985
+        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
986
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
987
+        if ( is_wp_error( $result ) ) {
988
+            throw new RuntimeException( $result->get_error_message() );
989
+        }
990
+
991
+        /**
992
+         * Fires after a scheduled action has been completed.
993
+         *
994
+         * @since 3.4.2
995
+         *
996
+         * @param int $action_id Action ID.
997
+         */
998
+        do_action( 'action_scheduler_completed_action', $action_id );
999
+    }
1000
+
1001
+    /**
1002
+     * Mark action as migrated when there is an error deleting the action.
1003
+     *
1004
+     * @param int $action_id Action ID.
1005
+     */
1006
+    public function mark_migrated( $action_id ) {
1007
+        wp_update_post(
1008
+            array(
1009
+                'ID'          => $action_id,
1010
+                'post_status' => 'migrated',
1011
+            )
1012
+        );
1013
+    }
1014
+
1015
+    /**
1016
+     * Determine whether the post store can be migrated.
1017
+     *
1018
+     * @param [type] $setting - Setting value.
1019
+     * @return bool
1020
+     */
1021
+    public function migration_dependencies_met( $setting ) {
1022
+        global $wpdb;
1023
+
1024
+        $dependencies_met = get_transient( self::DEPENDENCIES_MET );
1025
+        if ( empty( $dependencies_met ) ) {
1026
+            $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
1027
+            $found_action        = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1028
+                $wpdb->prepare(
1029
+                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
1030
+                    $maximum_args_length,
1031
+                    self::POST_TYPE
1032
+                )
1033
+            );
1034
+            $dependencies_met    = $found_action ? 'no' : 'yes';
1035
+            set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
1036
+        }
1037
+
1038
+        return 'yes' === $dependencies_met ? $setting : false;
1039
+    }
1040
+
1041
+    /**
1042
+     * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
1043
+     *
1044
+     * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However,
1045
+     * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
1046
+     * developers of this impending requirement.
1047
+     *
1048
+     * @param ActionScheduler_Action $action Action object.
1049
+     */
1050
+    protected function validate_action( ActionScheduler_Action $action ) {
1051
+        try {
1052
+            parent::validate_action( $action );
1053
+        } catch ( Exception $e ) {
1054
+            /* translators: %s is the error message */
1055
+            $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
1056
+            _doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
1057
+        }
1058
+    }
1059
+
1060
+    /**
1061
+     * (@codeCoverageIgnore)
1062
+     */
1063
+    public function init() {
1064
+        add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
1065
+
1066
+        $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
1067
+        $post_type_registrar->register();
1068
+
1069
+        $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar();
1070
+        $post_status_registrar->register();
1071
+
1072
+        $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
1073
+        $taxonomy_registrar->register();
1074
+    }
1075 1075
 }
Please login to merge, or discard this patch.
Spacing   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -35,18 +35,18 @@  discard block
 block discarded – undo
35 35
 	 * @throws RuntimeException Throws an exception if the action could not be saved.
36 36
 	 * @return int
37 37
 	 */
38
-	public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
38
+	public function save_action(ActionScheduler_Action $action, DateTime $scheduled_date = null) {
39 39
 		try {
40
-			$this->validate_action( $action );
41
-			$post_array = $this->create_post_array( $action, $scheduled_date );
42
-			$post_id    = $this->save_post_array( $post_array );
43
-			$this->save_post_schedule( $post_id, $action->get_schedule() );
44
-			$this->save_action_group( $post_id, $action->get_group() );
45
-			do_action( 'action_scheduler_stored_action', $post_id );
40
+			$this->validate_action($action);
41
+			$post_array = $this->create_post_array($action, $scheduled_date);
42
+			$post_id    = $this->save_post_array($post_array);
43
+			$this->save_post_schedule($post_id, $action->get_schedule());
44
+			$this->save_action_group($post_id, $action->get_group());
45
+			do_action('action_scheduler_stored_action', $post_id);
46 46
 			return $post_id;
47
-		} catch ( Exception $e ) {
47
+		} catch (Exception $e) {
48 48
 			/* translators: %s: action error message */
49
-			throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
49
+			throw new RuntimeException(sprintf(__('Error saving action: %s', 'action-scheduler'), $e->getMessage()), 0);
50 50
 		}
51 51
 	}
52 52
 
@@ -58,14 +58,14 @@  discard block
 block discarded – undo
58 58
 	 *
59 59
 	 * @return array Returns an array of post data.
60 60
 	 */
61
-	protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = null ) {
61
+	protected function create_post_array(ActionScheduler_Action $action, DateTime $scheduled_date = null) {
62 62
 		$post = array(
63 63
 			'post_type'     => self::POST_TYPE,
64 64
 			'post_title'    => $action->get_hook(),
65
-			'post_content'  => wp_json_encode( $action->get_args() ),
66
-			'post_status'   => ( $action->is_finished() ? 'publish' : 'pending' ),
67
-			'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
68
-			'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
65
+			'post_content'  => wp_json_encode($action->get_args()),
66
+			'post_status'   => ($action->is_finished() ? 'publish' : 'pending'),
67
+			'post_date_gmt' => $this->get_scheduled_date_string($action, $scheduled_date),
68
+			'post_date'     => $this->get_scheduled_date_string_local($action, $scheduled_date),
69 69
 		);
70 70
 		return $post;
71 71
 	}
@@ -77,28 +77,28 @@  discard block
 block discarded – undo
77 77
 	 * @return int Returns the post ID.
78 78
 	 * @throws RuntimeException Throws an exception if the action could not be saved.
79 79
 	 */
80
-	protected function save_post_array( $post_array ) {
81
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
82
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
80
+	protected function save_post_array($post_array) {
81
+		add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
82
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
83 83
 
84
-		$has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
84
+		$has_kses = false !== has_filter('content_save_pre', 'wp_filter_post_kses');
85 85
 
86
-		if ( $has_kses ) {
86
+		if ($has_kses) {
87 87
 			// Prevent KSES from corrupting JSON in post_content.
88 88
 			kses_remove_filters();
89 89
 		}
90 90
 
91
-		$post_id = wp_insert_post( $post_array );
91
+		$post_id = wp_insert_post($post_array);
92 92
 
93
-		if ( $has_kses ) {
93
+		if ($has_kses) {
94 94
 			kses_init_filters();
95 95
 		}
96 96
 
97
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
98
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
97
+		remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
98
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
99 99
 
100
-		if ( is_wp_error( $post_id ) || empty( $post_id ) ) {
101
-			throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
100
+		if (is_wp_error($post_id) || empty($post_id)) {
101
+			throw new RuntimeException(__('Unable to save action.', 'action-scheduler'));
102 102
 		}
103 103
 		return $post_id;
104 104
 	}
@@ -110,10 +110,10 @@  discard block
 block discarded – undo
110 110
 	 *
111 111
 	 * @return array
112 112
 	 */
113
-	public function filter_insert_post_data( $postdata ) {
114
-		if ( self::POST_TYPE === $postdata['post_type'] ) {
113
+	public function filter_insert_post_data($postdata) {
114
+		if (self::POST_TYPE === $postdata['post_type']) {
115 115
 			$postdata['post_author'] = 0;
116
-			if ( 'future' === $postdata['post_status'] ) {
116
+			if ('future' === $postdata['post_status']) {
117 117
 				$postdata['post_status'] = 'publish';
118 118
 			}
119 119
 		}
@@ -148,9 +148,9 @@  discard block
 block discarded – undo
148 148
 	 * @param string $post_type     Post type.
149 149
 	 * @return string
150 150
 	 */
151
-	public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
152
-		if ( self::POST_TYPE === $post_type ) {
153
-			$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
151
+	public function set_unique_post_slug($override_slug, $slug, $post_ID, $post_status, $post_type) {
152
+		if (self::POST_TYPE === $post_type) {
153
+			$override_slug = uniqid(self::POST_TYPE.'-', true).'-'.wp_generate_password(32, false);
154 154
 		}
155 155
 		return $override_slug;
156 156
 	}
@@ -163,8 +163,8 @@  discard block
 block discarded – undo
163 163
 	 *
164 164
 	 * @return void
165 165
 	 */
166
-	protected function save_post_schedule( $post_id, $schedule ) {
167
-		update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
166
+	protected function save_post_schedule($post_id, $schedule) {
167
+		update_post_meta($post_id, self::SCHEDULE_META_KEY, $schedule);
168 168
 	}
169 169
 
170 170
 	/**
@@ -174,11 +174,11 @@  discard block
 block discarded – undo
174 174
 	 * @param string $group   Group to save.
175 175
 	 * @return void
176 176
 	 */
177
-	protected function save_action_group( $post_id, $group ) {
178
-		if ( empty( $group ) ) {
179
-			wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, false );
177
+	protected function save_action_group($post_id, $group) {
178
+		if (empty($group)) {
179
+			wp_set_object_terms($post_id, array(), self::GROUP_TAXONOMY, false);
180 180
 		} else {
181
-			wp_set_object_terms( $post_id, array( $group ), self::GROUP_TAXONOMY, false );
181
+			wp_set_object_terms($post_id, array($group), self::GROUP_TAXONOMY, false);
182 182
 		}
183 183
 	}
184 184
 
@@ -188,16 +188,16 @@  discard block
 block discarded – undo
188 188
 	 * @param int $action_id Action ID.
189 189
 	 * @return object
190 190
 	 */
191
-	public function fetch_action( $action_id ) {
192
-		$post = $this->get_post( $action_id );
193
-		if ( empty( $post ) || self::POST_TYPE !== $post->post_type ) {
191
+	public function fetch_action($action_id) {
192
+		$post = $this->get_post($action_id);
193
+		if (empty($post) || self::POST_TYPE !== $post->post_type) {
194 194
 			return $this->get_null_action();
195 195
 		}
196 196
 
197 197
 		try {
198
-			$action = $this->make_action_from_post( $post );
199
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
200
-			do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
198
+			$action = $this->make_action_from_post($post);
199
+		} catch (ActionScheduler_InvalidActionException $exception) {
200
+			do_action('action_scheduler_failed_fetch_action', $post->ID, $exception);
201 201
 			return $this->get_null_action();
202 202
 		}
203 203
 
@@ -210,11 +210,11 @@  discard block
 block discarded – undo
210 210
 	 * @param string $action_id - Action ID.
211 211
 	 * @return WP_Post|null
212 212
 	 */
213
-	protected function get_post( $action_id ) {
214
-		if ( empty( $action_id ) ) {
213
+	protected function get_post($action_id) {
214
+		if (empty($action_id)) {
215 215
 			return null;
216 216
 		}
217
-		return get_post( $action_id );
217
+		return get_post($action_id);
218 218
 	}
219 219
 
220 220
 	/**
@@ -232,19 +232,19 @@  discard block
 block discarded – undo
232 232
 	 * @param WP_Post $post Post object.
233 233
 	 * @return WP_Post
234 234
 	 */
235
-	protected function make_action_from_post( $post ) {
235
+	protected function make_action_from_post($post) {
236 236
 		$hook = $post->post_title;
237 237
 
238
-		$args = json_decode( $post->post_content, true );
239
-		$this->validate_args( $args, $post->ID );
238
+		$args = json_decode($post->post_content, true);
239
+		$this->validate_args($args, $post->ID);
240 240
 
241
-		$schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
242
-		$this->validate_schedule( $schedule, $post->ID );
241
+		$schedule = get_post_meta($post->ID, self::SCHEDULE_META_KEY, true);
242
+		$this->validate_schedule($schedule, $post->ID);
243 243
 
244
-		$group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array( 'fields' => 'names' ) );
245
-		$group = empty( $group ) ? '' : reset( $group );
244
+		$group = wp_get_object_terms($post->ID, self::GROUP_TAXONOMY, array('fields' => 'names'));
245
+		$group = empty($group) ? '' : reset($group);
246 246
 
247
-		return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
247
+		return ActionScheduler::factory()->get_stored_action($this->get_action_status_by_post_status($post->post_status), $hook, $args, $schedule, $group);
248 248
 	}
249 249
 
250 250
 	/**
@@ -255,9 +255,9 @@  discard block
 block discarded – undo
255 255
 	 * @throws InvalidArgumentException Throw InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
256 256
 	 * @return string
257 257
 	 */
258
-	protected function get_action_status_by_post_status( $post_status ) {
258
+	protected function get_action_status_by_post_status($post_status) {
259 259
 
260
-		switch ( $post_status ) {
260
+		switch ($post_status) {
261 261
 			case 'publish':
262 262
 				$action_status = self::STATUS_COMPLETE;
263 263
 				break;
@@ -265,8 +265,8 @@  discard block
 block discarded – undo
265 265
 				$action_status = self::STATUS_CANCELED;
266 266
 				break;
267 267
 			default:
268
-				if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
269
-					throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
268
+				if ( ! array_key_exists($post_status, $this->get_status_labels())) {
269
+					throw new InvalidArgumentException(sprintf('Invalid post status: "%s". No matching action status available.', $post_status));
270 270
 				}
271 271
 				$action_status = $post_status;
272 272
 				break;
@@ -283,9 +283,9 @@  discard block
 block discarded – undo
283 283
 	 * @throws InvalidArgumentException Throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels().
284 284
 	 * @return string
285 285
 	 */
286
-	protected function get_post_status_by_action_status( $action_status ) {
286
+	protected function get_post_status_by_action_status($action_status) {
287 287
 
288
-		switch ( $action_status ) {
288
+		switch ($action_status) {
289 289
 			case self::STATUS_COMPLETE:
290 290
 				$post_status = 'publish';
291 291
 				break;
@@ -293,8 +293,8 @@  discard block
 block discarded – undo
293 293
 				$post_status = 'trash';
294 294
 				break;
295 295
 			default:
296
-				if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
297
-					throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
296
+				if ( ! array_key_exists($action_status, $this->get_status_labels())) {
297
+					throw new InvalidArgumentException(sprintf('Invalid action status: "%s".', $action_status));
298 298
 				}
299 299
 				$post_status = $action_status;
300 300
 				break;
@@ -312,10 +312,10 @@  discard block
 block discarded – undo
312 312
 	 * @throws InvalidArgumentException - Throw InvalidArgumentException if $select_or_count not count or select.
313 313
 	 * @return string SQL statement. The returned SQL is already properly escaped.
314 314
 	 */
315
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
315
+	protected function get_query_actions_sql(array $query, $select_or_count = 'select') {
316 316
 
317
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ), true ) ) {
318
-			throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
317
+		if ( ! in_array($select_or_count, array('select', 'count'), true)) {
318
+			throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'action-scheduler'));
319 319
 		}
320 320
 
321 321
 		$query = wp_parse_args(
@@ -344,14 +344,14 @@  discard block
 block discarded – undo
344 344
 		 * @var wpdb $wpdb
345 345
 		 */
346 346
 		global $wpdb;
347
-		$sql        = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
347
+		$sql        = ('count' === $select_or_count) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
348 348
 		$sql       .= "FROM {$wpdb->posts} p";
349 349
 		$sql_params = array();
350
-		if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
350
+		if (empty($query['group']) && 'group' === $query['orderby']) {
351 351
 			$sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
352 352
 			$sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
353 353
 			$sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
354
-		} elseif ( ! empty( $query['group'] ) ) {
354
+		} elseif ( ! empty($query['group'])) {
355 355
 			$sql         .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
356 356
 			$sql         .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
357 357
 			$sql         .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
@@ -360,58 +360,58 @@  discard block
 block discarded – undo
360 360
 		}
361 361
 		$sql         .= ' WHERE post_type=%s';
362 362
 		$sql_params[] = self::POST_TYPE;
363
-		if ( $query['hook'] ) {
363
+		if ($query['hook']) {
364 364
 			$sql         .= ' AND p.post_title=%s';
365 365
 			$sql_params[] = $query['hook'];
366 366
 		}
367
-		if ( $query['args'] !== null ) {
367
+		if ($query['args'] !== null) {
368 368
 			$sql         .= ' AND p.post_content=%s';
369
-			$sql_params[] = wp_json_encode( $query['args'] );
369
+			$sql_params[] = wp_json_encode($query['args']);
370 370
 		}
371 371
 
372
-		if ( $query['status'] ) {
373
-			$post_statuses = array_map( array( $this, 'get_post_status_by_action_status' ), (array) $query['status'] );
374
-			$placeholders  = array_fill( 0, count( $post_statuses ), '%s' );
375
-			$sql          .= ' AND p.post_status IN (' . join( ', ', $placeholders ) . ')';
376
-			$sql_params    = array_merge( $sql_params, array_values( $post_statuses ) );
372
+		if ($query['status']) {
373
+			$post_statuses = array_map(array($this, 'get_post_status_by_action_status'), (array) $query['status']);
374
+			$placeholders  = array_fill(0, count($post_statuses), '%s');
375
+			$sql          .= ' AND p.post_status IN ('.join(', ', $placeholders).')';
376
+			$sql_params    = array_merge($sql_params, array_values($post_statuses));
377 377
 		}
378 378
 
379
-		if ( $query['date'] instanceof DateTime ) {
379
+		if ($query['date'] instanceof DateTime) {
380 380
 			$date = clone $query['date'];
381
-			$date->setTimezone( new DateTimeZone( 'UTC' ) );
382
-			$date_string  = $date->format( 'Y-m-d H:i:s' );
383
-			$comparator   = $this->validate_sql_comparator( $query['date_compare'] );
381
+			$date->setTimezone(new DateTimeZone('UTC'));
382
+			$date_string  = $date->format('Y-m-d H:i:s');
383
+			$comparator   = $this->validate_sql_comparator($query['date_compare']);
384 384
 			$sql         .= " AND p.post_date_gmt $comparator %s";
385 385
 			$sql_params[] = $date_string;
386 386
 		}
387 387
 
388
-		if ( $query['modified'] instanceof DateTime ) {
388
+		if ($query['modified'] instanceof DateTime) {
389 389
 			$modified = clone $query['modified'];
390
-			$modified->setTimezone( new DateTimeZone( 'UTC' ) );
391
-			$date_string  = $modified->format( 'Y-m-d H:i:s' );
392
-			$comparator   = $this->validate_sql_comparator( $query['modified_compare'] );
390
+			$modified->setTimezone(new DateTimeZone('UTC'));
391
+			$date_string  = $modified->format('Y-m-d H:i:s');
392
+			$comparator   = $this->validate_sql_comparator($query['modified_compare']);
393 393
 			$sql         .= " AND p.post_modified_gmt $comparator %s";
394 394
 			$sql_params[] = $date_string;
395 395
 		}
396 396
 
397
-		if ( true === $query['claimed'] ) {
397
+		if (true === $query['claimed']) {
398 398
 			$sql .= " AND p.post_password != ''";
399
-		} elseif ( false === $query['claimed'] ) {
399
+		} elseif (false === $query['claimed']) {
400 400
 			$sql .= " AND p.post_password = ''";
401
-		} elseif ( $query['claimed'] !== null ) {
401
+		} elseif ($query['claimed'] !== null) {
402 402
 			$sql         .= ' AND p.post_password = %s';
403 403
 			$sql_params[] = $query['claimed'];
404 404
 		}
405 405
 
406
-		if ( ! empty( $query['search'] ) ) {
406
+		if ( ! empty($query['search'])) {
407 407
 			$sql .= ' AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)';
408
-			for ( $i = 0; $i < 3; $i++ ) {
409
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
408
+			for ($i = 0; $i < 3; $i++) {
409
+				$sql_params[] = sprintf('%%%s%%', $query['search']);
410 410
 			}
411 411
 		}
412 412
 
413
-		if ( 'select' === $select_or_count ) {
414
-			switch ( $query['orderby'] ) {
413
+		if ('select' === $select_or_count) {
414
+			switch ($query['orderby']) {
415 415
 				case 'hook':
416 416
 					$orderby = 'p.post_title';
417 417
 					break;
@@ -433,20 +433,20 @@  discard block
 block discarded – undo
433 433
 					$orderby = 'p.post_date_gmt';
434 434
 					break;
435 435
 			}
436
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
436
+			if ('ASC' === strtoupper($query['order'])) {
437 437
 				$order = 'ASC';
438 438
 			} else {
439 439
 				$order = 'DESC';
440 440
 			}
441 441
 			$sql .= " ORDER BY $orderby $order";
442
-			if ( $query['per_page'] > 0 ) {
442
+			if ($query['per_page'] > 0) {
443 443
 				$sql         .= ' LIMIT %d, %d';
444 444
 				$sql_params[] = $query['offset'];
445 445
 				$sql_params[] = $query['per_page'];
446 446
 			}
447 447
 		}
448 448
 
449
-		return $wpdb->prepare( $sql, $sql_params ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
449
+		return $wpdb->prepare($sql, $sql_params); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
450 450
 	}
451 451
 
452 452
 	/**
@@ -461,7 +461,7 @@  discard block
 block discarded – undo
461 461
 	 *
462 462
 	 * @return string|array|null The IDs of actions matching the query. Null on failure.
463 463
 	 */
464
-	public function query_actions( $query = array(), $query_type = 'select' ) {
464
+	public function query_actions($query = array(), $query_type = 'select') {
465 465
 		/**
466 466
 		 * Global $wpdb object.
467 467
 		 *
@@ -469,9 +469,9 @@  discard block
 block discarded – undo
469 469
 		 */
470 470
 		global $wpdb;
471 471
 
472
-		$sql = $this->get_query_actions_sql( $query, $query_type );
472
+		$sql = $this->get_query_actions_sql($query, $query_type);
473 473
 
474
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
474
+		return ('count' === $query_type) ? $wpdb->get_var($sql) : $wpdb->get_col($sql); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching,WordPress.DB.PreparedSQL.NotPrepared
475 475
 	}
476 476
 
477 477
 	/**
@@ -483,18 +483,18 @@  discard block
 block discarded – undo
483 483
 
484 484
 		$action_counts_by_status = array();
485 485
 		$action_stati_and_labels = $this->get_status_labels();
486
-		$posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
486
+		$posts_count_by_status   = (array) wp_count_posts(self::POST_TYPE, 'readable');
487 487
 
488
-		foreach ( $posts_count_by_status as $post_status_name => $count ) {
488
+		foreach ($posts_count_by_status as $post_status_name => $count) {
489 489
 
490 490
 			try {
491
-				$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
492
-			} catch ( Exception $e ) {
491
+				$action_status_name = $this->get_action_status_by_post_status($post_status_name);
492
+			} catch (Exception $e) {
493 493
 				// Ignore any post statuses that aren't for actions.
494 494
 				continue;
495 495
 			}
496
-			if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
497
-				$action_counts_by_status[ $action_status_name ] = $count;
496
+			if (array_key_exists($action_status_name, $action_stati_and_labels)) {
497
+				$action_counts_by_status[$action_status_name] = $count;
498 498
 			}
499 499
 		}
500 500
 
@@ -508,16 +508,16 @@  discard block
 block discarded – undo
508 508
 	 *
509 509
 	 * @throws InvalidArgumentException If $action_id is not identified.
510 510
 	 */
511
-	public function cancel_action( $action_id ) {
512
-		$post = get_post( $action_id );
513
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
511
+	public function cancel_action($action_id) {
512
+		$post = get_post($action_id);
513
+		if (empty($post) || (self::POST_TYPE !== $post->post_type)) {
514 514
 			/* translators: %s is the action ID */
515
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
515
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
516 516
 		}
517
-		do_action( 'action_scheduler_canceled_action', $action_id );
518
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
519
-		wp_trash_post( $action_id );
520
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
517
+		do_action('action_scheduler_canceled_action', $action_id);
518
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
519
+		wp_trash_post($action_id);
520
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
521 521
 	}
522 522
 
523 523
 	/**
@@ -527,15 +527,15 @@  discard block
 block discarded – undo
527 527
 	 * @return void
528 528
 	 * @throws InvalidArgumentException If action is not identified.
529 529
 	 */
530
-	public function delete_action( $action_id ) {
531
-		$post = get_post( $action_id );
532
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
530
+	public function delete_action($action_id) {
531
+		$post = get_post($action_id);
532
+		if (empty($post) || (self::POST_TYPE !== $post->post_type)) {
533 533
 			/* translators: %s is the action ID */
534
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
534
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
535 535
 		}
536
-		do_action( 'action_scheduler_deleted_action', $action_id );
536
+		do_action('action_scheduler_deleted_action', $action_id);
537 537
 
538
-		wp_delete_post( $action_id, true );
538
+		wp_delete_post($action_id, true);
539 539
 	}
540 540
 
541 541
 	/**
@@ -544,9 +544,9 @@  discard block
 block discarded – undo
544 544
 	 * @param int $action_id Action ID.
545 545
 	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
546 546
 	 */
547
-	public function get_date( $action_id ) {
548
-		$next = $this->get_date_gmt( $action_id );
549
-		return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
547
+	public function get_date($action_id) {
548
+		$next = $this->get_date_gmt($action_id);
549
+		return ActionScheduler_TimezoneHelper::set_local_timezone($next);
550 550
 	}
551 551
 
552 552
 	/**
@@ -557,16 +557,16 @@  discard block
 block discarded – undo
557 557
 	 * @throws InvalidArgumentException If $action_id is not identified.
558 558
 	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
559 559
 	 */
560
-	public function get_date_gmt( $action_id ) {
561
-		$post = get_post( $action_id );
562
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
560
+	public function get_date_gmt($action_id) {
561
+		$post = get_post($action_id);
562
+		if (empty($post) || (self::POST_TYPE !== $post->post_type)) {
563 563
 			/* translators: %s is the action ID */
564
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
564
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
565 565
 		}
566
-		if ( 'publish' === $post->post_status ) {
567
-			return as_get_datetime_object( $post->post_modified_gmt );
566
+		if ('publish' === $post->post_status) {
567
+			return as_get_datetime_object($post->post_modified_gmt);
568 568
 		} else {
569
-			return as_get_datetime_object( $post->post_date_gmt );
569
+			return as_get_datetime_object($post->post_date_gmt);
570 570
 		}
571 571
 	}
572 572
 
@@ -582,14 +582,14 @@  discard block
 block discarded – undo
582 582
 	 * @throws RuntimeException When there is an error staking a claim.
583 583
 	 * @throws InvalidArgumentException When the given group is not valid.
584 584
 	 */
585
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
585
+	public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '') {
586 586
 		$this->claim_before_date = $before_date;
587 587
 		$claim_id                = $this->generate_claim_id();
588
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
589
-		$action_ids              = $this->find_actions_by_claim_id( $claim_id );
588
+		$this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group);
589
+		$action_ids              = $this->find_actions_by_claim_id($claim_id);
590 590
 		$this->claim_before_date = null;
591 591
 
592
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
592
+		return new ActionScheduler_ActionClaim($claim_id, $action_ids);
593 593
 	}
594 594
 
595 595
 	/**
@@ -604,7 +604,7 @@  discard block
 block discarded – undo
604 604
 		return $wpdb->get_var(
605 605
 			$wpdb->prepare(
606 606
 				"SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')",
607
-				array( self::POST_TYPE )
607
+				array(self::POST_TYPE)
608 608
 			)
609 609
 		);
610 610
 	}
@@ -615,8 +615,8 @@  discard block
 block discarded – undo
615 615
 	 * @return string
616 616
 	 */
617 617
 	protected function generate_claim_id() {
618
-		$claim_id = md5( microtime( true ) . wp_rand( 0, 1000 ) );
619
-		return substr( $claim_id, 0, 20 ); // to fit in db field with 20 char limit.
618
+		$claim_id = md5(microtime(true).wp_rand(0, 1000));
619
+		return substr($claim_id, 0, 20); // to fit in db field with 20 char limit.
620 620
 	}
621 621
 
622 622
 	/**
@@ -631,14 +631,14 @@  discard block
 block discarded – undo
631 631
 	 * @return int The number of actions that were claimed.
632 632
 	 * @throws RuntimeException  When there is a database error.
633 633
 	 */
634
-	protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
634
+	protected function claim_actions($claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '') {
635 635
 		// Set up initial variables.
636 636
 		$date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
637
-		$limit_ids = ! empty( $group );
638
-		$ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
637
+		$limit_ids = ! empty($group);
638
+		$ids       = $limit_ids ? $this->get_actions_by_group($group, $limit, $date) : array();
639 639
 
640 640
 		// If limiting by IDs and no posts found, then return early since we have nothing to update.
641
-		if ( $limit_ids && 0 === count( $ids ) ) {
641
+		if ($limit_ids && 0 === count($ids)) {
642 642
 			return 0;
643 643
 		}
644 644
 
@@ -658,8 +658,8 @@  discard block
 block discarded – undo
658 658
 		$update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
659 659
 		$params = array(
660 660
 			$claim_id,
661
-			current_time( 'mysql', true ),
662
-			current_time( 'mysql' ),
661
+			current_time('mysql', true),
662
+			current_time('mysql'),
663 663
 		);
664 664
 
665 665
 		// Build initial WHERE clause.
@@ -667,10 +667,10 @@  discard block
 block discarded – undo
667 667
 		$params[] = self::POST_TYPE;
668 668
 		$params[] = ActionScheduler_Store::STATUS_PENDING;
669 669
 
670
-		if ( ! empty( $hooks ) ) {
671
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
672
-			$where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
673
-			$params       = array_merge( $params, array_values( $hooks ) );
670
+		if ( ! empty($hooks)) {
671
+			$placeholders = array_fill(0, count($hooks), '%s');
672
+			$where       .= ' AND post_title IN ('.join(', ', $placeholders).')';
673
+			$params       = array_merge($params, array_values($hooks));
674 674
 		}
675 675
 
676 676
 		/*
@@ -678,11 +678,11 @@  discard block
 block discarded – undo
678 678
 		 *
679 679
 		 * If we're not limiting by IDs, then include the post_date_gmt clause.
680 680
 		 */
681
-		if ( $limit_ids ) {
682
-			$where .= ' AND ID IN (' . join( ',', $ids ) . ')';
681
+		if ($limit_ids) {
682
+			$where .= ' AND ID IN ('.join(',', $ids).')';
683 683
 		} else {
684 684
 			$where   .= ' AND post_date_gmt <= %s';
685
-			$params[] = $date->format( 'Y-m-d H:i:s' );
685
+			$params[] = $date->format('Y-m-d H:i:s');
686 686
 		}
687 687
 
688 688
 		// Add the ORDER BY clause and,ms limit.
@@ -690,10 +690,10 @@  discard block
 block discarded – undo
690 690
 		$params[] = $limit;
691 691
 
692 692
 		// Run the query and gather results.
693
-		$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) ); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
693
+		$rows_affected = $wpdb->query($wpdb->prepare("{$update} {$where} {$order}", $params)); // phpcs:ignore // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
694 694
 
695
-		if ( false === $rows_affected ) {
696
-			throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
695
+		if (false === $rows_affected) {
696
+			throw new RuntimeException(__('Unable to claim actions. Database error.', 'action-scheduler'));
697 697
 		}
698 698
 
699 699
 		return (int) $rows_affected;
@@ -710,11 +710,11 @@  discard block
 block discarded – undo
710 710
 	 * @return array IDs of actions in the appropriate group and before the appropriate time.
711 711
 	 * @throws InvalidArgumentException When the group does not exist.
712 712
 	 */
713
-	protected function get_actions_by_group( $group, $limit, DateTime $date ) {
713
+	protected function get_actions_by_group($group, $limit, DateTime $date) {
714 714
 		// Ensure the group exists before continuing.
715
-		if ( ! term_exists( $group, self::GROUP_TAXONOMY ) ) {
715
+		if ( ! term_exists($group, self::GROUP_TAXONOMY)) {
716 716
 			/* translators: %s is the group name */
717
-			throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
717
+			throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'action-scheduler'), $group));
718 718
 		}
719 719
 
720 720
 		// Set up a query for post IDs to use later.
@@ -734,7 +734,7 @@  discard block
 block discarded – undo
734 734
 			),
735 735
 			'date_query'       => array(
736 736
 				'column'    => 'post_date_gmt',
737
-				'before'    => $date->format( 'Y-m-d H:i' ),
737
+				'before'    => $date->format('Y-m-d H:i'),
738 738
 				'inclusive' => true,
739 739
 			),
740 740
 			'tax_query'        => array( // phpcs:ignore WordPress.DB.SlowDBQuery
@@ -747,7 +747,7 @@  discard block
 block discarded – undo
747 747
 			),
748 748
 		);
749 749
 
750
-		return $query->query( $query_args );
750
+		return $query->query($query_args);
751 751
 	}
752 752
 
753 753
 	/**
@@ -756,7 +756,7 @@  discard block
 block discarded – undo
756 756
 	 * @param string $claim_id Claim ID.
757 757
 	 * @return array
758 758
 	 */
759
-	public function find_actions_by_claim_id( $claim_id ) {
759
+	public function find_actions_by_claim_id($claim_id) {
760 760
 		/**
761 761
 		 * Global wpdb object.
762 762
 		 *
@@ -765,8 +765,8 @@  discard block
 block discarded – undo
765 765
 		global $wpdb;
766 766
 
767 767
 		$action_ids  = array();
768
-		$before_date = isset( $this->claim_before_date ) ? $this->claim_before_date : as_get_datetime_object();
769
-		$cut_off     = $before_date->format( 'Y-m-d H:i:s' );
768
+		$before_date = isset($this->claim_before_date) ? $this->claim_before_date : as_get_datetime_object();
769
+		$cut_off     = $before_date->format('Y-m-d H:i:s');
770 770
 
771 771
 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
772 772
 		$results = $wpdb->get_results(
@@ -781,9 +781,9 @@  discard block
 block discarded – undo
781 781
 
782 782
 		// Verify that the scheduled date for each action is within the expected bounds (in some unusual
783 783
 		// cases, we cannot depend on MySQL to honor all of the WHERE conditions we specify).
784
-		foreach ( $results as $claimed_action ) {
785
-			if ( $claimed_action->post_date_gmt <= $cut_off ) {
786
-				$action_ids[] = absint( $claimed_action->ID );
784
+		foreach ($results as $claimed_action) {
785
+			if ($claimed_action->post_date_gmt <= $cut_off) {
786
+				$action_ids[] = absint($claimed_action->ID);
787 787
 			}
788 788
 		}
789 789
 
@@ -797,12 +797,12 @@  discard block
 block discarded – undo
797 797
 	 * @return void
798 798
 	 * @throws RuntimeException When the claim is not unlocked.
799 799
 	 */
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 ) ) {
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 803
 			return; // nothing to do.
804 804
 		}
805
-		$action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
805
+		$action_id_string = implode(',', array_map('intval', $action_ids));
806 806
 		/**
807 807
 		 * Global wpdb object.
808 808
 		 *
@@ -819,9 +819,9 @@  discard block
 block discarded – undo
819 819
 				)
820 820
 			)
821 821
 		);
822
-		if ( false === $result ) {
822
+		if (false === $result) {
823 823
 			/* translators: %s: claim ID */
824
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
824
+			throw new RuntimeException(sprintf(__('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id()));
825 825
 		}
826 826
 	}
827 827
 
@@ -831,7 +831,7 @@  discard block
 block discarded – undo
831 831
 	 * @param string $action_id Action ID.
832 832
 	 * @throws RuntimeException When unable to unlock claim on action ID.
833 833
 	 */
834
-	public function unclaim_action( $action_id ) {
834
+	public function unclaim_action($action_id) {
835 835
 		/**
836 836
 		 * Global wpdb object.
837 837
 		 *
@@ -847,9 +847,9 @@  discard block
 block discarded – undo
847 847
 				self::POST_TYPE
848 848
 			)
849 849
 		);
850
-		if ( false === $result ) {
850
+		if (false === $result) {
851 851
 			/* translators: %s: action ID */
852
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
852
+			throw new RuntimeException(sprintf(__('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id));
853 853
 		}
854 854
 	}
855 855
 
@@ -861,7 +861,7 @@  discard block
 block discarded – undo
861 861
 	 * @return void
862 862
 	 * @throws RuntimeException When unable to mark failure on action ID.
863 863
 	 */
864
-	public function mark_failure( $action_id ) {
864
+	public function mark_failure($action_id) {
865 865
 		/**
866 866
 		 * Global wpdb object.
867 867
 		 *
@@ -871,11 +871,11 @@  discard block
 block discarded – undo
871 871
 
872 872
 		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
873 873
 		$result = $wpdb->query(
874
-			$wpdb->prepare( "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE )
874
+			$wpdb->prepare("UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s", self::STATUS_FAILED, $action_id, self::POST_TYPE)
875 875
 		);
876
-		if ( false === $result ) {
876
+		if (false === $result) {
877 877
 			/* translators: %s: action ID */
878
-			throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
878
+			throw new RuntimeException(sprintf(__('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id));
879 879
 		}
880 880
 	}
881 881
 
@@ -885,8 +885,8 @@  discard block
 block discarded – undo
885 885
 	 * @param int $action_id Action ID.
886 886
 	 * @return mixed
887 887
 	 */
888
-	public function get_claim_id( $action_id ) {
889
-		return $this->get_post_column( $action_id, 'post_password' );
888
+	public function get_claim_id($action_id) {
889
+		return $this->get_post_column($action_id, 'post_password');
890 890
 	}
891 891
 
892 892
 	/**
@@ -897,14 +897,14 @@  discard block
 block discarded – undo
897 897
 	 * @return mixed
898 898
 	 * @throws InvalidArgumentException When the action ID is invalid.
899 899
 	 */
900
-	public function get_status( $action_id ) {
901
-		$status = $this->get_post_column( $action_id, 'post_status' );
900
+	public function get_status($action_id) {
901
+		$status = $this->get_post_column($action_id, 'post_status');
902 902
 
903
-		if ( null === $status ) {
904
-			throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
903
+		if (null === $status) {
904
+			throw new InvalidArgumentException(__('Invalid action ID. No status found.', 'action-scheduler'));
905 905
 		}
906 906
 
907
-		return $this->get_action_status_by_post_status( $status );
907
+		return $this->get_action_status_by_post_status($status);
908 908
 	}
909 909
 
910 910
 	/**
@@ -915,7 +915,7 @@  discard block
 block discarded – undo
915 915
 	 *
916 916
 	 * @return string|null
917 917
 	 */
918
-	private function get_post_column( $action_id, $column_name ) {
918
+	private function get_post_column($action_id, $column_name) {
919 919
 		/**
920 920
 		 * Global wpdb object.
921 921
 		 *
@@ -938,7 +938,7 @@  discard block
 block discarded – undo
938 938
 	 *
939 939
 	 * @param string $action_id Action ID.
940 940
 	 */
941
-	public function log_execution( $action_id ) {
941
+	public function log_execution($action_id) {
942 942
 		/**
943 943
 		 * Global wpdb object.
944 944
 		 *
@@ -951,8 +951,8 @@  discard block
 block discarded – undo
951 951
 			$wpdb->prepare(
952 952
 				"UPDATE {$wpdb->posts} SET menu_order = menu_order+1, post_status=%s, post_modified_gmt = %s, post_modified = %s WHERE ID = %d AND post_type = %s",
953 953
 				self::STATUS_RUNNING,
954
-				current_time( 'mysql', true ),
955
-				current_time( 'mysql' ),
954
+				current_time('mysql', true),
955
+				current_time('mysql'),
956 956
 				$action_id,
957 957
 				self::POST_TYPE
958 958
 			)
@@ -967,14 +967,14 @@  discard block
 block discarded – undo
967 967
 	 * @throws InvalidArgumentException When the action ID is invalid.
968 968
 	 * @throws RuntimeException         When there was an error executing the action.
969 969
 	 */
970
-	public function mark_complete( $action_id ) {
971
-		$post = get_post( $action_id );
972
-		if ( empty( $post ) || ( self::POST_TYPE !== $post->post_type ) ) {
970
+	public function mark_complete($action_id) {
971
+		$post = get_post($action_id);
972
+		if (empty($post) || (self::POST_TYPE !== $post->post_type)) {
973 973
 			/* translators: %s is the action ID */
974
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
974
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
975 975
 		}
976
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
977
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
976
+		add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
977
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
978 978
 		$result = wp_update_post(
979 979
 			array(
980 980
 				'ID'          => $action_id,
@@ -982,10 +982,10 @@  discard block
 block discarded – undo
982 982
 			),
983 983
 			true
984 984
 		);
985
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
986
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
987
-		if ( is_wp_error( $result ) ) {
988
-			throw new RuntimeException( $result->get_error_message() );
985
+		remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
986
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
987
+		if (is_wp_error($result)) {
988
+			throw new RuntimeException($result->get_error_message());
989 989
 		}
990 990
 
991 991
 		/**
@@ -995,7 +995,7 @@  discard block
 block discarded – undo
995 995
 		 *
996 996
 		 * @param int $action_id Action ID.
997 997
 		 */
998
-		do_action( 'action_scheduler_completed_action', $action_id );
998
+		do_action('action_scheduler_completed_action', $action_id);
999 999
 	}
1000 1000
 
1001 1001
 	/**
@@ -1003,7 +1003,7 @@  discard block
 block discarded – undo
1003 1003
 	 *
1004 1004
 	 * @param int $action_id Action ID.
1005 1005
 	 */
1006
-	public function mark_migrated( $action_id ) {
1006
+	public function mark_migrated($action_id) {
1007 1007
 		wp_update_post(
1008 1008
 			array(
1009 1009
 				'ID'          => $action_id,
@@ -1018,12 +1018,12 @@  discard block
 block discarded – undo
1018 1018
 	 * @param [type] $setting - Setting value.
1019 1019
 	 * @return bool
1020 1020
 	 */
1021
-	public function migration_dependencies_met( $setting ) {
1021
+	public function migration_dependencies_met($setting) {
1022 1022
 		global $wpdb;
1023 1023
 
1024
-		$dependencies_met = get_transient( self::DEPENDENCIES_MET );
1025
-		if ( empty( $dependencies_met ) ) {
1026
-			$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
1024
+		$dependencies_met = get_transient(self::DEPENDENCIES_MET);
1025
+		if (empty($dependencies_met)) {
1026
+			$maximum_args_length = apply_filters('action_scheduler_maximum_args_length', 191);
1027 1027
 			$found_action        = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
1028 1028
 				$wpdb->prepare(
1029 1029
 					"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
@@ -1031,8 +1031,8 @@  discard block
 block discarded – undo
1031 1031
 					self::POST_TYPE
1032 1032
 				)
1033 1033
 			);
1034
-			$dependencies_met    = $found_action ? 'no' : 'yes';
1035
-			set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
1034
+			$dependencies_met = $found_action ? 'no' : 'yes';
1035
+			set_transient(self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS);
1036 1036
 		}
1037 1037
 
1038 1038
 		return 'yes' === $dependencies_met ? $setting : false;
@@ -1047,13 +1047,13 @@  discard block
 block discarded – undo
1047 1047
 	 *
1048 1048
 	 * @param ActionScheduler_Action $action Action object.
1049 1049
 	 */
1050
-	protected function validate_action( ActionScheduler_Action $action ) {
1050
+	protected function validate_action(ActionScheduler_Action $action) {
1051 1051
 		try {
1052
-			parent::validate_action( $action );
1053
-		} catch ( Exception $e ) {
1052
+			parent::validate_action($action);
1053
+		} catch (Exception $e) {
1054 1054
 			/* translators: %s is the error message */
1055
-			$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
1056
-			_doing_it_wrong( 'ActionScheduler_Action::$args', esc_html( $message ), '2.1.0' );
1055
+			$message = sprintf(__('%s Support for strings longer than this will be removed in a future version.', 'action-scheduler'), $e->getMessage());
1056
+			_doing_it_wrong('ActionScheduler_Action::$args', esc_html($message), '2.1.0');
1057 1057
 		}
1058 1058
 	}
1059 1059
 
@@ -1061,7 +1061,7 @@  discard block
 block discarded – undo
1061 1061
 	 * (@codeCoverageIgnore)
1062 1062
 	 */
1063 1063
 	public function init() {
1064
-		add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
1064
+		add_filter('action_scheduler_migration_dependencies_met', array($this, 'migration_dependencies_met'));
1065 1065
 
1066 1066
 		$post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
1067 1067
 		$post_type_registrar->register();
Please login to merge, or discard this patch.
ext/action-scheduler/classes/data-stores/ActionScheduler_HybridStore.php 2 patches
Indentation   +406 added lines, -406 removed lines patch added patch discarded remove patch
@@ -13,415 +13,415 @@
 block discarded – undo
13 13
  * @since 3.0.0
14 14
  */
15 15
 class ActionScheduler_HybridStore extends Store {
16
-	const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
-
18
-	private $primary_store;
19
-	private $secondary_store;
20
-	private $migration_runner;
21
-
22
-	/**
23
-	 * @var int The dividing line between IDs of actions created
24
-	 *          by the primary and secondary stores.
25
-	 *
26
-	 * Methods that accept an action ID will compare the ID against
27
-	 * this to determine which store will contain that ID. In almost
28
-	 * all cases, the ID should come from the primary store, but if
29
-	 * client code is bypassing the API functions and fetching IDs
30
-	 * from elsewhere, then there is a chance that an unmigrated ID
31
-	 * might be requested.
32
-	 */
33
-	private $demarkation_id = 0;
34
-
35
-	/**
36
-	 * ActionScheduler_HybridStore constructor.
37
-	 *
38
-	 * @param Config $config Migration config object.
39
-	 */
40
-	public function __construct( Config $config = null ) {
41
-		$this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
-		if ( empty( $config ) ) {
43
-			$config = Controller::instance()->get_migration_config_object();
44
-		}
45
-		$this->primary_store    = $config->get_destination_store();
46
-		$this->secondary_store  = $config->get_source_store();
47
-		$this->migration_runner = new Runner( $config );
48
-	}
49
-
50
-	/**
51
-	 * Initialize the table data store tables.
52
-	 *
53
-	 * @codeCoverageIgnore
54
-	 */
55
-	public function init() {
56
-		add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 );
57
-		$this->primary_store->init();
58
-		$this->secondary_store->init();
59
-		remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 );
60
-	}
61
-
62
-	/**
63
-	 * When the actions table is created, set its autoincrement
64
-	 * value to be one higher than the posts table to ensure that
65
-	 * there are no ID collisions.
66
-	 *
67
-	 * @param string $table_name
68
-	 * @param string $table_suffix
69
-	 *
70
-	 * @return void
71
-	 * @codeCoverageIgnore
72
-	 */
73
-	public function set_autoincrement( $table_name, $table_suffix ) {
74
-		if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
-			if ( empty( $this->demarkation_id ) ) {
76
-				$this->demarkation_id = $this->set_demarkation_id();
77
-			}
78
-			/** @var \wpdb $wpdb */
79
-			global $wpdb;
80
-			/**
81
-			 * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
82
-			 * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
83
-			 */
84
-			$default_date = new DateTime( 'tomorrow' );
85
-			$null_action  = new ActionScheduler_NullAction();
86
-			$date_gmt     = $this->get_scheduled_date_string( $null_action, $default_date );
87
-			$date_local   = $this->get_scheduled_date_string_local( $null_action, $default_date );
88
-
89
-			$row_count = $wpdb->insert(
90
-				$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
91
-				array(
92
-					'action_id'            => $this->demarkation_id,
93
-					'hook'                 => '',
94
-					'status'               => '',
95
-					'scheduled_date_gmt'   => $date_gmt,
96
-					'scheduled_date_local' => $date_local,
97
-					'last_attempt_gmt'     => $date_gmt,
98
-					'last_attempt_local'   => $date_local,
99
-				)
100
-			);
101
-			if ( $row_count > 0 ) {
102
-				$wpdb->delete(
103
-					$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
104
-					array( 'action_id' => $this->demarkation_id )
105
-				);
106
-			}
107
-		}
108
-	}
109
-
110
-	/**
111
-	 * Store the demarkation id in WP options.
112
-	 *
113
-	 * @param int $id The ID to set as the demarkation point between the two stores
114
-	 *                Leave null to use the next ID from the WP posts table.
115
-	 *
116
-	 * @return int The new ID.
117
-	 *
118
-	 * @codeCoverageIgnore
119
-	 */
120
-	private function set_demarkation_id( $id = null ) {
121
-		if ( empty( $id ) ) {
122
-			/** @var \wpdb $wpdb */
123
-			global $wpdb;
124
-			$id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
125
-			$id ++;
126
-		}
127
-		update_option( self::DEMARKATION_OPTION, $id );
128
-
129
-		return $id;
130
-	}
131
-
132
-	/**
133
-	 * Find the first matching action from the secondary store.
134
-	 * If it exists, migrate it to the primary store immediately.
135
-	 * After it migrates, the secondary store will logically contain
136
-	 * the next matching action, so return the result thence.
137
-	 *
138
-	 * @param string $hook
139
-	 * @param array  $params
140
-	 *
141
-	 * @return string
142
-	 */
143
-	public function find_action( $hook, $params = array() ) {
144
-		$found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
145
-		if ( ! empty( $found_unmigrated_action ) ) {
146
-			$this->migrate( array( $found_unmigrated_action ) );
147
-		}
148
-
149
-		return $this->primary_store->find_action( $hook, $params );
150
-	}
151
-
152
-	/**
153
-	 * Find actions matching the query in the secondary source first.
154
-	 * If any are found, migrate them immediately. Then the secondary
155
-	 * store will contain the canonical results.
156
-	 *
157
-	 * @param array  $query
158
-	 * @param string $query_type Whether to select or count the results. Default, select.
159
-	 *
160
-	 * @return int[]
161
-	 */
162
-	public function query_actions( $query = array(), $query_type = 'select' ) {
163
-		$found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
164
-		if ( ! empty( $found_unmigrated_actions ) ) {
165
-			$this->migrate( $found_unmigrated_actions );
166
-		}
167
-
168
-		return $this->primary_store->query_actions( $query, $query_type );
169
-	}
170
-
171
-	/**
172
-	 * Get a count of all actions in the store, grouped by status
173
-	 *
174
-	 * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
175
-	 */
176
-	public function action_counts() {
177
-		$unmigrated_actions_count = $this->secondary_store->action_counts();
178
-		$migrated_actions_count   = $this->primary_store->action_counts();
179
-		$actions_count_by_status  = array();
180
-
181
-		foreach ( $this->get_status_labels() as $status_key => $status_label ) {
182
-
183
-			$count = 0;
184
-
185
-			if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
186
-				$count += $unmigrated_actions_count[ $status_key ];
187
-			}
188
-
189
-			if ( isset( $migrated_actions_count[ $status_key ] ) ) {
190
-				$count += $migrated_actions_count[ $status_key ];
191
-			}
192
-
193
-			$actions_count_by_status[ $status_key ] = $count;
194
-		}
195
-
196
-		$actions_count_by_status = array_filter( $actions_count_by_status );
197
-
198
-		return $actions_count_by_status;
199
-	}
200
-
201
-	/**
202
-	 * If any actions would have been claimed by the secondary store,
203
-	 * migrate them immediately, then ask the primary store for the
204
-	 * canonical claim.
205
-	 *
206
-	 * @param int           $max_actions
207
-	 * @param DateTime|null $before_date
208
-	 *
209
-	 * @return ActionScheduler_ActionClaim
210
-	 */
211
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
212
-		$claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
213
-
214
-		$claimed_actions = $claim->get_actions();
215
-		if ( ! empty( $claimed_actions ) ) {
216
-			$this->migrate( $claimed_actions );
217
-		}
218
-
219
-		$this->secondary_store->release_claim( $claim );
220
-
221
-		return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
222
-	}
223
-
224
-	/**
225
-	 * Migrate a list of actions to the table data store.
226
-	 *
227
-	 * @param array $action_ids List of action IDs.
228
-	 */
229
-	private function migrate( $action_ids ) {
230
-		$this->migration_runner->migrate_actions( $action_ids );
231
-	}
232
-
233
-	/**
234
-	 * Save an action to the primary store.
235
-	 *
236
-	 * @param ActionScheduler_Action $action Action object to be saved.
237
-	 * @param DateTime               $date Optional. Schedule date. Default null.
238
-	 *
239
-	 * @return int The action ID
240
-	 */
241
-	public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
242
-		return $this->primary_store->save_action( $action, $date );
243
-	}
244
-
245
-	/**
246
-	 * Retrieve an existing action whether migrated or not.
247
-	 *
248
-	 * @param int $action_id Action ID.
249
-	 */
250
-	public function fetch_action( $action_id ) {
251
-		$store = $this->get_store_from_action_id( $action_id, true );
252
-		if ( $store ) {
253
-			return $store->fetch_action( $action_id );
254
-		} else {
255
-			return new ActionScheduler_NullAction();
256
-		}
257
-	}
258
-
259
-	/**
260
-	 * Cancel an existing action whether migrated or not.
261
-	 *
262
-	 * @param int $action_id Action ID.
263
-	 */
264
-	public function cancel_action( $action_id ) {
265
-		$store = $this->get_store_from_action_id( $action_id );
266
-		if ( $store ) {
267
-			$store->cancel_action( $action_id );
268
-		}
269
-	}
270
-
271
-	/**
272
-	 * Delete an existing action whether migrated or not.
273
-	 *
274
-	 * @param int $action_id Action ID.
275
-	 */
276
-	public function delete_action( $action_id ) {
277
-		$store = $this->get_store_from_action_id( $action_id );
278
-		if ( $store ) {
279
-			$store->delete_action( $action_id );
280
-		}
281
-	}
282
-
283
-	/**
284
-	 * Get the schedule date an existing action whether migrated or not.
285
-	 *
286
-	 * @param int $action_id Action ID.
287
-	 */
288
-	public function get_date( $action_id ) {
289
-		$store = $this->get_store_from_action_id( $action_id );
290
-		if ( $store ) {
291
-			return $store->get_date( $action_id );
292
-		} else {
293
-			return null;
294
-		}
295
-	}
296
-
297
-	/**
298
-	 * Mark an existing action as failed whether migrated or not.
299
-	 *
300
-	 * @param int $action_id Action ID.
301
-	 */
302
-	public function mark_failure( $action_id ) {
303
-		$store = $this->get_store_from_action_id( $action_id );
304
-		if ( $store ) {
305
-			$store->mark_failure( $action_id );
306
-		}
307
-	}
308
-
309
-	/**
310
-	 * Log the execution of an existing action whether migrated or not.
311
-	 *
312
-	 * @param int $action_id Action ID.
313
-	 */
314
-	public function log_execution( $action_id ) {
315
-		$store = $this->get_store_from_action_id( $action_id );
316
-		if ( $store ) {
317
-			$store->log_execution( $action_id );
318
-		}
319
-	}
320
-
321
-	/**
322
-	 * Mark an existing action complete whether migrated or not.
323
-	 *
324
-	 * @param int $action_id Action ID.
325
-	 */
326
-	public function mark_complete( $action_id ) {
327
-		$store = $this->get_store_from_action_id( $action_id );
328
-		if ( $store ) {
329
-			$store->mark_complete( $action_id );
330
-		}
331
-	}
332
-
333
-	/**
334
-	 * Get an existing action status whether migrated or not.
335
-	 *
336
-	 * @param int $action_id Action ID.
337
-	 */
338
-	public function get_status( $action_id ) {
339
-		$store = $this->get_store_from_action_id( $action_id );
340
-		if ( $store ) {
341
-			return $store->get_status( $action_id );
342
-		}
343
-		return null;
344
-	}
345
-
346
-	/**
347
-	 * Return which store an action is stored in.
348
-	 *
349
-	 * @param int  $action_id ID of the action.
350
-	 * @param bool $primary_first Optional flag indicating search the primary store first.
351
-	 * @return ActionScheduler_Store
352
-	 */
353
-	protected function get_store_from_action_id( $action_id, $primary_first = false ) {
354
-		if ( $primary_first ) {
355
-			$stores = array(
356
-				$this->primary_store,
357
-				$this->secondary_store,
358
-			);
359
-		} elseif ( $action_id < $this->demarkation_id ) {
360
-			$stores = array(
361
-				$this->secondary_store,
362
-				$this->primary_store,
363
-			);
364
-		} else {
365
-			$stores = array(
366
-				$this->primary_store,
367
-			);
368
-		}
369
-
370
-		foreach ( $stores as $store ) {
371
-			$action = $store->fetch_action( $action_id );
372
-			if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) {
373
-				return $store;
374
-			}
375
-		}
376
-		return null;
377
-	}
378
-
379
-	/*
16
+    const DEMARKATION_OPTION = 'action_scheduler_hybrid_store_demarkation';
17
+
18
+    private $primary_store;
19
+    private $secondary_store;
20
+    private $migration_runner;
21
+
22
+    /**
23
+     * @var int The dividing line between IDs of actions created
24
+     *          by the primary and secondary stores.
25
+     *
26
+     * Methods that accept an action ID will compare the ID against
27
+     * this to determine which store will contain that ID. In almost
28
+     * all cases, the ID should come from the primary store, but if
29
+     * client code is bypassing the API functions and fetching IDs
30
+     * from elsewhere, then there is a chance that an unmigrated ID
31
+     * might be requested.
32
+     */
33
+    private $demarkation_id = 0;
34
+
35
+    /**
36
+     * ActionScheduler_HybridStore constructor.
37
+     *
38
+     * @param Config $config Migration config object.
39
+     */
40
+    public function __construct( Config $config = null ) {
41
+        $this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
+        if ( empty( $config ) ) {
43
+            $config = Controller::instance()->get_migration_config_object();
44
+        }
45
+        $this->primary_store    = $config->get_destination_store();
46
+        $this->secondary_store  = $config->get_source_store();
47
+        $this->migration_runner = new Runner( $config );
48
+    }
49
+
50
+    /**
51
+     * Initialize the table data store tables.
52
+     *
53
+     * @codeCoverageIgnore
54
+     */
55
+    public function init() {
56
+        add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 );
57
+        $this->primary_store->init();
58
+        $this->secondary_store->init();
59
+        remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 );
60
+    }
61
+
62
+    /**
63
+     * When the actions table is created, set its autoincrement
64
+     * value to be one higher than the posts table to ensure that
65
+     * there are no ID collisions.
66
+     *
67
+     * @param string $table_name
68
+     * @param string $table_suffix
69
+     *
70
+     * @return void
71
+     * @codeCoverageIgnore
72
+     */
73
+    public function set_autoincrement( $table_name, $table_suffix ) {
74
+        if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
+            if ( empty( $this->demarkation_id ) ) {
76
+                $this->demarkation_id = $this->set_demarkation_id();
77
+            }
78
+            /** @var \wpdb $wpdb */
79
+            global $wpdb;
80
+            /**
81
+             * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
82
+             * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
83
+             */
84
+            $default_date = new DateTime( 'tomorrow' );
85
+            $null_action  = new ActionScheduler_NullAction();
86
+            $date_gmt     = $this->get_scheduled_date_string( $null_action, $default_date );
87
+            $date_local   = $this->get_scheduled_date_string_local( $null_action, $default_date );
88
+
89
+            $row_count = $wpdb->insert(
90
+                $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
91
+                array(
92
+                    'action_id'            => $this->demarkation_id,
93
+                    'hook'                 => '',
94
+                    'status'               => '',
95
+                    'scheduled_date_gmt'   => $date_gmt,
96
+                    'scheduled_date_local' => $date_local,
97
+                    'last_attempt_gmt'     => $date_gmt,
98
+                    'last_attempt_local'   => $date_local,
99
+                )
100
+            );
101
+            if ( $row_count > 0 ) {
102
+                $wpdb->delete(
103
+                    $wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
104
+                    array( 'action_id' => $this->demarkation_id )
105
+                );
106
+            }
107
+        }
108
+    }
109
+
110
+    /**
111
+     * Store the demarkation id in WP options.
112
+     *
113
+     * @param int $id The ID to set as the demarkation point between the two stores
114
+     *                Leave null to use the next ID from the WP posts table.
115
+     *
116
+     * @return int The new ID.
117
+     *
118
+     * @codeCoverageIgnore
119
+     */
120
+    private function set_demarkation_id( $id = null ) {
121
+        if ( empty( $id ) ) {
122
+            /** @var \wpdb $wpdb */
123
+            global $wpdb;
124
+            $id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
125
+            $id ++;
126
+        }
127
+        update_option( self::DEMARKATION_OPTION, $id );
128
+
129
+        return $id;
130
+    }
131
+
132
+    /**
133
+     * Find the first matching action from the secondary store.
134
+     * If it exists, migrate it to the primary store immediately.
135
+     * After it migrates, the secondary store will logically contain
136
+     * the next matching action, so return the result thence.
137
+     *
138
+     * @param string $hook
139
+     * @param array  $params
140
+     *
141
+     * @return string
142
+     */
143
+    public function find_action( $hook, $params = array() ) {
144
+        $found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
145
+        if ( ! empty( $found_unmigrated_action ) ) {
146
+            $this->migrate( array( $found_unmigrated_action ) );
147
+        }
148
+
149
+        return $this->primary_store->find_action( $hook, $params );
150
+    }
151
+
152
+    /**
153
+     * Find actions matching the query in the secondary source first.
154
+     * If any are found, migrate them immediately. Then the secondary
155
+     * store will contain the canonical results.
156
+     *
157
+     * @param array  $query
158
+     * @param string $query_type Whether to select or count the results. Default, select.
159
+     *
160
+     * @return int[]
161
+     */
162
+    public function query_actions( $query = array(), $query_type = 'select' ) {
163
+        $found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
164
+        if ( ! empty( $found_unmigrated_actions ) ) {
165
+            $this->migrate( $found_unmigrated_actions );
166
+        }
167
+
168
+        return $this->primary_store->query_actions( $query, $query_type );
169
+    }
170
+
171
+    /**
172
+     * Get a count of all actions in the store, grouped by status
173
+     *
174
+     * @return array Set of 'status' => int $count pairs for statuses with 1 or more actions of that status.
175
+     */
176
+    public function action_counts() {
177
+        $unmigrated_actions_count = $this->secondary_store->action_counts();
178
+        $migrated_actions_count   = $this->primary_store->action_counts();
179
+        $actions_count_by_status  = array();
180
+
181
+        foreach ( $this->get_status_labels() as $status_key => $status_label ) {
182
+
183
+            $count = 0;
184
+
185
+            if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
186
+                $count += $unmigrated_actions_count[ $status_key ];
187
+            }
188
+
189
+            if ( isset( $migrated_actions_count[ $status_key ] ) ) {
190
+                $count += $migrated_actions_count[ $status_key ];
191
+            }
192
+
193
+            $actions_count_by_status[ $status_key ] = $count;
194
+        }
195
+
196
+        $actions_count_by_status = array_filter( $actions_count_by_status );
197
+
198
+        return $actions_count_by_status;
199
+    }
200
+
201
+    /**
202
+     * If any actions would have been claimed by the secondary store,
203
+     * migrate them immediately, then ask the primary store for the
204
+     * canonical claim.
205
+     *
206
+     * @param int           $max_actions
207
+     * @param DateTime|null $before_date
208
+     *
209
+     * @return ActionScheduler_ActionClaim
210
+     */
211
+    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
212
+        $claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
213
+
214
+        $claimed_actions = $claim->get_actions();
215
+        if ( ! empty( $claimed_actions ) ) {
216
+            $this->migrate( $claimed_actions );
217
+        }
218
+
219
+        $this->secondary_store->release_claim( $claim );
220
+
221
+        return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
222
+    }
223
+
224
+    /**
225
+     * Migrate a list of actions to the table data store.
226
+     *
227
+     * @param array $action_ids List of action IDs.
228
+     */
229
+    private function migrate( $action_ids ) {
230
+        $this->migration_runner->migrate_actions( $action_ids );
231
+    }
232
+
233
+    /**
234
+     * Save an action to the primary store.
235
+     *
236
+     * @param ActionScheduler_Action $action Action object to be saved.
237
+     * @param DateTime               $date Optional. Schedule date. Default null.
238
+     *
239
+     * @return int The action ID
240
+     */
241
+    public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
242
+        return $this->primary_store->save_action( $action, $date );
243
+    }
244
+
245
+    /**
246
+     * Retrieve an existing action whether migrated or not.
247
+     *
248
+     * @param int $action_id Action ID.
249
+     */
250
+    public function fetch_action( $action_id ) {
251
+        $store = $this->get_store_from_action_id( $action_id, true );
252
+        if ( $store ) {
253
+            return $store->fetch_action( $action_id );
254
+        } else {
255
+            return new ActionScheduler_NullAction();
256
+        }
257
+    }
258
+
259
+    /**
260
+     * Cancel an existing action whether migrated or not.
261
+     *
262
+     * @param int $action_id Action ID.
263
+     */
264
+    public function cancel_action( $action_id ) {
265
+        $store = $this->get_store_from_action_id( $action_id );
266
+        if ( $store ) {
267
+            $store->cancel_action( $action_id );
268
+        }
269
+    }
270
+
271
+    /**
272
+     * Delete an existing action whether migrated or not.
273
+     *
274
+     * @param int $action_id Action ID.
275
+     */
276
+    public function delete_action( $action_id ) {
277
+        $store = $this->get_store_from_action_id( $action_id );
278
+        if ( $store ) {
279
+            $store->delete_action( $action_id );
280
+        }
281
+    }
282
+
283
+    /**
284
+     * Get the schedule date an existing action whether migrated or not.
285
+     *
286
+     * @param int $action_id Action ID.
287
+     */
288
+    public function get_date( $action_id ) {
289
+        $store = $this->get_store_from_action_id( $action_id );
290
+        if ( $store ) {
291
+            return $store->get_date( $action_id );
292
+        } else {
293
+            return null;
294
+        }
295
+    }
296
+
297
+    /**
298
+     * Mark an existing action as failed whether migrated or not.
299
+     *
300
+     * @param int $action_id Action ID.
301
+     */
302
+    public function mark_failure( $action_id ) {
303
+        $store = $this->get_store_from_action_id( $action_id );
304
+        if ( $store ) {
305
+            $store->mark_failure( $action_id );
306
+        }
307
+    }
308
+
309
+    /**
310
+     * Log the execution of an existing action whether migrated or not.
311
+     *
312
+     * @param int $action_id Action ID.
313
+     */
314
+    public function log_execution( $action_id ) {
315
+        $store = $this->get_store_from_action_id( $action_id );
316
+        if ( $store ) {
317
+            $store->log_execution( $action_id );
318
+        }
319
+    }
320
+
321
+    /**
322
+     * Mark an existing action complete whether migrated or not.
323
+     *
324
+     * @param int $action_id Action ID.
325
+     */
326
+    public function mark_complete( $action_id ) {
327
+        $store = $this->get_store_from_action_id( $action_id );
328
+        if ( $store ) {
329
+            $store->mark_complete( $action_id );
330
+        }
331
+    }
332
+
333
+    /**
334
+     * Get an existing action status whether migrated or not.
335
+     *
336
+     * @param int $action_id Action ID.
337
+     */
338
+    public function get_status( $action_id ) {
339
+        $store = $this->get_store_from_action_id( $action_id );
340
+        if ( $store ) {
341
+            return $store->get_status( $action_id );
342
+        }
343
+        return null;
344
+    }
345
+
346
+    /**
347
+     * Return which store an action is stored in.
348
+     *
349
+     * @param int  $action_id ID of the action.
350
+     * @param bool $primary_first Optional flag indicating search the primary store first.
351
+     * @return ActionScheduler_Store
352
+     */
353
+    protected function get_store_from_action_id( $action_id, $primary_first = false ) {
354
+        if ( $primary_first ) {
355
+            $stores = array(
356
+                $this->primary_store,
357
+                $this->secondary_store,
358
+            );
359
+        } elseif ( $action_id < $this->demarkation_id ) {
360
+            $stores = array(
361
+                $this->secondary_store,
362
+                $this->primary_store,
363
+            );
364
+        } else {
365
+            $stores = array(
366
+                $this->primary_store,
367
+            );
368
+        }
369
+
370
+        foreach ( $stores as $store ) {
371
+            $action = $store->fetch_action( $action_id );
372
+            if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) {
373
+                return $store;
374
+            }
375
+        }
376
+        return null;
377
+    }
378
+
379
+    /*
380 380
 	 * * * * * * * * * * * * * * * * * * * * * * * * * *
381 381
 	 * All claim-related functions should operate solely
382 382
 	 * on the primary store.
383 383
 	 * * * * * * * * * * * * * * * * * * * * * * * * * * */
384 384
 
385
-	/**
386
-	 * Get the claim count from the table data store.
387
-	 */
388
-	public function get_claim_count() {
389
-		return $this->primary_store->get_claim_count();
390
-	}
391
-
392
-	/**
393
-	 * Retrieve the claim ID for an action from the table data store.
394
-	 *
395
-	 * @param int $action_id Action ID.
396
-	 */
397
-	public function get_claim_id( $action_id ) {
398
-		return $this->primary_store->get_claim_id( $action_id );
399
-	}
400
-
401
-	/**
402
-	 * Release a claim in the table data store.
403
-	 *
404
-	 * @param ActionScheduler_ActionClaim $claim Claim object.
405
-	 */
406
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
407
-		$this->primary_store->release_claim( $claim );
408
-	}
409
-
410
-	/**
411
-	 * Release claims on an action in the table data store.
412
-	 *
413
-	 * @param int $action_id Action ID.
414
-	 */
415
-	public function unclaim_action( $action_id ) {
416
-		$this->primary_store->unclaim_action( $action_id );
417
-	}
418
-
419
-	/**
420
-	 * Retrieve a list of action IDs by claim.
421
-	 *
422
-	 * @param int $claim_id Claim ID.
423
-	 */
424
-	public function find_actions_by_claim_id( $claim_id ) {
425
-		return $this->primary_store->find_actions_by_claim_id( $claim_id );
426
-	}
385
+    /**
386
+     * Get the claim count from the table data store.
387
+     */
388
+    public function get_claim_count() {
389
+        return $this->primary_store->get_claim_count();
390
+    }
391
+
392
+    /**
393
+     * Retrieve the claim ID for an action from the table data store.
394
+     *
395
+     * @param int $action_id Action ID.
396
+     */
397
+    public function get_claim_id( $action_id ) {
398
+        return $this->primary_store->get_claim_id( $action_id );
399
+    }
400
+
401
+    /**
402
+     * Release a claim in the table data store.
403
+     *
404
+     * @param ActionScheduler_ActionClaim $claim Claim object.
405
+     */
406
+    public function release_claim( ActionScheduler_ActionClaim $claim ) {
407
+        $this->primary_store->release_claim( $claim );
408
+    }
409
+
410
+    /**
411
+     * Release claims on an action in the table data store.
412
+     *
413
+     * @param int $action_id Action ID.
414
+     */
415
+    public function unclaim_action( $action_id ) {
416
+        $this->primary_store->unclaim_action( $action_id );
417
+    }
418
+
419
+    /**
420
+     * Retrieve a list of action IDs by claim.
421
+     *
422
+     * @param int $claim_id Claim ID.
423
+     */
424
+    public function find_actions_by_claim_id( $claim_id ) {
425
+        return $this->primary_store->find_actions_by_claim_id( $claim_id );
426
+    }
427 427
 }
Please login to merge, or discard this patch.
Spacing   +92 added lines, -92 removed lines patch added patch discarded remove patch
@@ -37,14 +37,14 @@  discard block
 block discarded – undo
37 37
 	 *
38 38
 	 * @param Config $config Migration config object.
39 39
 	 */
40
-	public function __construct( Config $config = null ) {
41
-		$this->demarkation_id = (int) get_option( self::DEMARKATION_OPTION, 0 );
42
-		if ( empty( $config ) ) {
40
+	public function __construct(Config $config = null) {
41
+		$this->demarkation_id = (int) get_option(self::DEMARKATION_OPTION, 0);
42
+		if (empty($config)) {
43 43
 			$config = Controller::instance()->get_migration_config_object();
44 44
 		}
45 45
 		$this->primary_store    = $config->get_destination_store();
46 46
 		$this->secondary_store  = $config->get_source_store();
47
-		$this->migration_runner = new Runner( $config );
47
+		$this->migration_runner = new Runner($config);
48 48
 	}
49 49
 
50 50
 	/**
@@ -53,10 +53,10 @@  discard block
 block discarded – undo
53 53
 	 * @codeCoverageIgnore
54 54
 	 */
55 55
 	public function init() {
56
-		add_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10, 2 );
56
+		add_action('action_scheduler/created_table', array($this, 'set_autoincrement'), 10, 2);
57 57
 		$this->primary_store->init();
58 58
 		$this->secondary_store->init();
59
-		remove_action( 'action_scheduler/created_table', array( $this, 'set_autoincrement' ), 10 );
59
+		remove_action('action_scheduler/created_table', array($this, 'set_autoincrement'), 10);
60 60
 	}
61 61
 
62 62
 	/**
@@ -70,9 +70,9 @@  discard block
 block discarded – undo
70 70
 	 * @return void
71 71
 	 * @codeCoverageIgnore
72 72
 	 */
73
-	public function set_autoincrement( $table_name, $table_suffix ) {
74
-		if ( ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix ) {
75
-			if ( empty( $this->demarkation_id ) ) {
73
+	public function set_autoincrement($table_name, $table_suffix) {
74
+		if (ActionScheduler_StoreSchema::ACTIONS_TABLE === $table_suffix) {
75
+			if (empty($this->demarkation_id)) {
76 76
 				$this->demarkation_id = $this->set_demarkation_id();
77 77
 			}
78 78
 			/** @var \wpdb $wpdb */
@@ -81,10 +81,10 @@  discard block
 block discarded – undo
81 81
 			 * A default date of '0000-00-00 00:00:00' is invalid in MySQL 5.7 when configured with
82 82
 			 * sql_mode including both STRICT_TRANS_TABLES and NO_ZERO_DATE.
83 83
 			 */
84
-			$default_date = new DateTime( 'tomorrow' );
84
+			$default_date = new DateTime('tomorrow');
85 85
 			$null_action  = new ActionScheduler_NullAction();
86
-			$date_gmt     = $this->get_scheduled_date_string( $null_action, $default_date );
87
-			$date_local   = $this->get_scheduled_date_string_local( $null_action, $default_date );
86
+			$date_gmt     = $this->get_scheduled_date_string($null_action, $default_date);
87
+			$date_local   = $this->get_scheduled_date_string_local($null_action, $default_date);
88 88
 
89 89
 			$row_count = $wpdb->insert(
90 90
 				$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
@@ -98,10 +98,10 @@  discard block
 block discarded – undo
98 98
 					'last_attempt_local'   => $date_local,
99 99
 				)
100 100
 			);
101
-			if ( $row_count > 0 ) {
101
+			if ($row_count > 0) {
102 102
 				$wpdb->delete(
103 103
 					$wpdb->{ActionScheduler_StoreSchema::ACTIONS_TABLE},
104
-					array( 'action_id' => $this->demarkation_id )
104
+					array('action_id' => $this->demarkation_id)
105 105
 				);
106 106
 			}
107 107
 		}
@@ -117,14 +117,14 @@  discard block
 block discarded – undo
117 117
 	 *
118 118
 	 * @codeCoverageIgnore
119 119
 	 */
120
-	private function set_demarkation_id( $id = null ) {
121
-		if ( empty( $id ) ) {
120
+	private function set_demarkation_id($id = null) {
121
+		if (empty($id)) {
122 122
 			/** @var \wpdb $wpdb */
123 123
 			global $wpdb;
124
-			$id = (int) $wpdb->get_var( "SELECT MAX(ID) FROM $wpdb->posts" );
125
-			$id ++;
124
+			$id = (int) $wpdb->get_var("SELECT MAX(ID) FROM $wpdb->posts");
125
+			$id++;
126 126
 		}
127
-		update_option( self::DEMARKATION_OPTION, $id );
127
+		update_option(self::DEMARKATION_OPTION, $id);
128 128
 
129 129
 		return $id;
130 130
 	}
@@ -140,13 +140,13 @@  discard block
 block discarded – undo
140 140
 	 *
141 141
 	 * @return string
142 142
 	 */
143
-	public function find_action( $hook, $params = array() ) {
144
-		$found_unmigrated_action = $this->secondary_store->find_action( $hook, $params );
145
-		if ( ! empty( $found_unmigrated_action ) ) {
146
-			$this->migrate( array( $found_unmigrated_action ) );
143
+	public function find_action($hook, $params = array()) {
144
+		$found_unmigrated_action = $this->secondary_store->find_action($hook, $params);
145
+		if ( ! empty($found_unmigrated_action)) {
146
+			$this->migrate(array($found_unmigrated_action));
147 147
 		}
148 148
 
149
-		return $this->primary_store->find_action( $hook, $params );
149
+		return $this->primary_store->find_action($hook, $params);
150 150
 	}
151 151
 
152 152
 	/**
@@ -159,13 +159,13 @@  discard block
 block discarded – undo
159 159
 	 *
160 160
 	 * @return int[]
161 161
 	 */
162
-	public function query_actions( $query = array(), $query_type = 'select' ) {
163
-		$found_unmigrated_actions = $this->secondary_store->query_actions( $query, 'select' );
164
-		if ( ! empty( $found_unmigrated_actions ) ) {
165
-			$this->migrate( $found_unmigrated_actions );
162
+	public function query_actions($query = array(), $query_type = 'select') {
163
+		$found_unmigrated_actions = $this->secondary_store->query_actions($query, 'select');
164
+		if ( ! empty($found_unmigrated_actions)) {
165
+			$this->migrate($found_unmigrated_actions);
166 166
 		}
167 167
 
168
-		return $this->primary_store->query_actions( $query, $query_type );
168
+		return $this->primary_store->query_actions($query, $query_type);
169 169
 	}
170 170
 
171 171
 	/**
@@ -178,22 +178,22 @@  discard block
 block discarded – undo
178 178
 		$migrated_actions_count   = $this->primary_store->action_counts();
179 179
 		$actions_count_by_status  = array();
180 180
 
181
-		foreach ( $this->get_status_labels() as $status_key => $status_label ) {
181
+		foreach ($this->get_status_labels() as $status_key => $status_label) {
182 182
 
183 183
 			$count = 0;
184 184
 
185
-			if ( isset( $unmigrated_actions_count[ $status_key ] ) ) {
186
-				$count += $unmigrated_actions_count[ $status_key ];
185
+			if (isset($unmigrated_actions_count[$status_key])) {
186
+				$count += $unmigrated_actions_count[$status_key];
187 187
 			}
188 188
 
189
-			if ( isset( $migrated_actions_count[ $status_key ] ) ) {
190
-				$count += $migrated_actions_count[ $status_key ];
189
+			if (isset($migrated_actions_count[$status_key])) {
190
+				$count += $migrated_actions_count[$status_key];
191 191
 			}
192 192
 
193
-			$actions_count_by_status[ $status_key ] = $count;
193
+			$actions_count_by_status[$status_key] = $count;
194 194
 		}
195 195
 
196
-		$actions_count_by_status = array_filter( $actions_count_by_status );
196
+		$actions_count_by_status = array_filter($actions_count_by_status);
197 197
 
198 198
 		return $actions_count_by_status;
199 199
 	}
@@ -208,17 +208,17 @@  discard block
 block discarded – undo
208 208
 	 *
209 209
 	 * @return ActionScheduler_ActionClaim
210 210
 	 */
211
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
212
-		$claim = $this->secondary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
211
+	public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '') {
212
+		$claim = $this->secondary_store->stake_claim($max_actions, $before_date, $hooks, $group);
213 213
 
214 214
 		$claimed_actions = $claim->get_actions();
215
-		if ( ! empty( $claimed_actions ) ) {
216
-			$this->migrate( $claimed_actions );
215
+		if ( ! empty($claimed_actions)) {
216
+			$this->migrate($claimed_actions);
217 217
 		}
218 218
 
219
-		$this->secondary_store->release_claim( $claim );
219
+		$this->secondary_store->release_claim($claim);
220 220
 
221
-		return $this->primary_store->stake_claim( $max_actions, $before_date, $hooks, $group );
221
+		return $this->primary_store->stake_claim($max_actions, $before_date, $hooks, $group);
222 222
 	}
223 223
 
224 224
 	/**
@@ -226,8 +226,8 @@  discard block
 block discarded – undo
226 226
 	 *
227 227
 	 * @param array $action_ids List of action IDs.
228 228
 	 */
229
-	private function migrate( $action_ids ) {
230
-		$this->migration_runner->migrate_actions( $action_ids );
229
+	private function migrate($action_ids) {
230
+		$this->migration_runner->migrate_actions($action_ids);
231 231
 	}
232 232
 
233 233
 	/**
@@ -238,8 +238,8 @@  discard block
 block discarded – undo
238 238
 	 *
239 239
 	 * @return int The action ID
240 240
 	 */
241
-	public function save_action( ActionScheduler_Action $action, DateTime $date = null ) {
242
-		return $this->primary_store->save_action( $action, $date );
241
+	public function save_action(ActionScheduler_Action $action, DateTime $date = null) {
242
+		return $this->primary_store->save_action($action, $date);
243 243
 	}
244 244
 
245 245
 	/**
@@ -247,10 +247,10 @@  discard block
 block discarded – undo
247 247
 	 *
248 248
 	 * @param int $action_id Action ID.
249 249
 	 */
250
-	public function fetch_action( $action_id ) {
251
-		$store = $this->get_store_from_action_id( $action_id, true );
252
-		if ( $store ) {
253
-			return $store->fetch_action( $action_id );
250
+	public function fetch_action($action_id) {
251
+		$store = $this->get_store_from_action_id($action_id, true);
252
+		if ($store) {
253
+			return $store->fetch_action($action_id);
254 254
 		} else {
255 255
 			return new ActionScheduler_NullAction();
256 256
 		}
@@ -261,10 +261,10 @@  discard block
 block discarded – undo
261 261
 	 *
262 262
 	 * @param int $action_id Action ID.
263 263
 	 */
264
-	public function cancel_action( $action_id ) {
265
-		$store = $this->get_store_from_action_id( $action_id );
266
-		if ( $store ) {
267
-			$store->cancel_action( $action_id );
264
+	public function cancel_action($action_id) {
265
+		$store = $this->get_store_from_action_id($action_id);
266
+		if ($store) {
267
+			$store->cancel_action($action_id);
268 268
 		}
269 269
 	}
270 270
 
@@ -273,10 +273,10 @@  discard block
 block discarded – undo
273 273
 	 *
274 274
 	 * @param int $action_id Action ID.
275 275
 	 */
276
-	public function delete_action( $action_id ) {
277
-		$store = $this->get_store_from_action_id( $action_id );
278
-		if ( $store ) {
279
-			$store->delete_action( $action_id );
276
+	public function delete_action($action_id) {
277
+		$store = $this->get_store_from_action_id($action_id);
278
+		if ($store) {
279
+			$store->delete_action($action_id);
280 280
 		}
281 281
 	}
282 282
 
@@ -285,10 +285,10 @@  discard block
 block discarded – undo
285 285
 	 *
286 286
 	 * @param int $action_id Action ID.
287 287
 	 */
288
-	public function get_date( $action_id ) {
289
-		$store = $this->get_store_from_action_id( $action_id );
290
-		if ( $store ) {
291
-			return $store->get_date( $action_id );
288
+	public function get_date($action_id) {
289
+		$store = $this->get_store_from_action_id($action_id);
290
+		if ($store) {
291
+			return $store->get_date($action_id);
292 292
 		} else {
293 293
 			return null;
294 294
 		}
@@ -299,10 +299,10 @@  discard block
 block discarded – undo
299 299
 	 *
300 300
 	 * @param int $action_id Action ID.
301 301
 	 */
302
-	public function mark_failure( $action_id ) {
303
-		$store = $this->get_store_from_action_id( $action_id );
304
-		if ( $store ) {
305
-			$store->mark_failure( $action_id );
302
+	public function mark_failure($action_id) {
303
+		$store = $this->get_store_from_action_id($action_id);
304
+		if ($store) {
305
+			$store->mark_failure($action_id);
306 306
 		}
307 307
 	}
308 308
 
@@ -311,10 +311,10 @@  discard block
 block discarded – undo
311 311
 	 *
312 312
 	 * @param int $action_id Action ID.
313 313
 	 */
314
-	public function log_execution( $action_id ) {
315
-		$store = $this->get_store_from_action_id( $action_id );
316
-		if ( $store ) {
317
-			$store->log_execution( $action_id );
314
+	public function log_execution($action_id) {
315
+		$store = $this->get_store_from_action_id($action_id);
316
+		if ($store) {
317
+			$store->log_execution($action_id);
318 318
 		}
319 319
 	}
320 320
 
@@ -323,10 +323,10 @@  discard block
 block discarded – undo
323 323
 	 *
324 324
 	 * @param int $action_id Action ID.
325 325
 	 */
326
-	public function mark_complete( $action_id ) {
327
-		$store = $this->get_store_from_action_id( $action_id );
328
-		if ( $store ) {
329
-			$store->mark_complete( $action_id );
326
+	public function mark_complete($action_id) {
327
+		$store = $this->get_store_from_action_id($action_id);
328
+		if ($store) {
329
+			$store->mark_complete($action_id);
330 330
 		}
331 331
 	}
332 332
 
@@ -335,10 +335,10 @@  discard block
 block discarded – undo
335 335
 	 *
336 336
 	 * @param int $action_id Action ID.
337 337
 	 */
338
-	public function get_status( $action_id ) {
339
-		$store = $this->get_store_from_action_id( $action_id );
340
-		if ( $store ) {
341
-			return $store->get_status( $action_id );
338
+	public function get_status($action_id) {
339
+		$store = $this->get_store_from_action_id($action_id);
340
+		if ($store) {
341
+			return $store->get_status($action_id);
342 342
 		}
343 343
 		return null;
344 344
 	}
@@ -350,13 +350,13 @@  discard block
 block discarded – undo
350 350
 	 * @param bool $primary_first Optional flag indicating search the primary store first.
351 351
 	 * @return ActionScheduler_Store
352 352
 	 */
353
-	protected function get_store_from_action_id( $action_id, $primary_first = false ) {
354
-		if ( $primary_first ) {
353
+	protected function get_store_from_action_id($action_id, $primary_first = false) {
354
+		if ($primary_first) {
355 355
 			$stores = array(
356 356
 				$this->primary_store,
357 357
 				$this->secondary_store,
358 358
 			);
359
-		} elseif ( $action_id < $this->demarkation_id ) {
359
+		} elseif ($action_id < $this->demarkation_id) {
360 360
 			$stores = array(
361 361
 				$this->secondary_store,
362 362
 				$this->primary_store,
@@ -367,9 +367,9 @@  discard block
 block discarded – undo
367 367
 			);
368 368
 		}
369 369
 
370
-		foreach ( $stores as $store ) {
371
-			$action = $store->fetch_action( $action_id );
372
-			if ( ! is_a( $action, 'ActionScheduler_NullAction' ) ) {
370
+		foreach ($stores as $store) {
371
+			$action = $store->fetch_action($action_id);
372
+			if ( ! is_a($action, 'ActionScheduler_NullAction')) {
373 373
 				return $store;
374 374
 			}
375 375
 		}
@@ -394,8 +394,8 @@  discard block
 block discarded – undo
394 394
 	 *
395 395
 	 * @param int $action_id Action ID.
396 396
 	 */
397
-	public function get_claim_id( $action_id ) {
398
-		return $this->primary_store->get_claim_id( $action_id );
397
+	public function get_claim_id($action_id) {
398
+		return $this->primary_store->get_claim_id($action_id);
399 399
 	}
400 400
 
401 401
 	/**
@@ -403,8 +403,8 @@  discard block
 block discarded – undo
403 403
 	 *
404 404
 	 * @param ActionScheduler_ActionClaim $claim Claim object.
405 405
 	 */
406
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
407
-		$this->primary_store->release_claim( $claim );
406
+	public function release_claim(ActionScheduler_ActionClaim $claim) {
407
+		$this->primary_store->release_claim($claim);
408 408
 	}
409 409
 
410 410
 	/**
@@ -412,8 +412,8 @@  discard block
 block discarded – undo
412 412
 	 *
413 413
 	 * @param int $action_id Action ID.
414 414
 	 */
415
-	public function unclaim_action( $action_id ) {
416
-		$this->primary_store->unclaim_action( $action_id );
415
+	public function unclaim_action($action_id) {
416
+		$this->primary_store->unclaim_action($action_id);
417 417
 	}
418 418
 
419 419
 	/**
@@ -421,7 +421,7 @@  discard block
 block discarded – undo
421 421
 	 *
422 422
 	 * @param int $claim_id Claim ID.
423 423
 	 */
424
-	public function find_actions_by_claim_id( $claim_id ) {
425
-		return $this->primary_store->find_actions_by_claim_id( $claim_id );
424
+	public function find_actions_by_claim_id($claim_id) {
425
+		return $this->primary_store->find_actions_by_claim_id($claim_id);
426 426
 	}
427 427
 }
Please login to merge, or discard this patch.