Passed
Pull Request — master (#284)
by Brian
06:11
created
action-scheduler/classes/data-stores/ActionScheduler_wpCommentLogger.php 2 patches
Indentation   +232 added lines, -232 removed lines patch added patch discarded remove patch
@@ -4,237 +4,237 @@
 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(array(
70
-			'post_id' => $action_id,
71
-			'orderby' => 'comment_date_gmt',
72
-			'order' => 'ASC',
73
-			'type' => self::TYPE,
74
-			'status' => $status,
75
-		));
76
-		$logs = array();
77
-		foreach ( $comments as $c ) {
78
-			$entry = $this->get_entry( $c );
79
-			if ( !empty($entry) ) {
80
-				$logs[] = $entry;
81
-			}
82
-		}
83
-		return $logs;
84
-	}
85
-
86
-	protected function get_comment( $comment_id ) {
87
-		return get_comment( $comment_id );
88
-	}
89
-
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( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
180
-
181
-			foreach ( (array) $count as $row ) {
182
-				// Don't count post-trashed toward totals
183
-				if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
184
-					$total += $row['num_comments'];
185
-				}
186
-				if ( isset( $approved[ $row['comment_approved'] ] ) ) {
187
-					$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
188
-				}
189
-			}
190
-
191
-			$stats['total_comments'] = $total;
192
-			$stats['all']            = $total;
193
-
194
-			foreach ( $approved as $key ) {
195
-				if ( empty( $stats[ $key ] ) ) {
196
-					$stats[ $key ] = 0;
197
-				}
198
-			}
199
-
200
-			$stats = (object) $stats;
201
-			set_transient( 'as_comment_count', $stats );
202
-		}
203
-
204
-		return $stats;
205
-	}
206
-
207
-	/**
208
-	 * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache
209
-	 * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
210
-	 */
211
-	public function delete_comment_count_cache() {
212
-		delete_transient( 'as_comment_count' );
213
-	}
214
-
215
-	/**
216
-	 * @codeCoverageIgnore
217
-	 */
218
-	public function init() {
219
-		add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
220
-		add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
221
-
222
-		parent::init();
223
-
224
-		add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
225
-		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
226
-		add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
227
-
228
-		// Delete comments count cache whenever there is a new comment or a comment status changes
229
-		add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
230
-		add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
231
-	}
232
-
233
-	public function disable_comment_counting() {
234
-		wp_defer_comment_counting(true);
235
-	}
236
-	public function enable_comment_counting() {
237
-		wp_defer_comment_counting(false);
238
-	}
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(array(
70
+            'post_id' => $action_id,
71
+            'orderby' => 'comment_date_gmt',
72
+            'order' => 'ASC',
73
+            'type' => self::TYPE,
74
+            'status' => $status,
75
+        ));
76
+        $logs = array();
77
+        foreach ( $comments as $c ) {
78
+            $entry = $this->get_entry( $c );
79
+            if ( !empty($entry) ) {
80
+                $logs[] = $entry;
81
+            }
82
+        }
83
+        return $logs;
84
+    }
85
+
86
+    protected function get_comment( $comment_id ) {
87
+        return get_comment( $comment_id );
88
+    }
89
+
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( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
180
+
181
+            foreach ( (array) $count as $row ) {
182
+                // Don't count post-trashed toward totals
183
+                if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
184
+                    $total += $row['num_comments'];
185
+                }
186
+                if ( isset( $approved[ $row['comment_approved'] ] ) ) {
187
+                    $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
188
+                }
189
+            }
190
+
191
+            $stats['total_comments'] = $total;
192
+            $stats['all']            = $total;
193
+
194
+            foreach ( $approved as $key ) {
195
+                if ( empty( $stats[ $key ] ) ) {
196
+                    $stats[ $key ] = 0;
197
+                }
198
+            }
199
+
200
+            $stats = (object) $stats;
201
+            set_transient( 'as_comment_count', $stats );
202
+        }
203
+
204
+        return $stats;
205
+    }
206
+
207
+    /**
208
+     * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache
209
+     * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
210
+     */
211
+    public function delete_comment_count_cache() {
212
+        delete_transient( 'as_comment_count' );
213
+    }
214
+
215
+    /**
216
+     * @codeCoverageIgnore
217
+     */
218
+    public function init() {
219
+        add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
220
+        add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
221
+
222
+        parent::init();
223
+
224
+        add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
225
+        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
226
+        add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
227
+
228
+        // Delete comments count cache whenever there is a new comment or a comment status changes
229
+        add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
230
+        add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
231
+    }
232
+
233
+    public function disable_comment_counting() {
234
+        wp_defer_comment_counting(true);
235
+    }
236
+    public function enable_comment_counting() {
237
+        wp_defer_comment_counting(false);
238
+    }
239 239
 
240 240
 }
Please login to merge, or discard this patch.
Spacing   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -14,20 +14,20 @@  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 29
 		$comment_date_gmt = $date->format('Y-m-d H:i:s');
30
-		ActionScheduler_TimezoneHelper::set_local_timezone( $date );
30
+		ActionScheduler_TimezoneHelper::set_local_timezone($date);
31 31
 		$comment_data = array(
32 32
 			'comment_post_ID' => $action_id,
33 33
 			'comment_date' => $date->format('Y-m-d H:i:s'),
@@ -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(array(
@@ -74,17 +74,17 @@  discard block
 block discarded – undo
74 74
 			'status' => $status,
75 75
 		));
76 76
 		$logs = array();
77
-		foreach ( $comments as $c ) {
78
-			$entry = $this->get_entry( $c );
79
-			if ( !empty($entry) ) {
77
+		foreach ($comments as $c) {
78
+			$entry = $this->get_entry($c);
79
+			if (!empty($entry)) {
80 80
 				$logs[] = $entry;
81 81
 			}
82 82
 		}
83 83
 		return $logs;
84 84
 	}
85 85
 
86
-	protected function get_comment( $comment_id ) {
87
-		return get_comment( $comment_id );
86
+	protected function get_comment($comment_id) {
87
+		return get_comment($comment_id);
88 88
 	}
89 89
 
90 90
 
@@ -92,14 +92,14 @@  discard block
 block discarded – undo
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,38 +167,38 @@  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();
179
-			$approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
179
+			$approved = array('0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed');
180 180
 
181
-			foreach ( (array) $count as $row ) {
181
+			foreach ((array) $count as $row) {
182 182
 				// Don't count post-trashed toward totals
183
-				if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
183
+				if ('post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved']) {
184 184
 					$total += $row['num_comments'];
185 185
 				}
186
-				if ( isset( $approved[ $row['comment_approved'] ] ) ) {
187
-					$stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
186
+				if (isset($approved[$row['comment_approved']])) {
187
+					$stats[$approved[$row['comment_approved']]] = $row['num_comments'];
188 188
 				}
189 189
 			}
190 190
 
191 191
 			$stats['total_comments'] = $total;
192 192
 			$stats['all']            = $total;
193 193
 
194
-			foreach ( $approved as $key ) {
195
-				if ( empty( $stats[ $key ] ) ) {
196
-					$stats[ $key ] = 0;
194
+			foreach ($approved as $key) {
195
+				if (empty($stats[$key])) {
196
+					$stats[$key] = 0;
197 197
 				}
198 198
 			}
199 199
 
200 200
 			$stats = (object) $stats;
201
-			set_transient( 'as_comment_count', $stats );
201
+			set_transient('as_comment_count', $stats);
202 202
 		}
203 203
 
204 204
 		return $stats;
@@ -209,25 +209,25 @@  discard block
 block discarded – undo
209 209
 	 * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
210 210
 	 */
211 211
 	public function delete_comment_count_cache() {
212
-		delete_transient( 'as_comment_count' );
212
+		delete_transient('as_comment_count');
213 213
 	}
214 214
 
215 215
 	/**
216 216
 	 * @codeCoverageIgnore
217 217
 	 */
218 218
 	public function init() {
219
-		add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
220
-		add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
219
+		add_action('action_scheduler_before_process_queue', array($this, 'disable_comment_counting'), 10, 0);
220
+		add_action('action_scheduler_after_process_queue', array($this, 'enable_comment_counting'), 10, 0);
221 221
 
222 222
 		parent::init();
223 223
 
224
-		add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
225
-		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
226
-		add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
224
+		add_action('pre_get_comments', array($this, 'filter_comment_queries'), 10, 1);
225
+		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
226
+		add_action('comment_feed_where', array($this, 'filter_comment_feed'), 10, 2);
227 227
 
228 228
 		// Delete comments count cache whenever there is a new comment or a comment status changes
229
-		add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
230
-		add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
229
+		add_action('wp_insert_comment', array($this, 'delete_comment_count_cache'));
230
+		add_action('wp_set_comment_status', array($this, 'delete_comment_count_cache'));
231 231
 	}
232 232
 
233 233
 	public function disable_comment_counting() {
Please login to merge, or discard this patch.
action-scheduler/classes/data-stores/ActionScheduler_wpPostStore.php 2 patches
Indentation   +844 added lines, -844 removed lines patch added patch discarded remove patch
@@ -4,857 +4,857 @@
 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
-	/** @var DateTimeZone */
13
-	protected $local_timezone = NULL;
14
-
15
-	public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
16
-		try {
17
-			$this->validate_action( $action );
18
-			$post_array = $this->create_post_array( $action, $scheduled_date );
19
-			$post_id = $this->save_post_array( $post_array );
20
-			$this->save_post_schedule( $post_id, $action->get_schedule() );
21
-			$this->save_action_group( $post_id, $action->get_group() );
22
-			do_action( 'action_scheduler_stored_action', $post_id );
23
-			return $post_id;
24
-		} catch ( Exception $e ) {
25
-			throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
26
-		}
27
-	}
28
-
29
-	protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
30
-		$post = array(
31
-			'post_type' => self::POST_TYPE,
32
-			'post_title' => $action->get_hook(),
33
-			'post_content' => json_encode($action->get_args()),
34
-			'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
35
-			'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
36
-			'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
37
-		);
38
-		return $post;
39
-	}
40
-
41
-	protected function save_post_array( $post_array ) {
42
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
43
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
44
-
45
-		$has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
46
-
47
-		if ( $has_kses ) {
48
-			// Prevent KSES from corrupting JSON in post_content.
49
-			kses_remove_filters();
50
-		}
51
-
52
-		$post_id = wp_insert_post($post_array);
53
-
54
-		if ( $has_kses ) {
55
-			kses_init_filters();
56
-		}
57
-
58
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
59
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
60
-
61
-		if ( is_wp_error($post_id) || empty($post_id) ) {
62
-			throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
63
-		}
64
-		return $post_id;
65
-	}
66
-
67
-	public function filter_insert_post_data( $postdata ) {
68
-		if ( $postdata['post_type'] == self::POST_TYPE ) {
69
-			$postdata['post_author'] = 0;
70
-			if ( $postdata['post_status'] == 'future' ) {
71
-				$postdata['post_status'] = 'publish';
72
-			}
73
-		}
74
-		return $postdata;
75
-	}
76
-
77
-	/**
78
-	 * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug().
79
-	 *
80
-	 * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish'
81
-	 * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug()
82
-	 * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing
83
-	 * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a
84
-	 * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a
85
-	 * database containing thousands of related post_name values.
86
-	 *
87
-	 * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue.
88
-	 *
89
-	 * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This
90
-	 * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a
91
-	 * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an
92
-	 * action's slug, being probably unique is good enough.
93
-	 *
94
-	 * For more backstory on this issue, see:
95
-	 * - https://github.com/woocommerce/action-scheduler/issues/44 and
96
-	 * - https://core.trac.wordpress.org/ticket/21112
97
-	 *
98
-	 * @param string $override_slug Short-circuit return value.
99
-	 * @param string $slug          The desired slug (post_name).
100
-	 * @param int    $post_ID       Post ID.
101
-	 * @param string $post_status   The post status.
102
-	 * @param string $post_type     Post type.
103
-	 * @return string
104
-	 */
105
-	public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
106
-		if ( self::POST_TYPE == $post_type ) {
107
-			$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
108
-		}
109
-		return $override_slug;
110
-	}
111
-
112
-	protected function save_post_schedule( $post_id, $schedule ) {
113
-		update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
114
-	}
115
-
116
-	protected function save_action_group( $post_id, $group ) {
117
-		if ( empty($group) ) {
118
-			wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE );
119
-		} else {
120
-			wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE );
121
-		}
122
-	}
123
-
124
-	public function fetch_action( $action_id ) {
125
-		$post = $this->get_post( $action_id );
126
-		if ( empty($post) || $post->post_type != self::POST_TYPE ) {
127
-			return $this->get_null_action();
128
-		}
129
-
130
-		try {
131
-			$action = $this->make_action_from_post( $post );
132
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
133
-			do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
134
-			return $this->get_null_action();
135
-		}
136
-
137
-		return $action;
138
-	}
139
-
140
-	protected function get_post( $action_id ) {
141
-		if ( empty($action_id) ) {
142
-			return NULL;
143
-		}
144
-		return get_post($action_id);
145
-	}
146
-
147
-	protected function get_null_action() {
148
-		return new ActionScheduler_NullAction();
149
-	}
150
-
151
-	protected function make_action_from_post( $post ) {
152
-		$hook = $post->post_title;
153
-
154
-		$args = json_decode( $post->post_content, true );
155
-		$this->validate_args( $args, $post->ID );
156
-
157
-		$schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
158
-		$this->validate_schedule( $schedule, $post->ID );
159
-
160
-		$group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
161
-		$group = empty( $group ) ? '' : reset($group);
162
-
163
-		return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
164
-	}
165
-
166
-	/**
167
-	 * @param string $post_status
168
-	 *
169
-	 * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
170
-	 * @return string
171
-	 */
172
-	protected function get_action_status_by_post_status( $post_status ) {
173
-
174
-		switch ( $post_status ) {
175
-			case 'publish' :
176
-				$action_status = self::STATUS_COMPLETE;
177
-				break;
178
-			case 'trash' :
179
-				$action_status = self::STATUS_CANCELED;
180
-				break;
181
-			default :
182
-				if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
183
-					throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
184
-				}
185
-				$action_status = $post_status;
186
-				break;
187
-		}
188
-
189
-		return $action_status;
190
-	}
191
-
192
-	/**
193
-	 * @param string $action_status
194
-	 * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
195
-	 * @return string
196
-	 */
197
-	protected function get_post_status_by_action_status( $action_status ) {
198
-
199
-		switch ( $action_status ) {
200
-			case self::STATUS_COMPLETE :
201
-				$post_status = 'publish';
202
-				break;
203
-			case self::STATUS_CANCELED :
204
-				$post_status = 'trash';
205
-				break;
206
-			default :
207
-				if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
208
-					throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
209
-				}
210
-				$post_status = $action_status;
211
-				break;
212
-		}
213
-
214
-		return $post_status;
215
-	}
216
-
217
-	/**
218
-	 * @param string $hook
219
-	 * @param array $params
220
-	 *
221
-	 * @return string ID of the next action matching the criteria or NULL if not found
222
-	 */
223
-	public function find_action( $hook, $params = array() ) {
224
-		$params = wp_parse_args( $params, array(
225
-			'args' => NULL,
226
-			'status' => ActionScheduler_Store::STATUS_PENDING,
227
-			'group' => '',
228
-		));
229
-		/** @var wpdb $wpdb */
230
-		global $wpdb;
231
-		$query = "SELECT p.ID FROM {$wpdb->posts} p";
232
-		$args = array();
233
-		if ( !empty($params['group']) ) {
234
-			$query .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
235
-			$query .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
236
-			$query .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id AND t.slug=%s";
237
-			$args[] = $params['group'];
238
-		}
239
-		$query .= " WHERE p.post_title=%s";
240
-		$args[] = $hook;
241
-		$query .= " AND p.post_type=%s";
242
-		$args[] = self::POST_TYPE;
243
-		if ( !is_null($params['args']) ) {
244
-			$query .= " AND p.post_content=%s";
245
-			$args[] = json_encode($params['args']);
246
-		}
247
-
248
-		if ( ! empty( $params['status'] ) ) {
249
-			$query .= " AND p.post_status=%s";
250
-			$args[] = $this->get_post_status_by_action_status( $params['status'] );
251
-		}
252
-
253
-		switch ( $params['status'] ) {
254
-			case self::STATUS_COMPLETE:
255
-			case self::STATUS_RUNNING:
256
-			case self::STATUS_FAILED:
257
-				$order = 'DESC'; // Find the most recent action that matches
258
-				break;
259
-			case self::STATUS_PENDING:
260
-			default:
261
-				$order = 'ASC'; // Find the next action that matches
262
-				break;
263
-		}
264
-		$query .= " ORDER BY post_date_gmt $order LIMIT 1";
265
-
266
-		$query = $wpdb->prepare( $query, $args );
267
-
268
-		$id = $wpdb->get_var($query);
269
-		return $id;
270
-	}
271
-
272
-	/**
273
-	 * Returns the SQL statement to query (or count) actions.
274
-	 *
275
-	 * @param array $query Filtering options
276
-	 * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count
277
-	 * @throws InvalidArgumentException if $select_or_count not count or select
278
-	 * @return string SQL statement. The returned SQL is already properly escaped.
279
-	 */
280
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
281
-
282
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
283
-			throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
284
-		}
285
-
286
-		$query = wp_parse_args( $query, array(
287
-			'hook' => '',
288
-			'args' => NULL,
289
-			'date' => NULL,
290
-			'date_compare' => '<=',
291
-			'modified' => NULL,
292
-			'modified_compare' => '<=',
293
-			'group' => '',
294
-			'status' => '',
295
-			'claimed' => NULL,
296
-			'per_page' => 5,
297
-			'offset' => 0,
298
-			'orderby' => 'date',
299
-			'order' => 'ASC',
300
-			'search' => '',
301
-		) );
302
-
303
-		/** @var wpdb $wpdb */
304
-		global $wpdb;
305
-		$sql  = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
306
-		$sql .= "FROM {$wpdb->posts} p";
307
-		$sql_params = array();
308
-		if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
309
-			$sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
310
-			$sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
311
-			$sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
312
-		} elseif ( ! empty( $query['group'] ) ) {
313
-			$sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
314
-			$sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
315
-			$sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
316
-			$sql .= " AND t.slug=%s";
317
-			$sql_params[] = $query['group'];
318
-		}
319
-		$sql .= " WHERE post_type=%s";
320
-		$sql_params[] = self::POST_TYPE;
321
-		if ( $query['hook'] ) {
322
-			$sql .= " AND p.post_title=%s";
323
-			$sql_params[] = $query['hook'];
324
-		}
325
-		if ( !is_null($query['args']) ) {
326
-			$sql .= " AND p.post_content=%s";
327
-			$sql_params[] = json_encode($query['args']);
328
-		}
329
-
330
-		if ( ! empty( $query['status'] ) ) {
331
-			$sql .= " AND p.post_status=%s";
332
-			$sql_params[] = $this->get_post_status_by_action_status( $query['status'] );
333
-		}
334
-
335
-		if ( $query['date'] instanceof DateTime ) {
336
-			$date = clone $query['date'];
337
-			$date->setTimezone( new DateTimeZone('UTC') );
338
-			$date_string = $date->format('Y-m-d H:i:s');
339
-			$comparator = $this->validate_sql_comparator($query['date_compare']);
340
-			$sql .= " AND p.post_date_gmt $comparator %s";
341
-			$sql_params[] = $date_string;
342
-		}
343
-
344
-		if ( $query['modified'] instanceof DateTime ) {
345
-			$modified = clone $query['modified'];
346
-			$modified->setTimezone( new DateTimeZone('UTC') );
347
-			$date_string = $modified->format('Y-m-d H:i:s');
348
-			$comparator = $this->validate_sql_comparator($query['modified_compare']);
349
-			$sql .= " AND p.post_modified_gmt $comparator %s";
350
-			$sql_params[] = $date_string;
351
-		}
352
-
353
-		if ( $query['claimed'] === TRUE ) {
354
-			$sql .= " AND p.post_password != ''";
355
-		} elseif ( $query['claimed'] === FALSE ) {
356
-			$sql .= " AND p.post_password = ''";
357
-		} elseif ( !is_null($query['claimed']) ) {
358
-			$sql .= " AND p.post_password = %s";
359
-			$sql_params[] = $query['claimed'];
360
-		}
361
-
362
-		if ( ! empty( $query['search'] ) ) {
363
-			$sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
364
-			for( $i = 0; $i < 3; $i++ ) {
365
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
366
-			}
367
-		}
368
-
369
-		if ( 'select' === $select_or_count ) {
370
-			switch ( $query['orderby'] ) {
371
-				case 'hook':
372
-					$orderby = 'p.post_title';
373
-					break;
374
-				case 'group':
375
-					$orderby = 't.name';
376
-					break;
377
-				case 'status':
378
-					$orderby = 'p.post_status';
379
-					break;
380
-				case 'modified':
381
-					$orderby = 'p.post_modified';
382
-					break;
383
-				case 'claim_id':
384
-					$orderby = 'p.post_password';
385
-					break;
386
-				case 'schedule':
387
-				case 'date':
388
-				default:
389
-					$orderby = 'p.post_date_gmt';
390
-					break;
391
-			}
392
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
393
-				$order = 'ASC';
394
-			} else {
395
-				$order = 'DESC';
396
-			}
397
-			$sql .= " ORDER BY $orderby $order";
398
-			if ( $query['per_page'] > 0 ) {
399
-				$sql .= " LIMIT %d, %d";
400
-				$sql_params[] = $query['offset'];
401
-				$sql_params[] = $query['per_page'];
402
-			}
403
-		}
404
-
405
-		return $wpdb->prepare( $sql, $sql_params );
406
-	}
407
-
408
-	/**
409
-	 * @param array $query
410
-	 * @param string $query_type Whether to select or count the results. Default, select.
411
-	 * @return string|array The IDs of actions matching the query
412
-	 */
413
-	public function query_actions( $query = array(), $query_type = 'select' ) {
414
-		/** @var wpdb $wpdb */
415
-		global $wpdb;
416
-
417
-		$sql = $this->get_query_actions_sql( $query, $query_type );
418
-
419
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
420
-	}
421
-
422
-	/**
423
-	 * Get a count of all actions in the store, grouped by status
424
-	 *
425
-	 * @return array
426
-	 */
427
-	public function action_counts() {
428
-
429
-		$action_counts_by_status = array();
430
-		$action_stati_and_labels = $this->get_status_labels();
431
-		$posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
432
-
433
-		foreach ( $posts_count_by_status as $post_status_name => $count ) {
434
-
435
-			try {
436
-				$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
437
-			} catch ( Exception $e ) {
438
-				// Ignore any post statuses that aren't for actions
439
-				continue;
440
-			}
441
-			if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
442
-				$action_counts_by_status[ $action_status_name ] = $count;
443
-			}
444
-		}
445
-
446
-		return $action_counts_by_status;
447
-	}
448
-
449
-	/**
450
-	 * @param string $action_id
451
-	 *
452
-	 * @throws InvalidArgumentException
453
-	 */
454
-	public function cancel_action( $action_id ) {
455
-		$post = get_post( $action_id );
456
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
457
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
458
-		}
459
-		do_action( 'action_scheduler_canceled_action', $action_id );
460
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
461
-		wp_trash_post( $action_id );
462
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
463
-	}
464
-
465
-	public function delete_action( $action_id ) {
466
-		$post = get_post( $action_id );
467
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
468
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
469
-		}
470
-		do_action( 'action_scheduler_deleted_action', $action_id );
471
-
472
-		wp_delete_post( $action_id, TRUE );
473
-	}
474
-
475
-	/**
476
-	 * @param string $action_id
477
-	 *
478
-	 * @throws InvalidArgumentException
479
-	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
480
-	 */
481
-	public function get_date( $action_id ) {
482
-		$next = $this->get_date_gmt( $action_id );
483
-		return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
484
-	}
485
-
486
-	/**
487
-	 * @param string $action_id
488
-	 *
489
-	 * @throws InvalidArgumentException
490
-	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
491
-	 */
492
-	public function get_date_gmt( $action_id ) {
493
-		$post = get_post( $action_id );
494
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
495
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
496
-		}
497
-		if ( $post->post_status == 'publish' ) {
498
-			return as_get_datetime_object( $post->post_modified_gmt );
499
-		} else {
500
-			return as_get_datetime_object( $post->post_date_gmt );
501
-		}
502
-	}
503
-
504
-	/**
505
-	 * @param int      $max_actions
506
-	 * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
507
-	 * @param array    $hooks       Claim only actions with a hook or hooks.
508
-	 * @param string   $group       Claim only actions in the given group.
509
-	 *
510
-	 * @return ActionScheduler_ActionClaim
511
-	 * @throws RuntimeException When there is an error staking a claim.
512
-	 * @throws InvalidArgumentException When the given group is not valid.
513
-	 */
514
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
515
-		$claim_id = $this->generate_claim_id();
516
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
517
-		$action_ids = $this->find_actions_by_claim_id( $claim_id );
518
-
519
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
520
-	}
521
-
522
-	/**
523
-	 * @return int
524
-	 */
525
-	public function get_claim_count(){
526
-		global $wpdb;
527
-
528
-		$sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
529
-		$sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) );
530
-
531
-		return $wpdb->get_var( $sql );
532
-	}
533
-
534
-	protected function generate_claim_id() {
535
-		$claim_id = md5(microtime(true) . rand(0,1000));
536
-		return substr($claim_id, 0, 20); // to fit in db field with 20 char limit
537
-	}
538
-
539
-	/**
540
-	 * @param string   $claim_id
541
-	 * @param int      $limit
542
-	 * @param DateTime $before_date Should use UTC timezone.
543
-	 * @param array    $hooks       Claim only actions with a hook or hooks.
544
-	 * @param string   $group       Claim only actions in the given group.
545
-	 *
546
-	 * @return int The number of actions that were claimed
547
-	 * @throws RuntimeException When there is a database error.
548
-	 * @throws InvalidArgumentException When the group is invalid.
549
-	 */
550
-	protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
551
-		// Set up initial variables.
552
-		$date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
553
-		$limit_ids = ! empty( $group );
554
-		$ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
555
-
556
-		// If limiting by IDs and no posts found, then return early since we have nothing to update.
557
-		if ( $limit_ids && 0 === count( $ids ) ) {
558
-			return 0;
559
-		}
560
-
561
-		/** @var wpdb $wpdb */
562
-		global $wpdb;
563
-
564
-		/*
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
+    /** @var DateTimeZone */
13
+    protected $local_timezone = NULL;
14
+
15
+    public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
16
+        try {
17
+            $this->validate_action( $action );
18
+            $post_array = $this->create_post_array( $action, $scheduled_date );
19
+            $post_id = $this->save_post_array( $post_array );
20
+            $this->save_post_schedule( $post_id, $action->get_schedule() );
21
+            $this->save_action_group( $post_id, $action->get_group() );
22
+            do_action( 'action_scheduler_stored_action', $post_id );
23
+            return $post_id;
24
+        } catch ( Exception $e ) {
25
+            throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
26
+        }
27
+    }
28
+
29
+    protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
30
+        $post = array(
31
+            'post_type' => self::POST_TYPE,
32
+            'post_title' => $action->get_hook(),
33
+            'post_content' => json_encode($action->get_args()),
34
+            'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
35
+            'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
36
+            'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
37
+        );
38
+        return $post;
39
+    }
40
+
41
+    protected function save_post_array( $post_array ) {
42
+        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
43
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
44
+
45
+        $has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
46
+
47
+        if ( $has_kses ) {
48
+            // Prevent KSES from corrupting JSON in post_content.
49
+            kses_remove_filters();
50
+        }
51
+
52
+        $post_id = wp_insert_post($post_array);
53
+
54
+        if ( $has_kses ) {
55
+            kses_init_filters();
56
+        }
57
+
58
+        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
59
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
60
+
61
+        if ( is_wp_error($post_id) || empty($post_id) ) {
62
+            throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
63
+        }
64
+        return $post_id;
65
+    }
66
+
67
+    public function filter_insert_post_data( $postdata ) {
68
+        if ( $postdata['post_type'] == self::POST_TYPE ) {
69
+            $postdata['post_author'] = 0;
70
+            if ( $postdata['post_status'] == 'future' ) {
71
+                $postdata['post_status'] = 'publish';
72
+            }
73
+        }
74
+        return $postdata;
75
+    }
76
+
77
+    /**
78
+     * Create a (probably unique) post name for scheduled actions in a more performant manner than wp_unique_post_slug().
79
+     *
80
+     * When an action's post status is transitioned to something other than 'draft', 'pending' or 'auto-draft, like 'publish'
81
+     * or 'failed' or 'trash', WordPress will find a unique slug (stored in post_name column) using the wp_unique_post_slug()
82
+     * function. This is done to ensure URL uniqueness. The approach taken by wp_unique_post_slug() is to iterate over existing
83
+     * post_name values that match, and append a number 1 greater than the largest. This makes sense when manually creating a
84
+     * post from the Edit Post screen. It becomes a bottleneck when automatically processing thousands of actions, with a
85
+     * database containing thousands of related post_name values.
86
+     *
87
+     * WordPress 5.1 introduces the 'pre_wp_unique_post_slug' filter for plugins to address this issue.
88
+     *
89
+     * We can short-circuit WordPress's wp_unique_post_slug() approach using the 'pre_wp_unique_post_slug' filter. This
90
+     * method is available to be used as a callback on that filter. It provides a more scalable approach to generating a
91
+     * post_name/slug that is probably unique. Because Action Scheduler never actually uses the post_name field, or an
92
+     * action's slug, being probably unique is good enough.
93
+     *
94
+     * For more backstory on this issue, see:
95
+     * - https://github.com/woocommerce/action-scheduler/issues/44 and
96
+     * - https://core.trac.wordpress.org/ticket/21112
97
+     *
98
+     * @param string $override_slug Short-circuit return value.
99
+     * @param string $slug          The desired slug (post_name).
100
+     * @param int    $post_ID       Post ID.
101
+     * @param string $post_status   The post status.
102
+     * @param string $post_type     Post type.
103
+     * @return string
104
+     */
105
+    public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
106
+        if ( self::POST_TYPE == $post_type ) {
107
+            $override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
108
+        }
109
+        return $override_slug;
110
+    }
111
+
112
+    protected function save_post_schedule( $post_id, $schedule ) {
113
+        update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
114
+    }
115
+
116
+    protected function save_action_group( $post_id, $group ) {
117
+        if ( empty($group) ) {
118
+            wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE );
119
+        } else {
120
+            wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE );
121
+        }
122
+    }
123
+
124
+    public function fetch_action( $action_id ) {
125
+        $post = $this->get_post( $action_id );
126
+        if ( empty($post) || $post->post_type != self::POST_TYPE ) {
127
+            return $this->get_null_action();
128
+        }
129
+
130
+        try {
131
+            $action = $this->make_action_from_post( $post );
132
+        } catch ( ActionScheduler_InvalidActionException $exception ) {
133
+            do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
134
+            return $this->get_null_action();
135
+        }
136
+
137
+        return $action;
138
+    }
139
+
140
+    protected function get_post( $action_id ) {
141
+        if ( empty($action_id) ) {
142
+            return NULL;
143
+        }
144
+        return get_post($action_id);
145
+    }
146
+
147
+    protected function get_null_action() {
148
+        return new ActionScheduler_NullAction();
149
+    }
150
+
151
+    protected function make_action_from_post( $post ) {
152
+        $hook = $post->post_title;
153
+
154
+        $args = json_decode( $post->post_content, true );
155
+        $this->validate_args( $args, $post->ID );
156
+
157
+        $schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
158
+        $this->validate_schedule( $schedule, $post->ID );
159
+
160
+        $group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
161
+        $group = empty( $group ) ? '' : reset($group);
162
+
163
+        return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
164
+    }
165
+
166
+    /**
167
+     * @param string $post_status
168
+     *
169
+     * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
170
+     * @return string
171
+     */
172
+    protected function get_action_status_by_post_status( $post_status ) {
173
+
174
+        switch ( $post_status ) {
175
+            case 'publish' :
176
+                $action_status = self::STATUS_COMPLETE;
177
+                break;
178
+            case 'trash' :
179
+                $action_status = self::STATUS_CANCELED;
180
+                break;
181
+            default :
182
+                if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
183
+                    throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
184
+                }
185
+                $action_status = $post_status;
186
+                break;
187
+        }
188
+
189
+        return $action_status;
190
+    }
191
+
192
+    /**
193
+     * @param string $action_status
194
+     * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
195
+     * @return string
196
+     */
197
+    protected function get_post_status_by_action_status( $action_status ) {
198
+
199
+        switch ( $action_status ) {
200
+            case self::STATUS_COMPLETE :
201
+                $post_status = 'publish';
202
+                break;
203
+            case self::STATUS_CANCELED :
204
+                $post_status = 'trash';
205
+                break;
206
+            default :
207
+                if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
208
+                    throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
209
+                }
210
+                $post_status = $action_status;
211
+                break;
212
+        }
213
+
214
+        return $post_status;
215
+    }
216
+
217
+    /**
218
+     * @param string $hook
219
+     * @param array $params
220
+     *
221
+     * @return string ID of the next action matching the criteria or NULL if not found
222
+     */
223
+    public function find_action( $hook, $params = array() ) {
224
+        $params = wp_parse_args( $params, array(
225
+            'args' => NULL,
226
+            'status' => ActionScheduler_Store::STATUS_PENDING,
227
+            'group' => '',
228
+        ));
229
+        /** @var wpdb $wpdb */
230
+        global $wpdb;
231
+        $query = "SELECT p.ID FROM {$wpdb->posts} p";
232
+        $args = array();
233
+        if ( !empty($params['group']) ) {
234
+            $query .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
235
+            $query .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
236
+            $query .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id AND t.slug=%s";
237
+            $args[] = $params['group'];
238
+        }
239
+        $query .= " WHERE p.post_title=%s";
240
+        $args[] = $hook;
241
+        $query .= " AND p.post_type=%s";
242
+        $args[] = self::POST_TYPE;
243
+        if ( !is_null($params['args']) ) {
244
+            $query .= " AND p.post_content=%s";
245
+            $args[] = json_encode($params['args']);
246
+        }
247
+
248
+        if ( ! empty( $params['status'] ) ) {
249
+            $query .= " AND p.post_status=%s";
250
+            $args[] = $this->get_post_status_by_action_status( $params['status'] );
251
+        }
252
+
253
+        switch ( $params['status'] ) {
254
+            case self::STATUS_COMPLETE:
255
+            case self::STATUS_RUNNING:
256
+            case self::STATUS_FAILED:
257
+                $order = 'DESC'; // Find the most recent action that matches
258
+                break;
259
+            case self::STATUS_PENDING:
260
+            default:
261
+                $order = 'ASC'; // Find the next action that matches
262
+                break;
263
+        }
264
+        $query .= " ORDER BY post_date_gmt $order LIMIT 1";
265
+
266
+        $query = $wpdb->prepare( $query, $args );
267
+
268
+        $id = $wpdb->get_var($query);
269
+        return $id;
270
+    }
271
+
272
+    /**
273
+     * Returns the SQL statement to query (or count) actions.
274
+     *
275
+     * @param array $query Filtering options
276
+     * @param string $select_or_count  Whether the SQL should select and return the IDs or just the row count
277
+     * @throws InvalidArgumentException if $select_or_count not count or select
278
+     * @return string SQL statement. The returned SQL is already properly escaped.
279
+     */
280
+    protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
281
+
282
+        if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
283
+            throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
284
+        }
285
+
286
+        $query = wp_parse_args( $query, array(
287
+            'hook' => '',
288
+            'args' => NULL,
289
+            'date' => NULL,
290
+            'date_compare' => '<=',
291
+            'modified' => NULL,
292
+            'modified_compare' => '<=',
293
+            'group' => '',
294
+            'status' => '',
295
+            'claimed' => NULL,
296
+            'per_page' => 5,
297
+            'offset' => 0,
298
+            'orderby' => 'date',
299
+            'order' => 'ASC',
300
+            'search' => '',
301
+        ) );
302
+
303
+        /** @var wpdb $wpdb */
304
+        global $wpdb;
305
+        $sql  = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
306
+        $sql .= "FROM {$wpdb->posts} p";
307
+        $sql_params = array();
308
+        if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
309
+            $sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
310
+            $sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
311
+            $sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
312
+        } elseif ( ! empty( $query['group'] ) ) {
313
+            $sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
314
+            $sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
315
+            $sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
316
+            $sql .= " AND t.slug=%s";
317
+            $sql_params[] = $query['group'];
318
+        }
319
+        $sql .= " WHERE post_type=%s";
320
+        $sql_params[] = self::POST_TYPE;
321
+        if ( $query['hook'] ) {
322
+            $sql .= " AND p.post_title=%s";
323
+            $sql_params[] = $query['hook'];
324
+        }
325
+        if ( !is_null($query['args']) ) {
326
+            $sql .= " AND p.post_content=%s";
327
+            $sql_params[] = json_encode($query['args']);
328
+        }
329
+
330
+        if ( ! empty( $query['status'] ) ) {
331
+            $sql .= " AND p.post_status=%s";
332
+            $sql_params[] = $this->get_post_status_by_action_status( $query['status'] );
333
+        }
334
+
335
+        if ( $query['date'] instanceof DateTime ) {
336
+            $date = clone $query['date'];
337
+            $date->setTimezone( new DateTimeZone('UTC') );
338
+            $date_string = $date->format('Y-m-d H:i:s');
339
+            $comparator = $this->validate_sql_comparator($query['date_compare']);
340
+            $sql .= " AND p.post_date_gmt $comparator %s";
341
+            $sql_params[] = $date_string;
342
+        }
343
+
344
+        if ( $query['modified'] instanceof DateTime ) {
345
+            $modified = clone $query['modified'];
346
+            $modified->setTimezone( new DateTimeZone('UTC') );
347
+            $date_string = $modified->format('Y-m-d H:i:s');
348
+            $comparator = $this->validate_sql_comparator($query['modified_compare']);
349
+            $sql .= " AND p.post_modified_gmt $comparator %s";
350
+            $sql_params[] = $date_string;
351
+        }
352
+
353
+        if ( $query['claimed'] === TRUE ) {
354
+            $sql .= " AND p.post_password != ''";
355
+        } elseif ( $query['claimed'] === FALSE ) {
356
+            $sql .= " AND p.post_password = ''";
357
+        } elseif ( !is_null($query['claimed']) ) {
358
+            $sql .= " AND p.post_password = %s";
359
+            $sql_params[] = $query['claimed'];
360
+        }
361
+
362
+        if ( ! empty( $query['search'] ) ) {
363
+            $sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
364
+            for( $i = 0; $i < 3; $i++ ) {
365
+                $sql_params[] = sprintf( '%%%s%%', $query['search'] );
366
+            }
367
+        }
368
+
369
+        if ( 'select' === $select_or_count ) {
370
+            switch ( $query['orderby'] ) {
371
+                case 'hook':
372
+                    $orderby = 'p.post_title';
373
+                    break;
374
+                case 'group':
375
+                    $orderby = 't.name';
376
+                    break;
377
+                case 'status':
378
+                    $orderby = 'p.post_status';
379
+                    break;
380
+                case 'modified':
381
+                    $orderby = 'p.post_modified';
382
+                    break;
383
+                case 'claim_id':
384
+                    $orderby = 'p.post_password';
385
+                    break;
386
+                case 'schedule':
387
+                case 'date':
388
+                default:
389
+                    $orderby = 'p.post_date_gmt';
390
+                    break;
391
+            }
392
+            if ( 'ASC' === strtoupper( $query['order'] ) ) {
393
+                $order = 'ASC';
394
+            } else {
395
+                $order = 'DESC';
396
+            }
397
+            $sql .= " ORDER BY $orderby $order";
398
+            if ( $query['per_page'] > 0 ) {
399
+                $sql .= " LIMIT %d, %d";
400
+                $sql_params[] = $query['offset'];
401
+                $sql_params[] = $query['per_page'];
402
+            }
403
+        }
404
+
405
+        return $wpdb->prepare( $sql, $sql_params );
406
+    }
407
+
408
+    /**
409
+     * @param array $query
410
+     * @param string $query_type Whether to select or count the results. Default, select.
411
+     * @return string|array The IDs of actions matching the query
412
+     */
413
+    public function query_actions( $query = array(), $query_type = 'select' ) {
414
+        /** @var wpdb $wpdb */
415
+        global $wpdb;
416
+
417
+        $sql = $this->get_query_actions_sql( $query, $query_type );
418
+
419
+        return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
420
+    }
421
+
422
+    /**
423
+     * Get a count of all actions in the store, grouped by status
424
+     *
425
+     * @return array
426
+     */
427
+    public function action_counts() {
428
+
429
+        $action_counts_by_status = array();
430
+        $action_stati_and_labels = $this->get_status_labels();
431
+        $posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
432
+
433
+        foreach ( $posts_count_by_status as $post_status_name => $count ) {
434
+
435
+            try {
436
+                $action_status_name = $this->get_action_status_by_post_status( $post_status_name );
437
+            } catch ( Exception $e ) {
438
+                // Ignore any post statuses that aren't for actions
439
+                continue;
440
+            }
441
+            if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
442
+                $action_counts_by_status[ $action_status_name ] = $count;
443
+            }
444
+        }
445
+
446
+        return $action_counts_by_status;
447
+    }
448
+
449
+    /**
450
+     * @param string $action_id
451
+     *
452
+     * @throws InvalidArgumentException
453
+     */
454
+    public function cancel_action( $action_id ) {
455
+        $post = get_post( $action_id );
456
+        if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
457
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
458
+        }
459
+        do_action( 'action_scheduler_canceled_action', $action_id );
460
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
461
+        wp_trash_post( $action_id );
462
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
463
+    }
464
+
465
+    public function delete_action( $action_id ) {
466
+        $post = get_post( $action_id );
467
+        if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
468
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
469
+        }
470
+        do_action( 'action_scheduler_deleted_action', $action_id );
471
+
472
+        wp_delete_post( $action_id, TRUE );
473
+    }
474
+
475
+    /**
476
+     * @param string $action_id
477
+     *
478
+     * @throws InvalidArgumentException
479
+     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
480
+     */
481
+    public function get_date( $action_id ) {
482
+        $next = $this->get_date_gmt( $action_id );
483
+        return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
484
+    }
485
+
486
+    /**
487
+     * @param string $action_id
488
+     *
489
+     * @throws InvalidArgumentException
490
+     * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
491
+     */
492
+    public function get_date_gmt( $action_id ) {
493
+        $post = get_post( $action_id );
494
+        if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
495
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
496
+        }
497
+        if ( $post->post_status == 'publish' ) {
498
+            return as_get_datetime_object( $post->post_modified_gmt );
499
+        } else {
500
+            return as_get_datetime_object( $post->post_date_gmt );
501
+        }
502
+    }
503
+
504
+    /**
505
+     * @param int      $max_actions
506
+     * @param DateTime $before_date Jobs must be schedule before this date. Defaults to now.
507
+     * @param array    $hooks       Claim only actions with a hook or hooks.
508
+     * @param string   $group       Claim only actions in the given group.
509
+     *
510
+     * @return ActionScheduler_ActionClaim
511
+     * @throws RuntimeException When there is an error staking a claim.
512
+     * @throws InvalidArgumentException When the given group is not valid.
513
+     */
514
+    public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
515
+        $claim_id = $this->generate_claim_id();
516
+        $this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
517
+        $action_ids = $this->find_actions_by_claim_id( $claim_id );
518
+
519
+        return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
520
+    }
521
+
522
+    /**
523
+     * @return int
524
+     */
525
+    public function get_claim_count(){
526
+        global $wpdb;
527
+
528
+        $sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
529
+        $sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) );
530
+
531
+        return $wpdb->get_var( $sql );
532
+    }
533
+
534
+    protected function generate_claim_id() {
535
+        $claim_id = md5(microtime(true) . rand(0,1000));
536
+        return substr($claim_id, 0, 20); // to fit in db field with 20 char limit
537
+    }
538
+
539
+    /**
540
+     * @param string   $claim_id
541
+     * @param int      $limit
542
+     * @param DateTime $before_date Should use UTC timezone.
543
+     * @param array    $hooks       Claim only actions with a hook or hooks.
544
+     * @param string   $group       Claim only actions in the given group.
545
+     *
546
+     * @return int The number of actions that were claimed
547
+     * @throws RuntimeException When there is a database error.
548
+     * @throws InvalidArgumentException When the group is invalid.
549
+     */
550
+    protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
551
+        // Set up initial variables.
552
+        $date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
553
+        $limit_ids = ! empty( $group );
554
+        $ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
555
+
556
+        // If limiting by IDs and no posts found, then return early since we have nothing to update.
557
+        if ( $limit_ids && 0 === count( $ids ) ) {
558
+            return 0;
559
+        }
560
+
561
+        /** @var wpdb $wpdb */
562
+        global $wpdb;
563
+
564
+        /*
565 565
 		 * Build up custom query to update the affected posts. Parameters are built as a separate array
566 566
 		 * to make it easier to identify where they are in the query.
567 567
 		 *
568 568
 		 * We can't use $wpdb->update() here because of the "ID IN ..." clause.
569 569
 		 */
570
-		$update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
571
-		$params = array(
572
-			$claim_id,
573
-			current_time( 'mysql', true ),
574
-			current_time( 'mysql' ),
575
-		);
576
-
577
-		// Build initial WHERE clause.
578
-		$where    = "WHERE post_type = %s AND post_status = %s AND post_password = ''";
579
-		$params[] = self::POST_TYPE;
580
-		$params[] = ActionScheduler_Store::STATUS_PENDING;
581
-
582
-		if ( ! empty( $hooks ) ) {
583
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
584
-			$where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
585
-			$params       = array_merge( $params, array_values( $hooks ) );
586
-		}
587
-
588
-		/*
570
+        $update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
571
+        $params = array(
572
+            $claim_id,
573
+            current_time( 'mysql', true ),
574
+            current_time( 'mysql' ),
575
+        );
576
+
577
+        // Build initial WHERE clause.
578
+        $where    = "WHERE post_type = %s AND post_status = %s AND post_password = ''";
579
+        $params[] = self::POST_TYPE;
580
+        $params[] = ActionScheduler_Store::STATUS_PENDING;
581
+
582
+        if ( ! empty( $hooks ) ) {
583
+            $placeholders = array_fill( 0, count( $hooks ), '%s' );
584
+            $where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
585
+            $params       = array_merge( $params, array_values( $hooks ) );
586
+        }
587
+
588
+        /*
589 589
 		 * Add the IDs to the WHERE clause. IDs not escaped because they came directly from a prior DB query.
590 590
 		 *
591 591
 		 * If we're not limiting by IDs, then include the post_date_gmt clause.
592 592
 		 */
593
-		if ( $limit_ids ) {
594
-			$where .= ' AND ID IN (' . join( ',', $ids ) . ')';
595
-		} else {
596
-			$where .= ' AND post_date_gmt <= %s';
597
-			$params[] = $date->format( 'Y-m-d H:i:s' );
598
-		}
599
-
600
-		// Add the ORDER BY clause and,ms limit.
601
-		$order    = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d';
602
-		$params[] = $limit;
603
-
604
-		// Run the query and gather results.
605
-		$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
606
-		if ( $rows_affected === false ) {
607
-			throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
608
-		}
609
-
610
-		return (int) $rows_affected;
611
-	}
612
-
613
-	/**
614
-	 * Get IDs of actions within a certain group and up to a certain date/time.
615
-	 *
616
-	 * @param string   $group The group to use in finding actions.
617
-	 * @param int      $limit The number of actions to retrieve.
618
-	 * @param DateTime $date  DateTime object representing cutoff time for actions. Actions retrieved will be
619
-	 *                        up to and including this DateTime.
620
-	 *
621
-	 * @return array IDs of actions in the appropriate group and before the appropriate time.
622
-	 * @throws InvalidArgumentException When the group does not exist.
623
-	 */
624
-	protected function get_actions_by_group( $group, $limit, DateTime $date ) {
625
-		// Ensure the group exists before continuing.
626
-		if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
627
-			throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
628
-		}
629
-
630
-		// Set up a query for post IDs to use later.
631
-		$query      = new WP_Query();
632
-		$query_args = array(
633
-			'fields'           => 'ids',
634
-			'post_type'        => self::POST_TYPE,
635
-			'post_status'      => ActionScheduler_Store::STATUS_PENDING,
636
-			'has_password'     => false,
637
-			'posts_per_page'   => $limit * 3,
638
-			'suppress_filters' => true,
639
-			'no_found_rows'    => true,
640
-			'orderby'          => array(
641
-				'menu_order' => 'ASC',
642
-				'date'       => 'ASC',
643
-				'ID'         => 'ASC',
644
-			),
645
-			'date_query'       => array(
646
-				'column' => 'post_date_gmt',
647
-				'before' => $date->format( 'Y-m-d H:i' ),
648
-				'inclusive' => true,
649
-			),
650
-			'tax_query' => array(
651
-				array(
652
-					'taxonomy'         => self::GROUP_TAXONOMY,
653
-					'field'            => 'slug',
654
-					'terms'            => $group,
655
-					'include_children' => false,
656
-				),
657
-			),
658
-		);
659
-
660
-		return $query->query( $query_args );
661
-	}
662
-
663
-	/**
664
-	 * @param string $claim_id
665
-	 * @return array
666
-	 */
667
-	public function find_actions_by_claim_id( $claim_id ) {
668
-		/** @var wpdb $wpdb */
669
-		global $wpdb;
670
-		$sql = "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
671
-		$sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) );
672
-		$action_ids = $wpdb->get_col( $sql );
673
-		return $action_ids;
674
-	}
675
-
676
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
677
-		$action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
678
-		if ( empty( $action_ids ) ) {
679
-			return; // nothing to do
680
-		}
681
-		$action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
682
-		/** @var wpdb $wpdb */
683
-		global $wpdb;
684
-		$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s";
685
-		$sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
686
-		$result = $wpdb->query( $sql );
687
-		if ( $result === false ) {
688
-			/* translators: %s: claim ID */
689
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
690
-		}
691
-	}
692
-
693
-	/**
694
-	 * @param string $action_id
695
-	 */
696
-	public function unclaim_action( $action_id ) {
697
-		/** @var wpdb $wpdb */
698
-		global $wpdb;
699
-		$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
700
-		$sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
701
-		$result = $wpdb->query( $sql );
702
-		if ( $result === false ) {
703
-			/* translators: %s: action ID */
704
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
705
-		}
706
-	}
707
-
708
-	public function mark_failure( $action_id ) {
709
-		/** @var wpdb $wpdb */
710
-		global $wpdb;
711
-		$sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
712
-		$sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
713
-		$result = $wpdb->query( $sql );
714
-		if ( $result === false ) {
715
-			/* translators: %s: action ID */
716
-			throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
717
-		}
718
-	}
719
-
720
-	/**
721
-	 * Return an action's claim ID, as stored in the post password column
722
-	 *
723
-	 * @param string $action_id
724
-	 * @return mixed
725
-	 */
726
-	public function get_claim_id( $action_id ) {
727
-		return $this->get_post_column( $action_id, 'post_password' );
728
-	}
729
-
730
-	/**
731
-	 * Return an action's status, as stored in the post status column
732
-	 *
733
-	 * @param string $action_id
734
-	 * @return mixed
735
-	 */
736
-	public function get_status( $action_id ) {
737
-		$status = $this->get_post_column( $action_id, 'post_status' );
738
-
739
-		if ( $status === null ) {
740
-			throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
741
-		}
742
-
743
-		return $this->get_action_status_by_post_status( $status );
744
-	}
745
-
746
-	private function get_post_column( $action_id, $column_name ) {
747
-		/** @var \wpdb $wpdb */
748
-		global $wpdb;
749
-		return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) );
750
-	}
751
-
752
-	/**
753
-	 * @param string $action_id
754
-	 */
755
-	public function log_execution( $action_id ) {
756
-		/** @var wpdb $wpdb */
757
-		global $wpdb;
758
-
759
-		$sql = "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";
760
-		$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE );
761
-		$wpdb->query($sql);
762
-	}
763
-
764
-	/**
765
-	 * Record that an action was completed.
766
-	 *
767
-	 * @param int $action_id ID of the completed action.
768
-	 * @throws InvalidArgumentException|RuntimeException
769
-	 */
770
-	public function mark_complete( $action_id ) {
771
-		$post = get_post( $action_id );
772
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
773
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
774
-		}
775
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
776
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
777
-		$result = wp_update_post(array(
778
-			'ID' => $action_id,
779
-			'post_status' => 'publish',
780
-		), TRUE);
781
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
782
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
783
-		if ( is_wp_error( $result ) ) {
784
-			throw new RuntimeException( $result->get_error_message() );
785
-		}
786
-	}
787
-
788
-	/**
789
-	 * Mark action as migrated when there is an error deleting the action.
790
-	 *
791
-	 * @param int $action_id Action ID.
792
-	 */
793
-	public function mark_migrated( $action_id ) {
794
-		wp_update_post(
795
-			array(
796
-				'ID'          => $action_id,
797
-				'post_status' => 'migrated'
798
-			)
799
-		);
800
-	}
801
-
802
-	/**
803
-	 * Determine whether the post store can be migrated.
804
-	 *
805
-	 * @return bool
806
-	 */
807
-	public function migration_dependencies_met( $setting ) {
808
-		global $wpdb;
809
-
810
-		$dependencies_met = get_transient( self::DEPENDENCIES_MET );
811
-		if ( empty( $dependencies_met ) ) {
812
-			$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
813
-			$found_action        = $wpdb->get_var(
814
-				$wpdb->prepare(
815
-					"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
816
-					$maximum_args_length,
817
-					self::POST_TYPE
818
-				)
819
-			);
820
-			$dependencies_met = $found_action ? 'no' : 'yes';
821
-			set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
822
-		}
823
-
824
-		return 'yes' == $dependencies_met ? $setting : false;
825
-	}
826
-
827
-	/**
828
-	 * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
829
-	 *
830
-	 * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However,
831
-	 * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
832
-	 * developers of this impending requirement.
833
-	 *
834
-	 * @param ActionScheduler_Action $action
835
-	 */
836
-	protected function validate_action( ActionScheduler_Action $action ) {
837
-		try {
838
-			parent::validate_action( $action );
839
-		} catch ( Exception $e ) {
840
-			$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
841
-			_doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
842
-		}
843
-	}
844
-
845
-	/**
846
-	 * @codeCoverageIgnore
847
-	 */
848
-	public function init() {
849
-		add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
850
-
851
-		$post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
852
-		$post_type_registrar->register();
853
-
854
-		$post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar();
855
-		$post_status_registrar->register();
856
-
857
-		$taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
858
-		$taxonomy_registrar->register();
859
-	}
593
+        if ( $limit_ids ) {
594
+            $where .= ' AND ID IN (' . join( ',', $ids ) . ')';
595
+        } else {
596
+            $where .= ' AND post_date_gmt <= %s';
597
+            $params[] = $date->format( 'Y-m-d H:i:s' );
598
+        }
599
+
600
+        // Add the ORDER BY clause and,ms limit.
601
+        $order    = 'ORDER BY menu_order ASC, post_date_gmt ASC, ID ASC LIMIT %d';
602
+        $params[] = $limit;
603
+
604
+        // Run the query and gather results.
605
+        $rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
606
+        if ( $rows_affected === false ) {
607
+            throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
608
+        }
609
+
610
+        return (int) $rows_affected;
611
+    }
612
+
613
+    /**
614
+     * Get IDs of actions within a certain group and up to a certain date/time.
615
+     *
616
+     * @param string   $group The group to use in finding actions.
617
+     * @param int      $limit The number of actions to retrieve.
618
+     * @param DateTime $date  DateTime object representing cutoff time for actions. Actions retrieved will be
619
+     *                        up to and including this DateTime.
620
+     *
621
+     * @return array IDs of actions in the appropriate group and before the appropriate time.
622
+     * @throws InvalidArgumentException When the group does not exist.
623
+     */
624
+    protected function get_actions_by_group( $group, $limit, DateTime $date ) {
625
+        // Ensure the group exists before continuing.
626
+        if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
627
+            throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
628
+        }
629
+
630
+        // Set up a query for post IDs to use later.
631
+        $query      = new WP_Query();
632
+        $query_args = array(
633
+            'fields'           => 'ids',
634
+            'post_type'        => self::POST_TYPE,
635
+            'post_status'      => ActionScheduler_Store::STATUS_PENDING,
636
+            'has_password'     => false,
637
+            'posts_per_page'   => $limit * 3,
638
+            'suppress_filters' => true,
639
+            'no_found_rows'    => true,
640
+            'orderby'          => array(
641
+                'menu_order' => 'ASC',
642
+                'date'       => 'ASC',
643
+                'ID'         => 'ASC',
644
+            ),
645
+            'date_query'       => array(
646
+                'column' => 'post_date_gmt',
647
+                'before' => $date->format( 'Y-m-d H:i' ),
648
+                'inclusive' => true,
649
+            ),
650
+            'tax_query' => array(
651
+                array(
652
+                    'taxonomy'         => self::GROUP_TAXONOMY,
653
+                    'field'            => 'slug',
654
+                    'terms'            => $group,
655
+                    'include_children' => false,
656
+                ),
657
+            ),
658
+        );
659
+
660
+        return $query->query( $query_args );
661
+    }
662
+
663
+    /**
664
+     * @param string $claim_id
665
+     * @return array
666
+     */
667
+    public function find_actions_by_claim_id( $claim_id ) {
668
+        /** @var wpdb $wpdb */
669
+        global $wpdb;
670
+        $sql = "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
671
+        $sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) );
672
+        $action_ids = $wpdb->get_col( $sql );
673
+        return $action_ids;
674
+    }
675
+
676
+    public function release_claim( ActionScheduler_ActionClaim $claim ) {
677
+        $action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
678
+        if ( empty( $action_ids ) ) {
679
+            return; // nothing to do
680
+        }
681
+        $action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
682
+        /** @var wpdb $wpdb */
683
+        global $wpdb;
684
+        $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s";
685
+        $sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
686
+        $result = $wpdb->query( $sql );
687
+        if ( $result === false ) {
688
+            /* translators: %s: claim ID */
689
+            throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
690
+        }
691
+    }
692
+
693
+    /**
694
+     * @param string $action_id
695
+     */
696
+    public function unclaim_action( $action_id ) {
697
+        /** @var wpdb $wpdb */
698
+        global $wpdb;
699
+        $sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
700
+        $sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
701
+        $result = $wpdb->query( $sql );
702
+        if ( $result === false ) {
703
+            /* translators: %s: action ID */
704
+            throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
705
+        }
706
+    }
707
+
708
+    public function mark_failure( $action_id ) {
709
+        /** @var wpdb $wpdb */
710
+        global $wpdb;
711
+        $sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
712
+        $sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
713
+        $result = $wpdb->query( $sql );
714
+        if ( $result === false ) {
715
+            /* translators: %s: action ID */
716
+            throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
717
+        }
718
+    }
719
+
720
+    /**
721
+     * Return an action's claim ID, as stored in the post password column
722
+     *
723
+     * @param string $action_id
724
+     * @return mixed
725
+     */
726
+    public function get_claim_id( $action_id ) {
727
+        return $this->get_post_column( $action_id, 'post_password' );
728
+    }
729
+
730
+    /**
731
+     * Return an action's status, as stored in the post status column
732
+     *
733
+     * @param string $action_id
734
+     * @return mixed
735
+     */
736
+    public function get_status( $action_id ) {
737
+        $status = $this->get_post_column( $action_id, 'post_status' );
738
+
739
+        if ( $status === null ) {
740
+            throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
741
+        }
742
+
743
+        return $this->get_action_status_by_post_status( $status );
744
+    }
745
+
746
+    private function get_post_column( $action_id, $column_name ) {
747
+        /** @var \wpdb $wpdb */
748
+        global $wpdb;
749
+        return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) );
750
+    }
751
+
752
+    /**
753
+     * @param string $action_id
754
+     */
755
+    public function log_execution( $action_id ) {
756
+        /** @var wpdb $wpdb */
757
+        global $wpdb;
758
+
759
+        $sql = "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";
760
+        $sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE );
761
+        $wpdb->query($sql);
762
+    }
763
+
764
+    /**
765
+     * Record that an action was completed.
766
+     *
767
+     * @param int $action_id ID of the completed action.
768
+     * @throws InvalidArgumentException|RuntimeException
769
+     */
770
+    public function mark_complete( $action_id ) {
771
+        $post = get_post( $action_id );
772
+        if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
773
+            throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
774
+        }
775
+        add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
776
+        add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
777
+        $result = wp_update_post(array(
778
+            'ID' => $action_id,
779
+            'post_status' => 'publish',
780
+        ), TRUE);
781
+        remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
782
+        remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
783
+        if ( is_wp_error( $result ) ) {
784
+            throw new RuntimeException( $result->get_error_message() );
785
+        }
786
+    }
787
+
788
+    /**
789
+     * Mark action as migrated when there is an error deleting the action.
790
+     *
791
+     * @param int $action_id Action ID.
792
+     */
793
+    public function mark_migrated( $action_id ) {
794
+        wp_update_post(
795
+            array(
796
+                'ID'          => $action_id,
797
+                'post_status' => 'migrated'
798
+            )
799
+        );
800
+    }
801
+
802
+    /**
803
+     * Determine whether the post store can be migrated.
804
+     *
805
+     * @return bool
806
+     */
807
+    public function migration_dependencies_met( $setting ) {
808
+        global $wpdb;
809
+
810
+        $dependencies_met = get_transient( self::DEPENDENCIES_MET );
811
+        if ( empty( $dependencies_met ) ) {
812
+            $maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
813
+            $found_action        = $wpdb->get_var(
814
+                $wpdb->prepare(
815
+                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
816
+                    $maximum_args_length,
817
+                    self::POST_TYPE
818
+                )
819
+            );
820
+            $dependencies_met = $found_action ? 'no' : 'yes';
821
+            set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
822
+        }
823
+
824
+        return 'yes' == $dependencies_met ? $setting : false;
825
+    }
826
+
827
+    /**
828
+     * InnoDB indexes have a maximum size of 767 bytes by default, which is only 191 characters with utf8mb4.
829
+     *
830
+     * Previously, AS wasn't concerned about args length, as we used the (unindex) post_content column. However,
831
+     * as we prepare to move to custom tables, and can use an indexed VARCHAR column instead, we want to warn
832
+     * developers of this impending requirement.
833
+     *
834
+     * @param ActionScheduler_Action $action
835
+     */
836
+    protected function validate_action( ActionScheduler_Action $action ) {
837
+        try {
838
+            parent::validate_action( $action );
839
+        } catch ( Exception $e ) {
840
+            $message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
841
+            _doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
842
+        }
843
+    }
844
+
845
+    /**
846
+     * @codeCoverageIgnore
847
+     */
848
+    public function init() {
849
+        add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
850
+
851
+        $post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
852
+        $post_type_registrar->register();
853
+
854
+        $post_status_registrar = new ActionScheduler_wpPostStore_PostStatusRegistrar();
855
+        $post_status_registrar->register();
856
+
857
+        $taxonomy_registrar = new ActionScheduler_wpPostStore_TaxonomyRegistrar();
858
+        $taxonomy_registrar->register();
859
+    }
860 860
 }
Please login to merge, or discard this patch.
Spacing   +210 added lines, -210 removed lines patch added patch discarded remove patch
@@ -12,62 +12,62 @@  discard block
 block discarded – undo
12 12
 	/** @var DateTimeZone */
13 13
 	protected $local_timezone = NULL;
14 14
 
15
-	public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
15
+	public function save_action(ActionScheduler_Action $action, DateTime $scheduled_date = NULL) {
16 16
 		try {
17
-			$this->validate_action( $action );
18
-			$post_array = $this->create_post_array( $action, $scheduled_date );
19
-			$post_id = $this->save_post_array( $post_array );
20
-			$this->save_post_schedule( $post_id, $action->get_schedule() );
21
-			$this->save_action_group( $post_id, $action->get_group() );
22
-			do_action( 'action_scheduler_stored_action', $post_id );
17
+			$this->validate_action($action);
18
+			$post_array = $this->create_post_array($action, $scheduled_date);
19
+			$post_id = $this->save_post_array($post_array);
20
+			$this->save_post_schedule($post_id, $action->get_schedule());
21
+			$this->save_action_group($post_id, $action->get_group());
22
+			do_action('action_scheduler_stored_action', $post_id);
23 23
 			return $post_id;
24
-		} catch ( Exception $e ) {
25
-			throw new RuntimeException( sprintf( __( 'Error saving action: %s', 'action-scheduler' ), $e->getMessage() ), 0 );
24
+		} catch (Exception $e) {
25
+			throw new RuntimeException(sprintf(__('Error saving action: %s', 'action-scheduler'), $e->getMessage()), 0);
26 26
 		}
27 27
 	}
28 28
 
29
-	protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
29
+	protected function create_post_array(ActionScheduler_Action $action, DateTime $scheduled_date = NULL) {
30 30
 		$post = array(
31 31
 			'post_type' => self::POST_TYPE,
32 32
 			'post_title' => $action->get_hook(),
33 33
 			'post_content' => json_encode($action->get_args()),
34
-			'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
35
-			'post_date_gmt' => $this->get_scheduled_date_string( $action, $scheduled_date ),
36
-			'post_date'     => $this->get_scheduled_date_string_local( $action, $scheduled_date ),
34
+			'post_status' => ($action->is_finished() ? 'publish' : 'pending'),
35
+			'post_date_gmt' => $this->get_scheduled_date_string($action, $scheduled_date),
36
+			'post_date'     => $this->get_scheduled_date_string_local($action, $scheduled_date),
37 37
 		);
38 38
 		return $post;
39 39
 	}
40 40
 
41
-	protected function save_post_array( $post_array ) {
42
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
43
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
41
+	protected function save_post_array($post_array) {
42
+		add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
43
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
44 44
 
45
-		$has_kses = false !== has_filter( 'content_save_pre', 'wp_filter_post_kses' );
45
+		$has_kses = false !== has_filter('content_save_pre', 'wp_filter_post_kses');
46 46
 
47
-		if ( $has_kses ) {
47
+		if ($has_kses) {
48 48
 			// Prevent KSES from corrupting JSON in post_content.
49 49
 			kses_remove_filters();
50 50
 		}
51 51
 
52 52
 		$post_id = wp_insert_post($post_array);
53 53
 
54
-		if ( $has_kses ) {
54
+		if ($has_kses) {
55 55
 			kses_init_filters();
56 56
 		}
57 57
 
58
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
59
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
58
+		remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
59
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
60 60
 
61
-		if ( is_wp_error($post_id) || empty($post_id) ) {
62
-			throw new RuntimeException( __( 'Unable to save action.', 'action-scheduler' ) );
61
+		if (is_wp_error($post_id) || empty($post_id)) {
62
+			throw new RuntimeException(__('Unable to save action.', 'action-scheduler'));
63 63
 		}
64 64
 		return $post_id;
65 65
 	}
66 66
 
67
-	public function filter_insert_post_data( $postdata ) {
68
-		if ( $postdata['post_type'] == self::POST_TYPE ) {
67
+	public function filter_insert_post_data($postdata) {
68
+		if ($postdata['post_type'] == self::POST_TYPE) {
69 69
 			$postdata['post_author'] = 0;
70
-			if ( $postdata['post_status'] == 'future' ) {
70
+			if ($postdata['post_status'] == 'future') {
71 71
 				$postdata['post_status'] = 'publish';
72 72
 			}
73 73
 		}
@@ -102,43 +102,43 @@  discard block
 block discarded – undo
102 102
 	 * @param string $post_type     Post type.
103 103
 	 * @return string
104 104
 	 */
105
-	public function set_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) {
106
-		if ( self::POST_TYPE == $post_type ) {
107
-			$override_slug = uniqid( self::POST_TYPE . '-', true ) . '-' . wp_generate_password( 32, false );
105
+	public function set_unique_post_slug($override_slug, $slug, $post_ID, $post_status, $post_type) {
106
+		if (self::POST_TYPE == $post_type) {
107
+			$override_slug = uniqid(self::POST_TYPE . '-', true) . '-' . wp_generate_password(32, false);
108 108
 		}
109 109
 		return $override_slug;
110 110
 	}
111 111
 
112
-	protected function save_post_schedule( $post_id, $schedule ) {
113
-		update_post_meta( $post_id, self::SCHEDULE_META_KEY, $schedule );
112
+	protected function save_post_schedule($post_id, $schedule) {
113
+		update_post_meta($post_id, self::SCHEDULE_META_KEY, $schedule);
114 114
 	}
115 115
 
116
-	protected function save_action_group( $post_id, $group ) {
117
-		if ( empty($group) ) {
118
-			wp_set_object_terms( $post_id, array(), self::GROUP_TAXONOMY, FALSE );
116
+	protected function save_action_group($post_id, $group) {
117
+		if (empty($group)) {
118
+			wp_set_object_terms($post_id, array(), self::GROUP_TAXONOMY, FALSE);
119 119
 		} else {
120
-			wp_set_object_terms( $post_id, array($group), self::GROUP_TAXONOMY, FALSE );
120
+			wp_set_object_terms($post_id, array($group), self::GROUP_TAXONOMY, FALSE);
121 121
 		}
122 122
 	}
123 123
 
124
-	public function fetch_action( $action_id ) {
125
-		$post = $this->get_post( $action_id );
126
-		if ( empty($post) || $post->post_type != self::POST_TYPE ) {
124
+	public function fetch_action($action_id) {
125
+		$post = $this->get_post($action_id);
126
+		if (empty($post) || $post->post_type != self::POST_TYPE) {
127 127
 			return $this->get_null_action();
128 128
 		}
129 129
 
130 130
 		try {
131
-			$action = $this->make_action_from_post( $post );
132
-		} catch ( ActionScheduler_InvalidActionException $exception ) {
133
-			do_action( 'action_scheduler_failed_fetch_action', $post->ID, $exception );
131
+			$action = $this->make_action_from_post($post);
132
+		} catch (ActionScheduler_InvalidActionException $exception) {
133
+			do_action('action_scheduler_failed_fetch_action', $post->ID, $exception);
134 134
 			return $this->get_null_action();
135 135
 		}
136 136
 
137 137
 		return $action;
138 138
 	}
139 139
 
140
-	protected function get_post( $action_id ) {
141
-		if ( empty($action_id) ) {
140
+	protected function get_post($action_id) {
141
+		if (empty($action_id)) {
142 142
 			return NULL;
143 143
 		}
144 144
 		return get_post($action_id);
@@ -148,19 +148,19 @@  discard block
 block discarded – undo
148 148
 		return new ActionScheduler_NullAction();
149 149
 	}
150 150
 
151
-	protected function make_action_from_post( $post ) {
151
+	protected function make_action_from_post($post) {
152 152
 		$hook = $post->post_title;
153 153
 
154
-		$args = json_decode( $post->post_content, true );
155
-		$this->validate_args( $args, $post->ID );
154
+		$args = json_decode($post->post_content, true);
155
+		$this->validate_args($args, $post->ID);
156 156
 
157
-		$schedule = get_post_meta( $post->ID, self::SCHEDULE_META_KEY, true );
158
-		$this->validate_schedule( $schedule, $post->ID );
157
+		$schedule = get_post_meta($post->ID, self::SCHEDULE_META_KEY, true);
158
+		$this->validate_schedule($schedule, $post->ID);
159 159
 
160
-		$group = wp_get_object_terms( $post->ID, self::GROUP_TAXONOMY, array('fields' => 'names') );
161
-		$group = empty( $group ) ? '' : reset($group);
160
+		$group = wp_get_object_terms($post->ID, self::GROUP_TAXONOMY, array('fields' => 'names'));
161
+		$group = empty($group) ? '' : reset($group);
162 162
 
163
-		return ActionScheduler::factory()->get_stored_action( $this->get_action_status_by_post_status( $post->post_status ), $hook, $args, $schedule, $group );
163
+		return ActionScheduler::factory()->get_stored_action($this->get_action_status_by_post_status($post->post_status), $hook, $args, $schedule, $group);
164 164
 	}
165 165
 
166 166
 	/**
@@ -169,9 +169,9 @@  discard block
 block discarded – undo
169 169
 	 * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
170 170
 	 * @return string
171 171
 	 */
172
-	protected function get_action_status_by_post_status( $post_status ) {
172
+	protected function get_action_status_by_post_status($post_status) {
173 173
 
174
-		switch ( $post_status ) {
174
+		switch ($post_status) {
175 175
 			case 'publish' :
176 176
 				$action_status = self::STATUS_COMPLETE;
177 177
 				break;
@@ -179,8 +179,8 @@  discard block
 block discarded – undo
179 179
 				$action_status = self::STATUS_CANCELED;
180 180
 				break;
181 181
 			default :
182
-				if ( ! array_key_exists( $post_status, $this->get_status_labels() ) ) {
183
-					throw new InvalidArgumentException( sprintf( 'Invalid post status: "%s". No matching action status available.', $post_status ) );
182
+				if (!array_key_exists($post_status, $this->get_status_labels())) {
183
+					throw new InvalidArgumentException(sprintf('Invalid post status: "%s". No matching action status available.', $post_status));
184 184
 				}
185 185
 				$action_status = $post_status;
186 186
 				break;
@@ -194,9 +194,9 @@  discard block
 block discarded – undo
194 194
 	 * @throws InvalidArgumentException if $post_status not in known status fields returned by $this->get_status_labels()
195 195
 	 * @return string
196 196
 	 */
197
-	protected function get_post_status_by_action_status( $action_status ) {
197
+	protected function get_post_status_by_action_status($action_status) {
198 198
 
199
-		switch ( $action_status ) {
199
+		switch ($action_status) {
200 200
 			case self::STATUS_COMPLETE :
201 201
 				$post_status = 'publish';
202 202
 				break;
@@ -204,8 +204,8 @@  discard block
 block discarded – undo
204 204
 				$post_status = 'trash';
205 205
 				break;
206 206
 			default :
207
-				if ( ! array_key_exists( $action_status, $this->get_status_labels() ) ) {
208
-					throw new InvalidArgumentException( sprintf( 'Invalid action status: "%s".', $action_status ) );
207
+				if (!array_key_exists($action_status, $this->get_status_labels())) {
208
+					throw new InvalidArgumentException(sprintf('Invalid action status: "%s".', $action_status));
209 209
 				}
210 210
 				$post_status = $action_status;
211 211
 				break;
@@ -220,8 +220,8 @@  discard block
 block discarded – undo
220 220
 	 *
221 221
 	 * @return string ID of the next action matching the criteria or NULL if not found
222 222
 	 */
223
-	public function find_action( $hook, $params = array() ) {
224
-		$params = wp_parse_args( $params, array(
223
+	public function find_action($hook, $params = array()) {
224
+		$params = wp_parse_args($params, array(
225 225
 			'args' => NULL,
226 226
 			'status' => ActionScheduler_Store::STATUS_PENDING,
227 227
 			'group' => '',
@@ -230,7 +230,7 @@  discard block
 block discarded – undo
230 230
 		global $wpdb;
231 231
 		$query = "SELECT p.ID FROM {$wpdb->posts} p";
232 232
 		$args = array();
233
-		if ( !empty($params['group']) ) {
233
+		if (!empty($params['group'])) {
234 234
 			$query .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
235 235
 			$query .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
236 236
 			$query .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id AND t.slug=%s";
@@ -240,17 +240,17 @@  discard block
 block discarded – undo
240 240
 		$args[] = $hook;
241 241
 		$query .= " AND p.post_type=%s";
242 242
 		$args[] = self::POST_TYPE;
243
-		if ( !is_null($params['args']) ) {
243
+		if (!is_null($params['args'])) {
244 244
 			$query .= " AND p.post_content=%s";
245 245
 			$args[] = json_encode($params['args']);
246 246
 		}
247 247
 
248
-		if ( ! empty( $params['status'] ) ) {
248
+		if (!empty($params['status'])) {
249 249
 			$query .= " AND p.post_status=%s";
250
-			$args[] = $this->get_post_status_by_action_status( $params['status'] );
250
+			$args[] = $this->get_post_status_by_action_status($params['status']);
251 251
 		}
252 252
 
253
-		switch ( $params['status'] ) {
253
+		switch ($params['status']) {
254 254
 			case self::STATUS_COMPLETE:
255 255
 			case self::STATUS_RUNNING:
256 256
 			case self::STATUS_FAILED:
@@ -263,7 +263,7 @@  discard block
 block discarded – undo
263 263
 		}
264 264
 		$query .= " ORDER BY post_date_gmt $order LIMIT 1";
265 265
 
266
-		$query = $wpdb->prepare( $query, $args );
266
+		$query = $wpdb->prepare($query, $args);
267 267
 
268 268
 		$id = $wpdb->get_var($query);
269 269
 		return $id;
@@ -277,13 +277,13 @@  discard block
 block discarded – undo
277 277
 	 * @throws InvalidArgumentException if $select_or_count not count or select
278 278
 	 * @return string SQL statement. The returned SQL is already properly escaped.
279 279
 	 */
280
-	protected function get_query_actions_sql( array $query, $select_or_count = 'select' ) {
280
+	protected function get_query_actions_sql(array $query, $select_or_count = 'select') {
281 281
 
282
-		if ( ! in_array( $select_or_count, array( 'select', 'count' ) ) ) {
283
-			throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
282
+		if (!in_array($select_or_count, array('select', 'count'))) {
283
+			throw new InvalidArgumentException(__('Invalid schedule. Cannot save action.', 'action-scheduler'));
284 284
 		}
285 285
 
286
-		$query = wp_parse_args( $query, array(
286
+		$query = wp_parse_args($query, array(
287 287
 			'hook' => '',
288 288
 			'args' => NULL,
289 289
 			'date' => NULL,
@@ -298,18 +298,18 @@  discard block
 block discarded – undo
298 298
 			'orderby' => 'date',
299 299
 			'order' => 'ASC',
300 300
 			'search' => '',
301
-		) );
301
+		));
302 302
 
303 303
 		/** @var wpdb $wpdb */
304 304
 		global $wpdb;
305
-		$sql  = ( 'count' === $select_or_count ) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
305
+		$sql  = ('count' === $select_or_count) ? 'SELECT count(p.ID)' : 'SELECT p.ID ';
306 306
 		$sql .= "FROM {$wpdb->posts} p";
307 307
 		$sql_params = array();
308
-		if ( empty( $query['group'] ) && 'group' === $query['orderby'] ) {
308
+		if (empty($query['group']) && 'group' === $query['orderby']) {
309 309
 			$sql .= " LEFT JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
310 310
 			$sql .= " LEFT JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
311 311
 			$sql .= " LEFT JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
312
-		} elseif ( ! empty( $query['group'] ) ) {
312
+		} elseif (!empty($query['group'])) {
313 313
 			$sql .= " INNER JOIN {$wpdb->term_relationships} tr ON tr.object_id=p.ID";
314 314
 			$sql .= " INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id=tt.term_taxonomy_id";
315 315
 			$sql .= " INNER JOIN {$wpdb->terms} t ON tt.term_id=t.term_id";
@@ -318,56 +318,56 @@  discard block
 block discarded – undo
318 318
 		}
319 319
 		$sql .= " WHERE post_type=%s";
320 320
 		$sql_params[] = self::POST_TYPE;
321
-		if ( $query['hook'] ) {
321
+		if ($query['hook']) {
322 322
 			$sql .= " AND p.post_title=%s";
323 323
 			$sql_params[] = $query['hook'];
324 324
 		}
325
-		if ( !is_null($query['args']) ) {
325
+		if (!is_null($query['args'])) {
326 326
 			$sql .= " AND p.post_content=%s";
327 327
 			$sql_params[] = json_encode($query['args']);
328 328
 		}
329 329
 
330
-		if ( ! empty( $query['status'] ) ) {
330
+		if (!empty($query['status'])) {
331 331
 			$sql .= " AND p.post_status=%s";
332
-			$sql_params[] = $this->get_post_status_by_action_status( $query['status'] );
332
+			$sql_params[] = $this->get_post_status_by_action_status($query['status']);
333 333
 		}
334 334
 
335
-		if ( $query['date'] instanceof DateTime ) {
335
+		if ($query['date'] instanceof DateTime) {
336 336
 			$date = clone $query['date'];
337
-			$date->setTimezone( new DateTimeZone('UTC') );
337
+			$date->setTimezone(new DateTimeZone('UTC'));
338 338
 			$date_string = $date->format('Y-m-d H:i:s');
339 339
 			$comparator = $this->validate_sql_comparator($query['date_compare']);
340 340
 			$sql .= " AND p.post_date_gmt $comparator %s";
341 341
 			$sql_params[] = $date_string;
342 342
 		}
343 343
 
344
-		if ( $query['modified'] instanceof DateTime ) {
344
+		if ($query['modified'] instanceof DateTime) {
345 345
 			$modified = clone $query['modified'];
346
-			$modified->setTimezone( new DateTimeZone('UTC') );
346
+			$modified->setTimezone(new DateTimeZone('UTC'));
347 347
 			$date_string = $modified->format('Y-m-d H:i:s');
348 348
 			$comparator = $this->validate_sql_comparator($query['modified_compare']);
349 349
 			$sql .= " AND p.post_modified_gmt $comparator %s";
350 350
 			$sql_params[] = $date_string;
351 351
 		}
352 352
 
353
-		if ( $query['claimed'] === TRUE ) {
353
+		if ($query['claimed'] === TRUE) {
354 354
 			$sql .= " AND p.post_password != ''";
355
-		} elseif ( $query['claimed'] === FALSE ) {
355
+		} elseif ($query['claimed'] === FALSE) {
356 356
 			$sql .= " AND p.post_password = ''";
357
-		} elseif ( !is_null($query['claimed']) ) {
357
+		} elseif (!is_null($query['claimed'])) {
358 358
 			$sql .= " AND p.post_password = %s";
359 359
 			$sql_params[] = $query['claimed'];
360 360
 		}
361 361
 
362
-		if ( ! empty( $query['search'] ) ) {
362
+		if (!empty($query['search'])) {
363 363
 			$sql .= " AND (p.post_title LIKE %s OR p.post_content LIKE %s OR p.post_password LIKE %s)";
364
-			for( $i = 0; $i < 3; $i++ ) {
365
-				$sql_params[] = sprintf( '%%%s%%', $query['search'] );
364
+			for ($i = 0; $i < 3; $i++) {
365
+				$sql_params[] = sprintf('%%%s%%', $query['search']);
366 366
 			}
367 367
 		}
368 368
 
369
-		if ( 'select' === $select_or_count ) {
370
-			switch ( $query['orderby'] ) {
369
+		if ('select' === $select_or_count) {
370
+			switch ($query['orderby']) {
371 371
 				case 'hook':
372 372
 					$orderby = 'p.post_title';
373 373
 					break;
@@ -389,20 +389,20 @@  discard block
 block discarded – undo
389 389
 					$orderby = 'p.post_date_gmt';
390 390
 					break;
391 391
 			}
392
-			if ( 'ASC' === strtoupper( $query['order'] ) ) {
392
+			if ('ASC' === strtoupper($query['order'])) {
393 393
 				$order = 'ASC';
394 394
 			} else {
395 395
 				$order = 'DESC';
396 396
 			}
397 397
 			$sql .= " ORDER BY $orderby $order";
398
-			if ( $query['per_page'] > 0 ) {
398
+			if ($query['per_page'] > 0) {
399 399
 				$sql .= " LIMIT %d, %d";
400 400
 				$sql_params[] = $query['offset'];
401 401
 				$sql_params[] = $query['per_page'];
402 402
 			}
403 403
 		}
404 404
 
405
-		return $wpdb->prepare( $sql, $sql_params );
405
+		return $wpdb->prepare($sql, $sql_params);
406 406
 	}
407 407
 
408 408
 	/**
@@ -410,13 +410,13 @@  discard block
 block discarded – undo
410 410
 	 * @param string $query_type Whether to select or count the results. Default, select.
411 411
 	 * @return string|array The IDs of actions matching the query
412 412
 	 */
413
-	public function query_actions( $query = array(), $query_type = 'select' ) {
413
+	public function query_actions($query = array(), $query_type = 'select') {
414 414
 		/** @var wpdb $wpdb */
415 415
 		global $wpdb;
416 416
 
417
-		$sql = $this->get_query_actions_sql( $query, $query_type );
417
+		$sql = $this->get_query_actions_sql($query, $query_type);
418 418
 
419
-		return ( 'count' === $query_type ) ? $wpdb->get_var( $sql ) : $wpdb->get_col( $sql );
419
+		return ('count' === $query_type) ? $wpdb->get_var($sql) : $wpdb->get_col($sql);
420 420
 	}
421 421
 
422 422
 	/**
@@ -428,18 +428,18 @@  discard block
 block discarded – undo
428 428
 
429 429
 		$action_counts_by_status = array();
430 430
 		$action_stati_and_labels = $this->get_status_labels();
431
-		$posts_count_by_status   = (array) wp_count_posts( self::POST_TYPE, 'readable' );
431
+		$posts_count_by_status   = (array) wp_count_posts(self::POST_TYPE, 'readable');
432 432
 
433
-		foreach ( $posts_count_by_status as $post_status_name => $count ) {
433
+		foreach ($posts_count_by_status as $post_status_name => $count) {
434 434
 
435 435
 			try {
436
-				$action_status_name = $this->get_action_status_by_post_status( $post_status_name );
437
-			} catch ( Exception $e ) {
436
+				$action_status_name = $this->get_action_status_by_post_status($post_status_name);
437
+			} catch (Exception $e) {
438 438
 				// Ignore any post statuses that aren't for actions
439 439
 				continue;
440 440
 			}
441
-			if ( array_key_exists( $action_status_name, $action_stati_and_labels ) ) {
442
-				$action_counts_by_status[ $action_status_name ] = $count;
441
+			if (array_key_exists($action_status_name, $action_stati_and_labels)) {
442
+				$action_counts_by_status[$action_status_name] = $count;
443 443
 			}
444 444
 		}
445 445
 
@@ -451,25 +451,25 @@  discard block
 block discarded – undo
451 451
 	 *
452 452
 	 * @throws InvalidArgumentException
453 453
 	 */
454
-	public function cancel_action( $action_id ) {
455
-		$post = get_post( $action_id );
456
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
457
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
454
+	public function cancel_action($action_id) {
455
+		$post = get_post($action_id);
456
+		if (empty($post) || ($post->post_type != self::POST_TYPE)) {
457
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
458 458
 		}
459
-		do_action( 'action_scheduler_canceled_action', $action_id );
460
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
461
-		wp_trash_post( $action_id );
462
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
459
+		do_action('action_scheduler_canceled_action', $action_id);
460
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
461
+		wp_trash_post($action_id);
462
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
463 463
 	}
464 464
 
465
-	public function delete_action( $action_id ) {
466
-		$post = get_post( $action_id );
467
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
468
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
465
+	public function delete_action($action_id) {
466
+		$post = get_post($action_id);
467
+		if (empty($post) || ($post->post_type != self::POST_TYPE)) {
468
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
469 469
 		}
470
-		do_action( 'action_scheduler_deleted_action', $action_id );
470
+		do_action('action_scheduler_deleted_action', $action_id);
471 471
 
472
-		wp_delete_post( $action_id, TRUE );
472
+		wp_delete_post($action_id, TRUE);
473 473
 	}
474 474
 
475 475
 	/**
@@ -478,9 +478,9 @@  discard block
 block discarded – undo
478 478
 	 * @throws InvalidArgumentException
479 479
 	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
480 480
 	 */
481
-	public function get_date( $action_id ) {
482
-		$next = $this->get_date_gmt( $action_id );
483
-		return ActionScheduler_TimezoneHelper::set_local_timezone( $next );
481
+	public function get_date($action_id) {
482
+		$next = $this->get_date_gmt($action_id);
483
+		return ActionScheduler_TimezoneHelper::set_local_timezone($next);
484 484
 	}
485 485
 
486 486
 	/**
@@ -489,15 +489,15 @@  discard block
 block discarded – undo
489 489
 	 * @throws InvalidArgumentException
490 490
 	 * @return ActionScheduler_DateTime The date the action is schedule to run, or the date that it ran.
491 491
 	 */
492
-	public function get_date_gmt( $action_id ) {
493
-		$post = get_post( $action_id );
494
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
495
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
492
+	public function get_date_gmt($action_id) {
493
+		$post = get_post($action_id);
494
+		if (empty($post) || ($post->post_type != self::POST_TYPE)) {
495
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
496 496
 		}
497
-		if ( $post->post_status == 'publish' ) {
498
-			return as_get_datetime_object( $post->post_modified_gmt );
497
+		if ($post->post_status == 'publish') {
498
+			return as_get_datetime_object($post->post_modified_gmt);
499 499
 		} else {
500
-			return as_get_datetime_object( $post->post_date_gmt );
500
+			return as_get_datetime_object($post->post_date_gmt);
501 501
 		}
502 502
 	}
503 503
 
@@ -511,28 +511,28 @@  discard block
 block discarded – undo
511 511
 	 * @throws RuntimeException When there is an error staking a claim.
512 512
 	 * @throws InvalidArgumentException When the given group is not valid.
513 513
 	 */
514
-	public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' ) {
514
+	public function stake_claim($max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '') {
515 515
 		$claim_id = $this->generate_claim_id();
516
-		$this->claim_actions( $claim_id, $max_actions, $before_date, $hooks, $group );
517
-		$action_ids = $this->find_actions_by_claim_id( $claim_id );
516
+		$this->claim_actions($claim_id, $max_actions, $before_date, $hooks, $group);
517
+		$action_ids = $this->find_actions_by_claim_id($claim_id);
518 518
 
519
-		return new ActionScheduler_ActionClaim( $claim_id, $action_ids );
519
+		return new ActionScheduler_ActionClaim($claim_id, $action_ids);
520 520
 	}
521 521
 
522 522
 	/**
523 523
 	 * @return int
524 524
 	 */
525
-	public function get_claim_count(){
525
+	public function get_claim_count() {
526 526
 		global $wpdb;
527 527
 
528 528
 		$sql = "SELECT COUNT(DISTINCT post_password) FROM {$wpdb->posts} WHERE post_password != '' AND post_type = %s AND post_status IN ('in-progress','pending')";
529
-		$sql = $wpdb->prepare( $sql, array( self::POST_TYPE ) );
529
+		$sql = $wpdb->prepare($sql, array(self::POST_TYPE));
530 530
 
531
-		return $wpdb->get_var( $sql );
531
+		return $wpdb->get_var($sql);
532 532
 	}
533 533
 
534 534
 	protected function generate_claim_id() {
535
-		$claim_id = md5(microtime(true) . rand(0,1000));
535
+		$claim_id = md5(microtime(true) . rand(0, 1000));
536 536
 		return substr($claim_id, 0, 20); // to fit in db field with 20 char limit
537 537
 	}
538 538
 
@@ -547,14 +547,14 @@  discard block
 block discarded – undo
547 547
 	 * @throws RuntimeException When there is a database error.
548 548
 	 * @throws InvalidArgumentException When the group is invalid.
549 549
 	 */
550
-	protected function claim_actions( $claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '' ) {
550
+	protected function claim_actions($claim_id, $limit, DateTime $before_date = null, $hooks = array(), $group = '') {
551 551
 		// Set up initial variables.
552 552
 		$date      = null === $before_date ? as_get_datetime_object() : clone $before_date;
553
-		$limit_ids = ! empty( $group );
554
-		$ids       = $limit_ids ? $this->get_actions_by_group( $group, $limit, $date ) : array();
553
+		$limit_ids = !empty($group);
554
+		$ids       = $limit_ids ? $this->get_actions_by_group($group, $limit, $date) : array();
555 555
 
556 556
 		// If limiting by IDs and no posts found, then return early since we have nothing to update.
557
-		if ( $limit_ids && 0 === count( $ids ) ) {
557
+		if ($limit_ids && 0 === count($ids)) {
558 558
 			return 0;
559 559
 		}
560 560
 
@@ -570,8 +570,8 @@  discard block
 block discarded – undo
570 570
 		$update = "UPDATE {$wpdb->posts} SET post_password = %s, post_modified_gmt = %s, post_modified = %s";
571 571
 		$params = array(
572 572
 			$claim_id,
573
-			current_time( 'mysql', true ),
574
-			current_time( 'mysql' ),
573
+			current_time('mysql', true),
574
+			current_time('mysql'),
575 575
 		);
576 576
 
577 577
 		// Build initial WHERE clause.
@@ -579,10 +579,10 @@  discard block
 block discarded – undo
579 579
 		$params[] = self::POST_TYPE;
580 580
 		$params[] = ActionScheduler_Store::STATUS_PENDING;
581 581
 
582
-		if ( ! empty( $hooks ) ) {
583
-			$placeholders = array_fill( 0, count( $hooks ), '%s' );
584
-			$where       .= ' AND post_title IN (' . join( ', ', $placeholders ) . ')';
585
-			$params       = array_merge( $params, array_values( $hooks ) );
582
+		if (!empty($hooks)) {
583
+			$placeholders = array_fill(0, count($hooks), '%s');
584
+			$where       .= ' AND post_title IN (' . join(', ', $placeholders) . ')';
585
+			$params       = array_merge($params, array_values($hooks));
586 586
 		}
587 587
 
588 588
 		/*
@@ -590,11 +590,11 @@  discard block
 block discarded – undo
590 590
 		 *
591 591
 		 * If we're not limiting by IDs, then include the post_date_gmt clause.
592 592
 		 */
593
-		if ( $limit_ids ) {
594
-			$where .= ' AND ID IN (' . join( ',', $ids ) . ')';
593
+		if ($limit_ids) {
594
+			$where .= ' AND ID IN (' . join(',', $ids) . ')';
595 595
 		} else {
596 596
 			$where .= ' AND post_date_gmt <= %s';
597
-			$params[] = $date->format( 'Y-m-d H:i:s' );
597
+			$params[] = $date->format('Y-m-d H:i:s');
598 598
 		}
599 599
 
600 600
 		// Add the ORDER BY clause and,ms limit.
@@ -602,9 +602,9 @@  discard block
 block discarded – undo
602 602
 		$params[] = $limit;
603 603
 
604 604
 		// Run the query and gather results.
605
-		$rows_affected = $wpdb->query( $wpdb->prepare( "{$update} {$where} {$order}", $params ) );
606
-		if ( $rows_affected === false ) {
607
-			throw new RuntimeException( __( 'Unable to claim actions. Database error.', 'action-scheduler' ) );
605
+		$rows_affected = $wpdb->query($wpdb->prepare("{$update} {$where} {$order}", $params));
606
+		if ($rows_affected === false) {
607
+			throw new RuntimeException(__('Unable to claim actions. Database error.', 'action-scheduler'));
608 608
 		}
609 609
 
610 610
 		return (int) $rows_affected;
@@ -621,10 +621,10 @@  discard block
 block discarded – undo
621 621
 	 * @return array IDs of actions in the appropriate group and before the appropriate time.
622 622
 	 * @throws InvalidArgumentException When the group does not exist.
623 623
 	 */
624
-	protected function get_actions_by_group( $group, $limit, DateTime $date ) {
624
+	protected function get_actions_by_group($group, $limit, DateTime $date) {
625 625
 		// Ensure the group exists before continuing.
626
-		if ( ! term_exists( $group, self::GROUP_TAXONOMY )) {
627
-			throw new InvalidArgumentException( sprintf( __( 'The group "%s" does not exist.', 'action-scheduler' ), $group ) );
626
+		if (!term_exists($group, self::GROUP_TAXONOMY)) {
627
+			throw new InvalidArgumentException(sprintf(__('The group "%s" does not exist.', 'action-scheduler'), $group));
628 628
 		}
629 629
 
630 630
 		// Set up a query for post IDs to use later.
@@ -644,7 +644,7 @@  discard block
 block discarded – undo
644 644
 			),
645 645
 			'date_query'       => array(
646 646
 				'column' => 'post_date_gmt',
647
-				'before' => $date->format( 'Y-m-d H:i' ),
647
+				'before' => $date->format('Y-m-d H:i'),
648 648
 				'inclusive' => true,
649 649
 			),
650 650
 			'tax_query' => array(
@@ -657,63 +657,63 @@  discard block
 block discarded – undo
657 657
 			),
658 658
 		);
659 659
 
660
-		return $query->query( $query_args );
660
+		return $query->query($query_args);
661 661
 	}
662 662
 
663 663
 	/**
664 664
 	 * @param string $claim_id
665 665
 	 * @return array
666 666
 	 */
667
-	public function find_actions_by_claim_id( $claim_id ) {
667
+	public function find_actions_by_claim_id($claim_id) {
668 668
 		/** @var wpdb $wpdb */
669 669
 		global $wpdb;
670 670
 		$sql = "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_password = %s";
671
-		$sql = $wpdb->prepare( $sql, array( self::POST_TYPE, $claim_id ) );
672
-		$action_ids = $wpdb->get_col( $sql );
671
+		$sql = $wpdb->prepare($sql, array(self::POST_TYPE, $claim_id));
672
+		$action_ids = $wpdb->get_col($sql);
673 673
 		return $action_ids;
674 674
 	}
675 675
 
676
-	public function release_claim( ActionScheduler_ActionClaim $claim ) {
677
-		$action_ids = $this->find_actions_by_claim_id( $claim->get_id() );
678
-		if ( empty( $action_ids ) ) {
676
+	public function release_claim(ActionScheduler_ActionClaim $claim) {
677
+		$action_ids = $this->find_actions_by_claim_id($claim->get_id());
678
+		if (empty($action_ids)) {
679 679
 			return; // nothing to do
680 680
 		}
681
-		$action_id_string = implode( ',', array_map( 'intval', $action_ids ) );
681
+		$action_id_string = implode(',', array_map('intval', $action_ids));
682 682
 		/** @var wpdb $wpdb */
683 683
 		global $wpdb;
684 684
 		$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID IN ($action_id_string) AND post_password = %s";
685
-		$sql = $wpdb->prepare( $sql, array( $claim->get_id() ) );
686
-		$result = $wpdb->query( $sql );
687
-		if ( $result === false ) {
685
+		$sql = $wpdb->prepare($sql, array($claim->get_id()));
686
+		$result = $wpdb->query($sql);
687
+		if ($result === false) {
688 688
 			/* translators: %s: claim ID */
689
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim %s. Database error.', 'action-scheduler' ), $claim->get_id() ) );
689
+			throw new RuntimeException(sprintf(__('Unable to unlock claim %s. Database error.', 'action-scheduler'), $claim->get_id()));
690 690
 		}
691 691
 	}
692 692
 
693 693
 	/**
694 694
 	 * @param string $action_id
695 695
 	 */
696
-	public function unclaim_action( $action_id ) {
696
+	public function unclaim_action($action_id) {
697 697
 		/** @var wpdb $wpdb */
698 698
 		global $wpdb;
699 699
 		$sql = "UPDATE {$wpdb->posts} SET post_password = '' WHERE ID = %d AND post_type = %s";
700
-		$sql = $wpdb->prepare( $sql, $action_id, self::POST_TYPE );
701
-		$result = $wpdb->query( $sql );
702
-		if ( $result === false ) {
700
+		$sql = $wpdb->prepare($sql, $action_id, self::POST_TYPE);
701
+		$result = $wpdb->query($sql);
702
+		if ($result === false) {
703 703
 			/* translators: %s: action ID */
704
-			throw new RuntimeException( sprintf( __( 'Unable to unlock claim on action %s. Database error.', 'action-scheduler' ), $action_id ) );
704
+			throw new RuntimeException(sprintf(__('Unable to unlock claim on action %s. Database error.', 'action-scheduler'), $action_id));
705 705
 		}
706 706
 	}
707 707
 
708
-	public function mark_failure( $action_id ) {
708
+	public function mark_failure($action_id) {
709 709
 		/** @var wpdb $wpdb */
710 710
 		global $wpdb;
711 711
 		$sql = "UPDATE {$wpdb->posts} SET post_status = %s WHERE ID = %d AND post_type = %s";
712
-		$sql = $wpdb->prepare( $sql, self::STATUS_FAILED, $action_id, self::POST_TYPE );
713
-		$result = $wpdb->query( $sql );
714
-		if ( $result === false ) {
712
+		$sql = $wpdb->prepare($sql, self::STATUS_FAILED, $action_id, self::POST_TYPE);
713
+		$result = $wpdb->query($sql);
714
+		if ($result === false) {
715 715
 			/* translators: %s: action ID */
716
-			throw new RuntimeException( sprintf( __( 'Unable to mark failure on action %s. Database error.', 'action-scheduler' ), $action_id ) );
716
+			throw new RuntimeException(sprintf(__('Unable to mark failure on action %s. Database error.', 'action-scheduler'), $action_id));
717 717
 		}
718 718
 	}
719 719
 
@@ -723,8 +723,8 @@  discard block
 block discarded – undo
723 723
 	 * @param string $action_id
724 724
 	 * @return mixed
725 725
 	 */
726
-	public function get_claim_id( $action_id ) {
727
-		return $this->get_post_column( $action_id, 'post_password' );
726
+	public function get_claim_id($action_id) {
727
+		return $this->get_post_column($action_id, 'post_password');
728 728
 	}
729 729
 
730 730
 	/**
@@ -733,31 +733,31 @@  discard block
 block discarded – undo
733 733
 	 * @param string $action_id
734 734
 	 * @return mixed
735 735
 	 */
736
-	public function get_status( $action_id ) {
737
-		$status = $this->get_post_column( $action_id, 'post_status' );
736
+	public function get_status($action_id) {
737
+		$status = $this->get_post_column($action_id, 'post_status');
738 738
 
739
-		if ( $status === null ) {
740
-			throw new InvalidArgumentException( __( 'Invalid action ID. No status found.', 'action-scheduler' ) );
739
+		if ($status === null) {
740
+			throw new InvalidArgumentException(__('Invalid action ID. No status found.', 'action-scheduler'));
741 741
 		}
742 742
 
743
-		return $this->get_action_status_by_post_status( $status );
743
+		return $this->get_action_status_by_post_status($status);
744 744
 	}
745 745
 
746
-	private function get_post_column( $action_id, $column_name ) {
746
+	private function get_post_column($action_id, $column_name) {
747 747
 		/** @var \wpdb $wpdb */
748 748
 		global $wpdb;
749
-		return $wpdb->get_var( $wpdb->prepare( "SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE ) );
749
+		return $wpdb->get_var($wpdb->prepare("SELECT {$column_name} FROM {$wpdb->posts} WHERE ID=%d AND post_type=%s", $action_id, self::POST_TYPE));
750 750
 	}
751 751
 
752 752
 	/**
753 753
 	 * @param string $action_id
754 754
 	 */
755
-	public function log_execution( $action_id ) {
755
+	public function log_execution($action_id) {
756 756
 		/** @var wpdb $wpdb */
757 757
 		global $wpdb;
758 758
 
759 759
 		$sql = "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";
760
-		$sql = $wpdb->prepare( $sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE );
760
+		$sql = $wpdb->prepare($sql, self::STATUS_RUNNING, current_time('mysql', true), current_time('mysql'), $action_id, self::POST_TYPE);
761 761
 		$wpdb->query($sql);
762 762
 	}
763 763
 
@@ -767,21 +767,21 @@  discard block
 block discarded – undo
767 767
 	 * @param int $action_id ID of the completed action.
768 768
 	 * @throws InvalidArgumentException|RuntimeException
769 769
 	 */
770
-	public function mark_complete( $action_id ) {
771
-		$post = get_post( $action_id );
772
-		if ( empty( $post ) || ( $post->post_type != self::POST_TYPE ) ) {
773
-			throw new InvalidArgumentException( sprintf( __( 'Unidentified action %s', 'action-scheduler' ), $action_id ) );
770
+	public function mark_complete($action_id) {
771
+		$post = get_post($action_id);
772
+		if (empty($post) || ($post->post_type != self::POST_TYPE)) {
773
+			throw new InvalidArgumentException(sprintf(__('Unidentified action %s', 'action-scheduler'), $action_id));
774 774
 		}
775
-		add_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10, 1 );
776
-		add_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10, 5 );
775
+		add_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10, 1);
776
+		add_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10, 5);
777 777
 		$result = wp_update_post(array(
778 778
 			'ID' => $action_id,
779 779
 			'post_status' => 'publish',
780 780
 		), TRUE);
781
-		remove_filter( 'wp_insert_post_data', array( $this, 'filter_insert_post_data' ), 10 );
782
-		remove_filter( 'pre_wp_unique_post_slug', array( $this, 'set_unique_post_slug' ), 10 );
783
-		if ( is_wp_error( $result ) ) {
784
-			throw new RuntimeException( $result->get_error_message() );
781
+		remove_filter('wp_insert_post_data', array($this, 'filter_insert_post_data'), 10);
782
+		remove_filter('pre_wp_unique_post_slug', array($this, 'set_unique_post_slug'), 10);
783
+		if (is_wp_error($result)) {
784
+			throw new RuntimeException($result->get_error_message());
785 785
 		}
786 786
 	}
787 787
 
@@ -790,7 +790,7 @@  discard block
 block discarded – undo
790 790
 	 *
791 791
 	 * @param int $action_id Action ID.
792 792
 	 */
793
-	public function mark_migrated( $action_id ) {
793
+	public function mark_migrated($action_id) {
794 794
 		wp_update_post(
795 795
 			array(
796 796
 				'ID'          => $action_id,
@@ -804,12 +804,12 @@  discard block
 block discarded – undo
804 804
 	 *
805 805
 	 * @return bool
806 806
 	 */
807
-	public function migration_dependencies_met( $setting ) {
807
+	public function migration_dependencies_met($setting) {
808 808
 		global $wpdb;
809 809
 
810
-		$dependencies_met = get_transient( self::DEPENDENCIES_MET );
811
-		if ( empty( $dependencies_met ) ) {
812
-			$maximum_args_length = apply_filters( 'action_scheduler_maximum_args_length', 191 );
810
+		$dependencies_met = get_transient(self::DEPENDENCIES_MET);
811
+		if (empty($dependencies_met)) {
812
+			$maximum_args_length = apply_filters('action_scheduler_maximum_args_length', 191);
813 813
 			$found_action        = $wpdb->get_var(
814 814
 				$wpdb->prepare(
815 815
 					"SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND CHAR_LENGTH(post_content) > %d LIMIT 1",
@@ -818,7 +818,7 @@  discard block
 block discarded – undo
818 818
 				)
819 819
 			);
820 820
 			$dependencies_met = $found_action ? 'no' : 'yes';
821
-			set_transient( self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS );
821
+			set_transient(self::DEPENDENCIES_MET, $dependencies_met, DAY_IN_SECONDS);
822 822
 		}
823 823
 
824 824
 		return 'yes' == $dependencies_met ? $setting : false;
@@ -833,12 +833,12 @@  discard block
 block discarded – undo
833 833
 	 *
834 834
 	 * @param ActionScheduler_Action $action
835 835
 	 */
836
-	protected function validate_action( ActionScheduler_Action $action ) {
836
+	protected function validate_action(ActionScheduler_Action $action) {
837 837
 		try {
838
-			parent::validate_action( $action );
839
-		} catch ( Exception $e ) {
840
-			$message = sprintf( __( '%s Support for strings longer than this will be removed in a future version.', 'action-scheduler' ), $e->getMessage() );
841
-			_doing_it_wrong( 'ActionScheduler_Action::$args', $message, '2.1.0' );
838
+			parent::validate_action($action);
839
+		} catch (Exception $e) {
840
+			$message = sprintf(__('%s Support for strings longer than this will be removed in a future version.', 'action-scheduler'), $e->getMessage());
841
+			_doing_it_wrong('ActionScheduler_Action::$args', $message, '2.1.0');
842 842
 		}
843 843
 	}
844 844
 
@@ -846,7 +846,7 @@  discard block
 block discarded – undo
846 846
 	 * @codeCoverageIgnore
847 847
 	 */
848 848
 	public function init() {
849
-		add_filter( 'action_scheduler_migration_dependencies_met', array( $this, 'migration_dependencies_met' ) );
849
+		add_filter('action_scheduler_migration_dependencies_met', array($this, 'migration_dependencies_met'));
850 850
 
851 851
 		$post_type_registrar = new ActionScheduler_wpPostStore_PostTypeRegistrar();
852 852
 		$post_type_registrar->register();
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/schema/ActionScheduler_LoggerSchema.php 2 patches
Indentation   +21 added lines, -21 removed lines patch added patch discarded remove patch
@@ -8,28 +8,28 @@  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 = 2;
13
+    /**
14
+     * @var int Increment this value to trigger a schema update.
15
+     */
16
+    protected $schema_version = 2;
17 17
 
18
-	public function __construct() {
19
-		$this->tables = [
20
-			self::LOG_TABLE,
21
-		];
22
-	}
18
+    public function __construct() {
19
+        $this->tables = [
20
+            self::LOG_TABLE,
21
+        ];
22
+    }
23 23
 
24
-	protected function get_table_definition( $table ) {
25
-		global $wpdb;
26
-		$table_name       = $wpdb->$table;
27
-		$charset_collate  = $wpdb->get_charset_collate();
28
-		switch ( $table ) {
24
+    protected function get_table_definition( $table ) {
25
+        global $wpdb;
26
+        $table_name       = $wpdb->$table;
27
+        $charset_collate  = $wpdb->get_charset_collate();
28
+        switch ( $table ) {
29 29
 
30
-			case self::LOG_TABLE:
30
+            case self::LOG_TABLE:
31 31
 
32
-				return "CREATE TABLE {$table_name} (
32
+                return "CREATE TABLE {$table_name} (
33 33
 				        log_id bigint(20) unsigned NOT NULL auto_increment,
34 34
 				        action_id bigint(20) unsigned NOT NULL,
35 35
 				        message text NOT NULL,
@@ -40,8 +40,8 @@  discard block
 block discarded – undo
40 40
 				        KEY log_date_gmt (log_date_gmt)
41 41
 				        ) $charset_collate";
42 42
 
43
-			default:
44
-				return '';
45
-		}
46
-	}
43
+            default:
44
+                return '';
45
+        }
46
+    }
47 47
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -21,11 +21,11 @@
 block discarded – undo
21 21
 		];
22 22
 	}
23 23
 
24
-	protected function get_table_definition( $table ) {
24
+	protected function get_table_definition($table) {
25 25
 		global $wpdb;
26 26
 		$table_name       = $wpdb->$table;
27 27
 		$charset_collate  = $wpdb->get_charset_collate();
28
-		switch ( $table ) {
28
+		switch ($table) {
29 29
 
30 30
 			case self::LOG_TABLE:
31 31
 
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/schema/ActionScheduler_StoreSchema.php 2 patches
Indentation   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -8,33 +8,33 @@  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';
11
+    const ACTIONS_TABLE = 'actionscheduler_actions';
12
+    const CLAIMS_TABLE  = 'actionscheduler_claims';
13
+    const GROUPS_TABLE  = 'actionscheduler_groups';
14 14
 
15
-	/**
16
-	 * @var int Increment this value to trigger a schema update.
17
-	 */
18
-	protected $schema_version = 3;
15
+    /**
16
+     * @var int Increment this value to trigger a schema update.
17
+     */
18
+    protected $schema_version = 3;
19 19
 
20
-	public function __construct() {
21
-		$this->tables = [
22
-			self::ACTIONS_TABLE,
23
-			self::CLAIMS_TABLE,
24
-			self::GROUPS_TABLE,
25
-		];
26
-	}
20
+    public function __construct() {
21
+        $this->tables = [
22
+            self::ACTIONS_TABLE,
23
+            self::CLAIMS_TABLE,
24
+            self::GROUPS_TABLE,
25
+        ];
26
+    }
27 27
 
28
-	protected function get_table_definition( $table ) {
29
-		global $wpdb;
30
-		$table_name       = $wpdb->$table;
31
-		$charset_collate  = $wpdb->get_charset_collate();
32
-		$max_index_length = 191; // @see wp_get_db_schema()
33
-		switch ( $table ) {
28
+    protected function get_table_definition( $table ) {
29
+        global $wpdb;
30
+        $table_name       = $wpdb->$table;
31
+        $charset_collate  = $wpdb->get_charset_collate();
32
+        $max_index_length = 191; // @see wp_get_db_schema()
33
+        switch ( $table ) {
34 34
 
35
-			case self::ACTIONS_TABLE:
35
+            case self::ACTIONS_TABLE:
36 36
 
37
-				return "CREATE TABLE {$table_name} (
37
+                return "CREATE TABLE {$table_name} (
38 38
 				        action_id bigint(20) unsigned NOT NULL auto_increment,
39 39
 				        hook varchar(191) NOT NULL,
40 40
 				        status varchar(20) NOT NULL,
@@ -58,26 +58,26 @@  discard block
 block discarded – undo
58 58
 				        KEY claim_id (claim_id)
59 59
 				        ) $charset_collate";
60 60
 
61
-			case self::CLAIMS_TABLE:
61
+            case self::CLAIMS_TABLE:
62 62
 
63
-				return "CREATE TABLE {$table_name} (
63
+                return "CREATE TABLE {$table_name} (
64 64
 				        claim_id bigint(20) unsigned NOT NULL auto_increment,
65 65
 				        date_created_gmt datetime NOT NULL default '0000-00-00 00:00:00',
66 66
 				        PRIMARY KEY  (claim_id),
67 67
 				        KEY date_created_gmt (date_created_gmt)
68 68
 				        ) $charset_collate";
69 69
 
70
-			case self::GROUPS_TABLE:
70
+            case self::GROUPS_TABLE:
71 71
 
72
-				return "CREATE TABLE {$table_name} (
72
+                return "CREATE TABLE {$table_name} (
73 73
 				        group_id bigint(20) unsigned NOT NULL auto_increment,
74 74
 				        slug varchar(255) NOT NULL,
75 75
 				        PRIMARY KEY  (group_id),
76 76
 				        KEY slug (slug($max_index_length))
77 77
 				        ) $charset_collate";
78 78
 
79
-			default:
80
-				return '';
81
-		}
82
-	}
79
+            default:
80
+                return '';
81
+        }
82
+    }
83 83
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -25,12 +25,12 @@
 block discarded – undo
25 25
 		];
26 26
 	}
27 27
 
28
-	protected function get_table_definition( $table ) {
28
+	protected function get_table_definition($table) {
29 29
 		global $wpdb;
30 30
 		$table_name       = $wpdb->$table;
31 31
 		$charset_collate  = $wpdb->get_charset_collate();
32 32
 		$max_index_length = 191; // @see wp_get_db_schema()
33
-		switch ( $table ) {
33
+		switch ($table) {
34 34
 
35 35
 			case self::ACTIONS_TABLE:
36 36
 
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/ActionScheduler_NullLogEntry.php 2 patches
Indentation   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -4,8 +4,8 @@
 block discarded – undo
4 4
  * Class ActionScheduler_NullLogEntry
5 5
  */
6 6
 class ActionScheduler_NullLogEntry extends ActionScheduler_LogEntry {
7
-	public function __construct( $action_id = '', $message = '' ) {
8
-		// nothing to see here
9
-	}
7
+    public function __construct( $action_id = '', $message = '' ) {
8
+        // nothing to see here
9
+    }
10 10
 }
11
- 
12 11
\ No newline at end of file
12
+    
13 13
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -4,7 +4,7 @@
 block discarded – undo
4 4
  * Class ActionScheduler_NullLogEntry
5 5
  */
6 6
 class ActionScheduler_NullLogEntry extends ActionScheduler_LogEntry {
7
-	public function __construct( $action_id = '', $message = '' ) {
7
+	public function __construct($action_id = '', $message = '') {
8 8
 		// nothing to see here
9 9
 	}
10 10
 }
Please login to merge, or discard this patch.
libraries/action-scheduler/classes/ActionScheduler_QueueCleaner.php 2 patches
Indentation   +147 added lines, -147 removed lines patch added patch discarded remove patch
@@ -5,151 +5,151 @@
 block discarded – undo
5 5
  */
6 6
 class ActionScheduler_QueueCleaner {
7 7
 
8
-	/** @var int */
9
-	protected $batch_size;
10
-
11
-	/** @var ActionScheduler_Store */
12
-	private $store = null;
13
-
14
-	/**
15
-	 * 31 days in seconds.
16
-	 *
17
-	 * @var int
18
-	 */
19
-	private $month_in_seconds = 2678400;
20
-
21
-	/**
22
-	 * ActionScheduler_QueueCleaner constructor.
23
-	 *
24
-	 * @param ActionScheduler_Store $store      The store instance.
25
-	 * @param int                   $batch_size The batch size.
26
-	 */
27
-	public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
28
-		$this->store = $store ? $store : ActionScheduler_Store::instance();
29
-		$this->batch_size = $batch_size;
30
-	}
31
-
32
-	public function delete_old_actions() {
33
-		$lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
34
-		$cutoff = as_get_datetime_object($lifespan.' seconds ago');
35
-
36
-		$statuses_to_purge = array(
37
-			ActionScheduler_Store::STATUS_COMPLETE,
38
-			ActionScheduler_Store::STATUS_CANCELED,
39
-		);
40
-
41
-		foreach ( $statuses_to_purge as $status ) {
42
-			$actions_to_delete = $this->store->query_actions( array(
43
-				'status'           => $status,
44
-				'modified'         => $cutoff,
45
-				'modified_compare' => '<=',
46
-				'per_page'         => $this->get_batch_size(),
47
-			) );
48
-
49
-			foreach ( $actions_to_delete as $action_id ) {
50
-				try {
51
-					$this->store->delete_action( $action_id );
52
-				} catch ( Exception $e ) {
53
-
54
-					/**
55
-					 * Notify 3rd party code of exceptions when deleting a completed action older than the retention period
56
-					 *
57
-					 * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their
58
-					 * actions.
59
-					 *
60
-					 * @since 2.0.0
61
-					 *
62
-					 * @param int $action_id The scheduled actions ID in the data store
63
-					 * @param Exception $e The exception thrown when attempting to delete the action from the data store
64
-					 * @param int $lifespan The retention period, in seconds, for old actions
65
-					 * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch
66
-					 */
67
-					do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );
68
-				}
69
-			}
70
-		}
71
-	}
72
-
73
-	/**
74
-	 * Unclaim pending actions that have not been run within a given time limit.
75
-	 *
76
-	 * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
77
-	 * as a parameter is 10x the time limit used for queue processing.
78
-	 *
79
-	 * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes).
80
-	 */
81
-	public function reset_timeouts( $time_limit = 300 ) {
82
-		$timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit );
83
-		if ( $timeout < 0 ) {
84
-			return;
85
-		}
86
-		$cutoff = as_get_datetime_object($timeout.' seconds ago');
87
-		$actions_to_reset = $this->store->query_actions( array(
88
-			'status'           => ActionScheduler_Store::STATUS_PENDING,
89
-			'modified'         => $cutoff,
90
-			'modified_compare' => '<=',
91
-			'claimed'          => true,
92
-			'per_page'         => $this->get_batch_size(),
93
-		) );
94
-
95
-		foreach ( $actions_to_reset as $action_id ) {
96
-			$this->store->unclaim_action( $action_id );
97
-			do_action( 'action_scheduler_reset_action', $action_id );
98
-		}
99
-	}
100
-
101
-	/**
102
-	 * Mark actions that have been running for more than a given time limit as failed, based on
103
-	 * the assumption some uncatachable and unloggable fatal error occurred during processing.
104
-	 *
105
-	 * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
106
-	 * as a parameter is 10x the time limit used for queue processing.
107
-	 *
108
-	 * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes).
109
-	 */
110
-	public function mark_failures( $time_limit = 300 ) {
111
-		$timeout = apply_filters( 'action_scheduler_failure_period', $time_limit );
112
-		if ( $timeout < 0 ) {
113
-			return;
114
-		}
115
-		$cutoff = as_get_datetime_object($timeout.' seconds ago');
116
-		$actions_to_reset = $this->store->query_actions( array(
117
-			'status'           => ActionScheduler_Store::STATUS_RUNNING,
118
-			'modified'         => $cutoff,
119
-			'modified_compare' => '<=',
120
-			'per_page'         => $this->get_batch_size(),
121
-		) );
122
-
123
-		foreach ( $actions_to_reset as $action_id ) {
124
-			$this->store->mark_failure( $action_id );
125
-			do_action( 'action_scheduler_failed_action', $action_id, $timeout );
126
-		}
127
-	}
128
-
129
-	/**
130
-	 * Do all of the cleaning actions.
131
-	 *
132
-	 * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes).
133
-	 * @author Jeremy Pry
134
-	 */
135
-	public function clean( $time_limit = 300 ) {
136
-		$this->delete_old_actions();
137
-		$this->reset_timeouts( $time_limit );
138
-		$this->mark_failures( $time_limit );
139
-	}
140
-
141
-	/**
142
-	 * Get the batch size for cleaning the queue.
143
-	 *
144
-	 * @author Jeremy Pry
145
-	 * @return int
146
-	 */
147
-	protected function get_batch_size() {
148
-		/**
149
-		 * Filter the batch size when cleaning the queue.
150
-		 *
151
-		 * @param int $batch_size The number of actions to clean in one batch.
152
-		 */
153
-		return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) );
154
-	}
8
+    /** @var int */
9
+    protected $batch_size;
10
+
11
+    /** @var ActionScheduler_Store */
12
+    private $store = null;
13
+
14
+    /**
15
+     * 31 days in seconds.
16
+     *
17
+     * @var int
18
+     */
19
+    private $month_in_seconds = 2678400;
20
+
21
+    /**
22
+     * ActionScheduler_QueueCleaner constructor.
23
+     *
24
+     * @param ActionScheduler_Store $store      The store instance.
25
+     * @param int                   $batch_size The batch size.
26
+     */
27
+    public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
28
+        $this->store = $store ? $store : ActionScheduler_Store::instance();
29
+        $this->batch_size = $batch_size;
30
+    }
31
+
32
+    public function delete_old_actions() {
33
+        $lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
34
+        $cutoff = as_get_datetime_object($lifespan.' seconds ago');
35
+
36
+        $statuses_to_purge = array(
37
+            ActionScheduler_Store::STATUS_COMPLETE,
38
+            ActionScheduler_Store::STATUS_CANCELED,
39
+        );
40
+
41
+        foreach ( $statuses_to_purge as $status ) {
42
+            $actions_to_delete = $this->store->query_actions( array(
43
+                'status'           => $status,
44
+                'modified'         => $cutoff,
45
+                'modified_compare' => '<=',
46
+                'per_page'         => $this->get_batch_size(),
47
+            ) );
48
+
49
+            foreach ( $actions_to_delete as $action_id ) {
50
+                try {
51
+                    $this->store->delete_action( $action_id );
52
+                } catch ( Exception $e ) {
53
+
54
+                    /**
55
+                     * Notify 3rd party code of exceptions when deleting a completed action older than the retention period
56
+                     *
57
+                     * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their
58
+                     * actions.
59
+                     *
60
+                     * @since 2.0.0
61
+                     *
62
+                     * @param int $action_id The scheduled actions ID in the data store
63
+                     * @param Exception $e The exception thrown when attempting to delete the action from the data store
64
+                     * @param int $lifespan The retention period, in seconds, for old actions
65
+                     * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch
66
+                     */
67
+                    do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );
68
+                }
69
+            }
70
+        }
71
+    }
72
+
73
+    /**
74
+     * Unclaim pending actions that have not been run within a given time limit.
75
+     *
76
+     * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
77
+     * as a parameter is 10x the time limit used for queue processing.
78
+     *
79
+     * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes).
80
+     */
81
+    public function reset_timeouts( $time_limit = 300 ) {
82
+        $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit );
83
+        if ( $timeout < 0 ) {
84
+            return;
85
+        }
86
+        $cutoff = as_get_datetime_object($timeout.' seconds ago');
87
+        $actions_to_reset = $this->store->query_actions( array(
88
+            'status'           => ActionScheduler_Store::STATUS_PENDING,
89
+            'modified'         => $cutoff,
90
+            'modified_compare' => '<=',
91
+            'claimed'          => true,
92
+            'per_page'         => $this->get_batch_size(),
93
+        ) );
94
+
95
+        foreach ( $actions_to_reset as $action_id ) {
96
+            $this->store->unclaim_action( $action_id );
97
+            do_action( 'action_scheduler_reset_action', $action_id );
98
+        }
99
+    }
100
+
101
+    /**
102
+     * Mark actions that have been running for more than a given time limit as failed, based on
103
+     * the assumption some uncatachable and unloggable fatal error occurred during processing.
104
+     *
105
+     * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
106
+     * as a parameter is 10x the time limit used for queue processing.
107
+     *
108
+     * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes).
109
+     */
110
+    public function mark_failures( $time_limit = 300 ) {
111
+        $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit );
112
+        if ( $timeout < 0 ) {
113
+            return;
114
+        }
115
+        $cutoff = as_get_datetime_object($timeout.' seconds ago');
116
+        $actions_to_reset = $this->store->query_actions( array(
117
+            'status'           => ActionScheduler_Store::STATUS_RUNNING,
118
+            'modified'         => $cutoff,
119
+            'modified_compare' => '<=',
120
+            'per_page'         => $this->get_batch_size(),
121
+        ) );
122
+
123
+        foreach ( $actions_to_reset as $action_id ) {
124
+            $this->store->mark_failure( $action_id );
125
+            do_action( 'action_scheduler_failed_action', $action_id, $timeout );
126
+        }
127
+    }
128
+
129
+    /**
130
+     * Do all of the cleaning actions.
131
+     *
132
+     * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes).
133
+     * @author Jeremy Pry
134
+     */
135
+    public function clean( $time_limit = 300 ) {
136
+        $this->delete_old_actions();
137
+        $this->reset_timeouts( $time_limit );
138
+        $this->mark_failures( $time_limit );
139
+    }
140
+
141
+    /**
142
+     * Get the batch size for cleaning the queue.
143
+     *
144
+     * @author Jeremy Pry
145
+     * @return int
146
+     */
147
+    protected function get_batch_size() {
148
+        /**
149
+         * Filter the batch size when cleaning the queue.
150
+         *
151
+         * @param int $batch_size The number of actions to clean in one batch.
152
+         */
153
+        return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) );
154
+    }
155 155
 }
Please login to merge, or discard this patch.
Spacing   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -24,32 +24,32 @@  discard block
 block discarded – undo
24 24
 	 * @param ActionScheduler_Store $store      The store instance.
25 25
 	 * @param int                   $batch_size The batch size.
26 26
 	 */
27
-	public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
27
+	public function __construct(ActionScheduler_Store $store = null, $batch_size = 20) {
28 28
 		$this->store = $store ? $store : ActionScheduler_Store::instance();
29 29
 		$this->batch_size = $batch_size;
30 30
 	}
31 31
 
32 32
 	public function delete_old_actions() {
33
-		$lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
34
-		$cutoff = as_get_datetime_object($lifespan.' seconds ago');
33
+		$lifespan = apply_filters('action_scheduler_retention_period', $this->month_in_seconds);
34
+		$cutoff = as_get_datetime_object($lifespan . ' seconds ago');
35 35
 
36 36
 		$statuses_to_purge = array(
37 37
 			ActionScheduler_Store::STATUS_COMPLETE,
38 38
 			ActionScheduler_Store::STATUS_CANCELED,
39 39
 		);
40 40
 
41
-		foreach ( $statuses_to_purge as $status ) {
42
-			$actions_to_delete = $this->store->query_actions( array(
41
+		foreach ($statuses_to_purge as $status) {
42
+			$actions_to_delete = $this->store->query_actions(array(
43 43
 				'status'           => $status,
44 44
 				'modified'         => $cutoff,
45 45
 				'modified_compare' => '<=',
46 46
 				'per_page'         => $this->get_batch_size(),
47
-			) );
47
+			));
48 48
 
49
-			foreach ( $actions_to_delete as $action_id ) {
49
+			foreach ($actions_to_delete as $action_id) {
50 50
 				try {
51
-					$this->store->delete_action( $action_id );
52
-				} catch ( Exception $e ) {
51
+					$this->store->delete_action($action_id);
52
+				} catch (Exception $e) {
53 53
 
54 54
 					/**
55 55
 					 * Notify 3rd party code of exceptions when deleting a completed action older than the retention period
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
 					 * @param int $lifespan The retention period, in seconds, for old actions
65 65
 					 * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch
66 66
 					 */
67
-					do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );
67
+					do_action('action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count($actions_to_delete));
68 68
 				}
69 69
 			}
70 70
 		}
@@ -78,23 +78,23 @@  discard block
 block discarded – undo
78 78
 	 *
79 79
 	 * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes).
80 80
 	 */
81
-	public function reset_timeouts( $time_limit = 300 ) {
82
-		$timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit );
83
-		if ( $timeout < 0 ) {
81
+	public function reset_timeouts($time_limit = 300) {
82
+		$timeout = apply_filters('action_scheduler_timeout_period', $time_limit);
83
+		if ($timeout < 0) {
84 84
 			return;
85 85
 		}
86
-		$cutoff = as_get_datetime_object($timeout.' seconds ago');
87
-		$actions_to_reset = $this->store->query_actions( array(
86
+		$cutoff = as_get_datetime_object($timeout . ' seconds ago');
87
+		$actions_to_reset = $this->store->query_actions(array(
88 88
 			'status'           => ActionScheduler_Store::STATUS_PENDING,
89 89
 			'modified'         => $cutoff,
90 90
 			'modified_compare' => '<=',
91 91
 			'claimed'          => true,
92 92
 			'per_page'         => $this->get_batch_size(),
93
-		) );
93
+		));
94 94
 
95
-		foreach ( $actions_to_reset as $action_id ) {
96
-			$this->store->unclaim_action( $action_id );
97
-			do_action( 'action_scheduler_reset_action', $action_id );
95
+		foreach ($actions_to_reset as $action_id) {
96
+			$this->store->unclaim_action($action_id);
97
+			do_action('action_scheduler_reset_action', $action_id);
98 98
 		}
99 99
 	}
100 100
 
@@ -107,22 +107,22 @@  discard block
 block discarded – undo
107 107
 	 *
108 108
 	 * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes).
109 109
 	 */
110
-	public function mark_failures( $time_limit = 300 ) {
111
-		$timeout = apply_filters( 'action_scheduler_failure_period', $time_limit );
112
-		if ( $timeout < 0 ) {
110
+	public function mark_failures($time_limit = 300) {
111
+		$timeout = apply_filters('action_scheduler_failure_period', $time_limit);
112
+		if ($timeout < 0) {
113 113
 			return;
114 114
 		}
115
-		$cutoff = as_get_datetime_object($timeout.' seconds ago');
116
-		$actions_to_reset = $this->store->query_actions( array(
115
+		$cutoff = as_get_datetime_object($timeout . ' seconds ago');
116
+		$actions_to_reset = $this->store->query_actions(array(
117 117
 			'status'           => ActionScheduler_Store::STATUS_RUNNING,
118 118
 			'modified'         => $cutoff,
119 119
 			'modified_compare' => '<=',
120 120
 			'per_page'         => $this->get_batch_size(),
121
-		) );
121
+		));
122 122
 
123
-		foreach ( $actions_to_reset as $action_id ) {
124
-			$this->store->mark_failure( $action_id );
125
-			do_action( 'action_scheduler_failed_action', $action_id, $timeout );
123
+		foreach ($actions_to_reset as $action_id) {
124
+			$this->store->mark_failure($action_id);
125
+			do_action('action_scheduler_failed_action', $action_id, $timeout);
126 126
 		}
127 127
 	}
128 128
 
@@ -132,10 +132,10 @@  discard block
 block discarded – undo
132 132
 	 * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes).
133 133
 	 * @author Jeremy Pry
134 134
 	 */
135
-	public function clean( $time_limit = 300 ) {
135
+	public function clean($time_limit = 300) {
136 136
 		$this->delete_old_actions();
137
-		$this->reset_timeouts( $time_limit );
138
-		$this->mark_failures( $time_limit );
137
+		$this->reset_timeouts($time_limit);
138
+		$this->mark_failures($time_limit);
139 139
 	}
140 140
 
141 141
 	/**
@@ -150,6 +150,6 @@  discard block
 block discarded – undo
150 150
 		 *
151 151
 		 * @param int $batch_size The number of actions to clean in one batch.
152 152
 		 */
153
-		return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) );
153
+		return absint(apply_filters('action_scheduler_cleanup_batch_size', $this->batch_size));
154 154
 	}
155 155
 }
Please login to merge, or discard this patch.
includes/libraries/action-scheduler/classes/ActionScheduler_OptionLock.php 2 patches
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -9,41 +9,41 @@
 block discarded – undo
9 9
  */
10 10
 class ActionScheduler_OptionLock extends ActionScheduler_Lock {
11 11
 
12
-	/**
13
-	 * Set a lock using options for a given amount of time (60 seconds by default).
14
-	 *
15
-	 * Using an autoloaded option avoids running database queries or other resource intensive tasks
16
-	 * on frequently triggered hooks, like 'init' or 'shutdown'.
17
-	 *
18
-	 * For example, ActionScheduler_QueueRunner->maybe_dispatch_async_request() uses a lock to avoid
19
-	 * calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown',
20
-	 * hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count()
21
-	 * to find the current number of claims in the database.
22
-	 *
23
-	 * @param string $lock_type A string to identify different lock types.
24
-	 * @bool True if lock value has changed, false if not or if set failed.
25
-	 */
26
-	public function set( $lock_type ) {
27
-		return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
28
-	}
12
+    /**
13
+     * Set a lock using options for a given amount of time (60 seconds by default).
14
+     *
15
+     * Using an autoloaded option avoids running database queries or other resource intensive tasks
16
+     * on frequently triggered hooks, like 'init' or 'shutdown'.
17
+     *
18
+     * For example, ActionScheduler_QueueRunner->maybe_dispatch_async_request() uses a lock to avoid
19
+     * calling ActionScheduler_QueueRunner->has_maximum_concurrent_batches() every time the 'shutdown',
20
+     * hook is triggered, because that method calls ActionScheduler_QueueRunner->store->get_claim_count()
21
+     * to find the current number of claims in the database.
22
+     *
23
+     * @param string $lock_type A string to identify different lock types.
24
+     * @bool True if lock value has changed, false if not or if set failed.
25
+     */
26
+    public function set( $lock_type ) {
27
+        return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
28
+    }
29 29
 
30
-	/**
31
-	 * If a lock is set, return the timestamp it was set to expiry.
32
-	 *
33
-	 * @param string $lock_type A string to identify different lock types.
34
-	 * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
35
-	 */
36
-	public function get_expiration( $lock_type ) {
37
-		return get_option( $this->get_key( $lock_type ) );
38
-	}
30
+    /**
31
+     * If a lock is set, return the timestamp it was set to expiry.
32
+     *
33
+     * @param string $lock_type A string to identify different lock types.
34
+     * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
35
+     */
36
+    public function get_expiration( $lock_type ) {
37
+        return get_option( $this->get_key( $lock_type ) );
38
+    }
39 39
 
40
-	/**
41
-	 * Get the key to use for storing the lock in the transient
42
-	 *
43
-	 * @param string $lock_type A string to identify different lock types.
44
-	 * @return string
45
-	 */
46
-	protected function get_key( $lock_type ) {
47
-		return sprintf( 'action_scheduler_lock_%s', $lock_type );
48
-	}
40
+    /**
41
+     * Get the key to use for storing the lock in the transient
42
+     *
43
+     * @param string $lock_type A string to identify different lock types.
44
+     * @return string
45
+     */
46
+    protected function get_key( $lock_type ) {
47
+        return sprintf( 'action_scheduler_lock_%s', $lock_type );
48
+    }
49 49
 }
Please login to merge, or discard this patch.
Spacing   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -23,8 +23,8 @@  discard block
 block discarded – undo
23 23
 	 * @param string $lock_type A string to identify different lock types.
24 24
 	 * @bool True if lock value has changed, false if not or if set failed.
25 25
 	 */
26
-	public function set( $lock_type ) {
27
-		return update_option( $this->get_key( $lock_type ), time() + $this->get_duration( $lock_type ) );
26
+	public function set($lock_type) {
27
+		return update_option($this->get_key($lock_type), time() + $this->get_duration($lock_type));
28 28
 	}
29 29
 
30 30
 	/**
@@ -33,8 +33,8 @@  discard block
 block discarded – undo
33 33
 	 * @param string $lock_type A string to identify different lock types.
34 34
 	 * @return bool|int False if no lock is set, otherwise the timestamp for when the lock is set to expire.
35 35
 	 */
36
-	public function get_expiration( $lock_type ) {
37
-		return get_option( $this->get_key( $lock_type ) );
36
+	public function get_expiration($lock_type) {
37
+		return get_option($this->get_key($lock_type));
38 38
 	}
39 39
 
40 40
 	/**
@@ -43,7 +43,7 @@  discard block
 block discarded – undo
43 43
 	 * @param string $lock_type A string to identify different lock types.
44 44
 	 * @return string
45 45
 	 */
46
-	protected function get_key( $lock_type ) {
47
-		return sprintf( 'action_scheduler_lock_%s', $lock_type );
46
+	protected function get_key($lock_type) {
47
+		return sprintf('action_scheduler_lock_%s', $lock_type);
48 48
 	}
49 49
 }
Please login to merge, or discard this patch.
includes/libraries/action-scheduler/classes/ActionScheduler_ActionClaim.php 2 patches
Indentation   +13 added lines, -13 removed lines patch added patch discarded remove patch
@@ -4,20 +4,20 @@
 block discarded – undo
4 4
  * Class ActionScheduler_ActionClaim
5 5
  */
6 6
 class ActionScheduler_ActionClaim {
7
-	private $id = '';
8
-	private $action_ids = array();
7
+    private $id = '';
8
+    private $action_ids = array();
9 9
 
10
-	public function __construct( $id, array $action_ids ) {
11
-		$this->id = $id;
12
-		$this->action_ids = $action_ids;
13
-	}
10
+    public function __construct( $id, array $action_ids ) {
11
+        $this->id = $id;
12
+        $this->action_ids = $action_ids;
13
+    }
14 14
 
15
-	public function get_id() {
16
-		return $this->id;
17
-	}
15
+    public function get_id() {
16
+        return $this->id;
17
+    }
18 18
 
19
-	public function get_actions() {
20
-		return $this->action_ids;
21
-	}
19
+    public function get_actions() {
20
+        return $this->action_ids;
21
+    }
22 22
 }
23
- 
24 23
\ No newline at end of file
24
+    
25 25
\ No newline at end of file
Please login to merge, or discard this patch.
Spacing   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -7,7 +7,7 @@
 block discarded – undo
7 7
 	private $id = '';
8 8
 	private $action_ids = array();
9 9
 
10
-	public function __construct( $id, array $action_ids ) {
10
+	public function __construct($id, array $action_ids) {
11 11
 		$this->id = $id;
12 12
 		$this->action_ids = $action_ids;
13 13
 	}
Please login to merge, or discard this patch.
includes/libraries/action-scheduler/classes/ActionScheduler_QueueRunner.php 2 patches
Indentation   +191 added lines, -191 removed lines patch added patch discarded remove patch
@@ -4,195 +4,195 @@
 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 ( is_null( $async_request ) ) {
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
-		$cron_context = array( 'WP Cron' );
54
-
55
-		if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
56
-
57
-			// Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
58
-			$next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
59
-			if ( $next_timestamp ) {
60
-				wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
61
-			}
62
-
63
-			$schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
64
-			wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
65
-		}
66
-
67
-		add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
68
-		$this->hook_dispatch_async_request();
69
-	}
70
-
71
-	/**
72
-	 * Hook check for dispatching an async request.
73
-	 */
74
-	public function hook_dispatch_async_request() {
75
-		add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
76
-	}
77
-
78
-	/**
79
-	 * Unhook check for dispatching an async request.
80
-	 */
81
-	public function unhook_dispatch_async_request() {
82
-		remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
83
-	}
84
-
85
-	/**
86
-	 * Check if we should dispatch an async request to process actions.
87
-	 *
88
-	 * This method is attached to 'shutdown', so is called frequently. To avoid slowing down
89
-	 * the site, it mitigates the work performed in each request by:
90
-	 * 1. checking if it's in the admin context and then
91
-	 * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
92
-	 * 3. haven't exceeded the number of allowed batches.
93
-	 *
94
-	 * The order of these checks is important, because they run from a check on a value:
95
-	 * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
96
-	 * 2. in memory - transients use autoloaded options by default
97
-	 * 3. from a database query - has_maximum_concurrent_batches() run the query
98
-	 *    $this->store->get_claim_count() to find the current number of claims in the DB.
99
-	 *
100
-	 * If all of these conditions are met, then we request an async runner check whether it
101
-	 * should dispatch a request to process pending actions.
102
-	 */
103
-	public function maybe_dispatch_async_request() {
104
-		if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
105
-			// Only start an async queue at most once every 60 seconds
106
-			ActionScheduler::lock()->set( 'async-request-runner' );
107
-			$this->async_request->maybe_dispatch();
108
-		}
109
-	}
110
-
111
-	/**
112
-	 * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
113
-	 *
114
-	 * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
115
-	 * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
116
-	 * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
117
-	 * should set a context as the first parameter. For an example of this, refer to the code seen in
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
-	 * Running large batches can eat up memory, as WP adds data to its object cache.
178
-	 *
179
-	 * If using a persistent object store, this has the side effect of flushing that
180
-	 * as well, so this is disabled by default. To enable:
181
-	 *
182
-	 * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' );
183
-	 */
184
-	protected function clear_caches() {
185
-		if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {
186
-			wp_cache_flush();
187
-		}
188
-	}
189
-
190
-	public function add_wp_cron_schedule( $schedules ) {
191
-		$schedules['every_minute'] = array(
192
-			'interval' => 60, // in seconds
193
-			'display'  => __( 'Every minute', 'action-scheduler' ),
194
-		);
195
-
196
-		return $schedules;
197
-	}
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 ( is_null( $async_request ) ) {
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
+        $cron_context = array( 'WP Cron' );
54
+
55
+        if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
56
+
57
+            // Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
58
+            $next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
59
+            if ( $next_timestamp ) {
60
+                wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
61
+            }
62
+
63
+            $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
64
+            wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
65
+        }
66
+
67
+        add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
68
+        $this->hook_dispatch_async_request();
69
+    }
70
+
71
+    /**
72
+     * Hook check for dispatching an async request.
73
+     */
74
+    public function hook_dispatch_async_request() {
75
+        add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
76
+    }
77
+
78
+    /**
79
+     * Unhook check for dispatching an async request.
80
+     */
81
+    public function unhook_dispatch_async_request() {
82
+        remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
83
+    }
84
+
85
+    /**
86
+     * Check if we should dispatch an async request to process actions.
87
+     *
88
+     * This method is attached to 'shutdown', so is called frequently. To avoid slowing down
89
+     * the site, it mitigates the work performed in each request by:
90
+     * 1. checking if it's in the admin context and then
91
+     * 2. haven't run on the 'shutdown' hook within the lock time (60 seconds by default)
92
+     * 3. haven't exceeded the number of allowed batches.
93
+     *
94
+     * The order of these checks is important, because they run from a check on a value:
95
+     * 1. in memory - is_admin() maps to $GLOBALS or the WP_ADMIN constant
96
+     * 2. in memory - transients use autoloaded options by default
97
+     * 3. from a database query - has_maximum_concurrent_batches() run the query
98
+     *    $this->store->get_claim_count() to find the current number of claims in the DB.
99
+     *
100
+     * If all of these conditions are met, then we request an async runner check whether it
101
+     * should dispatch a request to process pending actions.
102
+     */
103
+    public function maybe_dispatch_async_request() {
104
+        if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
105
+            // Only start an async queue at most once every 60 seconds
106
+            ActionScheduler::lock()->set( 'async-request-runner' );
107
+            $this->async_request->maybe_dispatch();
108
+        }
109
+    }
110
+
111
+    /**
112
+     * Process actions in the queue. Attached to self::WP_CRON_HOOK i.e. 'action_scheduler_run_queue'
113
+     *
114
+     * The $context param of this method defaults to 'WP Cron', because prior to Action Scheduler 3.0.0
115
+     * that was the only context in which this method was run, and the self::WP_CRON_HOOK hook had no context
116
+     * passed along with it. New code calling this method directly, or by triggering the self::WP_CRON_HOOK,
117
+     * should set a context as the first parameter. For an example of this, refer to the code seen in
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
+     * Running large batches can eat up memory, as WP adds data to its object cache.
178
+     *
179
+     * If using a persistent object store, this has the side effect of flushing that
180
+     * as well, so this is disabled by default. To enable:
181
+     *
182
+     * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' );
183
+     */
184
+    protected function clear_caches() {
185
+        if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {
186
+            wp_cache_flush();
187
+        }
188
+    }
189
+
190
+    public function add_wp_cron_schedule( $schedules ) {
191
+        $schedules['every_minute'] = array(
192
+            'interval' => 60, // in seconds
193
+            'display'  => __( 'Every minute', 'action-scheduler' ),
194
+        );
195
+
196
+        return $schedules;
197
+    }
198 198
 }
Please login to merge, or discard this patch.
Spacing   +34 added lines, -34 removed lines patch added patch discarded remove patch
@@ -19,7 +19,7 @@  discard block
 block discarded – undo
19 19
 	 * @codeCoverageIgnore
20 20
 	 */
21 21
 	public static function instance() {
22
-		if ( empty(self::$runner) ) {
22
+		if (empty(self::$runner)) {
23 23
 			$class = apply_filters('action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner');
24 24
 			self::$runner = new $class();
25 25
 		}
@@ -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 ( is_null( $async_request ) ) {
40
-			$async_request = new ActionScheduler_AsyncRequest_QueueRunner( $this->store );
39
+		if (is_null($async_request)) {
40
+			$async_request = new ActionScheduler_AsyncRequest_QueueRunner($this->store);
41 41
 		}
42 42
 
43 43
 		$this->async_request = $async_request;
@@ -48,23 +48,23 @@  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
-		$cron_context = array( 'WP Cron' );
53
+		$cron_context = array('WP Cron');
54 54
 
55
-		if ( ! wp_next_scheduled( self::WP_CRON_HOOK, $cron_context ) ) {
55
+		if (!wp_next_scheduled(self::WP_CRON_HOOK, $cron_context)) {
56 56
 
57 57
 			// Check for and remove any WP Cron hook scheduled by Action Scheduler < 3.0.0, which didn't include the $context param
58
-			$next_timestamp = wp_next_scheduled( self::WP_CRON_HOOK );
59
-			if ( $next_timestamp ) {
60
-				wp_unschedule_event( $next_timestamp, self::WP_CRON_HOOK );
58
+			$next_timestamp = wp_next_scheduled(self::WP_CRON_HOOK);
59
+			if ($next_timestamp) {
60
+				wp_unschedule_event($next_timestamp, self::WP_CRON_HOOK);
61 61
 			}
62 62
 
63
-			$schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
64
-			wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK, $cron_context );
63
+			$schedule = apply_filters('action_scheduler_run_schedule', self::WP_CRON_SCHEDULE);
64
+			wp_schedule_event(time(), $schedule, self::WP_CRON_HOOK, $cron_context);
65 65
 		}
66 66
 
67
-		add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
67
+		add_action(self::WP_CRON_HOOK, array(self::instance(), 'run'));
68 68
 		$this->hook_dispatch_async_request();
69 69
 	}
70 70
 
@@ -72,14 +72,14 @@  discard block
 block discarded – undo
72 72
 	 * Hook check for dispatching an async request.
73 73
 	 */
74 74
 	public function hook_dispatch_async_request() {
75
-		add_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
75
+		add_action('shutdown', array($this, 'maybe_dispatch_async_request'));
76 76
 	}
77 77
 
78 78
 	/**
79 79
 	 * Unhook check for dispatching an async request.
80 80
 	 */
81 81
 	public function unhook_dispatch_async_request() {
82
-		remove_action( 'shutdown', array( $this, 'maybe_dispatch_async_request' ) );
82
+		remove_action('shutdown', array($this, 'maybe_dispatch_async_request'));
83 83
 	}
84 84
 
85 85
 	/**
@@ -101,9 +101,9 @@  discard block
 block discarded – undo
101 101
 	 * should dispatch a request to process pending actions.
102 102
 	 */
103 103
 	public function maybe_dispatch_async_request() {
104
-		if ( is_admin() && ! ActionScheduler::lock()->is_locked( 'async-request-runner' ) ) {
104
+		if (is_admin() && !ActionScheduler::lock()->is_locked('async-request-runner')) {
105 105
 			// Only start an async queue at most once every 60 seconds
106
-			ActionScheduler::lock()->set( 'async-request-runner' );
106
+			ActionScheduler::lock()->set('async-request-runner');
107 107
 			$this->async_request->maybe_dispatch();
108 108
 		}
109 109
 	}
@@ -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,20 +150,20 @@  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 = '' ) {
153
+	protected function do_batch($size = 100, $context = '') {
154 154
 		$claim = $this->store->stake_claim($size);
155 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
 		}
@@ -182,15 +182,15 @@  discard block
 block discarded – undo
182 182
 	 * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' );
183 183
 	 */
184 184
 	protected function clear_caches() {
185
-		if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {
185
+		if (!wp_using_ext_object_cache() || apply_filters('action_scheduler_queue_runner_flush_cache', false)) {
186 186
 			wp_cache_flush();
187 187
 		}
188 188
 	}
189 189
 
190
-	public function add_wp_cron_schedule( $schedules ) {
190
+	public function add_wp_cron_schedule($schedules) {
191 191
 		$schedules['every_minute'] = array(
192 192
 			'interval' => 60, // in seconds
193
-			'display'  => __( 'Every minute', 'action-scheduler' ),
193
+			'display'  => __('Every minute', 'action-scheduler'),
194 194
 		);
195 195
 
196 196
 		return $schedules;
Please login to merge, or discard this patch.