PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.0.5
WooCommerce v10.0.5
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / libraries / wp-background-process.php
woocommerce / includes / libraries Last commit date
class-wc-eval-math.php 6 years ago wp-async-request.php 8 years ago wp-background-process.php 1 year ago
wp-background-process.php
504 lines
1 <?php // @codingStandardsIgnoreLine.
2 /**
3 * Abstract WP_Background_Process class.
4 *
5 * @package WP-Background-Processing
6 * @extends WP_Async_Request
7 */
8
9 defined( 'ABSPATH' ) || exit;
10
11 /**
12 * Abstract WP_Background_Process class.
13 */
14 abstract class WP_Background_Process extends WP_Async_Request {
15
16 /**
17 * Action
18 *
19 * (default value: 'background_process')
20 *
21 * @var string
22 * @access protected
23 */
24 protected $action = 'background_process';
25
26 /**
27 * Start time of current process.
28 *
29 * (default value: 0)
30 *
31 * @var int
32 * @access protected
33 */
34 protected $start_time = 0;
35
36 /**
37 * Cron_hook_identifier
38 *
39 * @var mixed
40 * @access protected
41 */
42 protected $cron_hook_identifier;
43
44 /**
45 * Cron_interval_identifier
46 *
47 * @var mixed
48 * @access protected
49 */
50 protected $cron_interval_identifier;
51
52 /**
53 * Initiate new background process
54 */
55 public function __construct() {
56 parent::__construct();
57
58 $this->cron_hook_identifier = $this->identifier . '_cron';
59 $this->cron_interval_identifier = $this->identifier . '_cron_interval';
60
61 add_action( $this->cron_hook_identifier, array( $this, 'handle_cron_healthcheck' ) );
62 add_filter( 'cron_schedules', array( $this, 'schedule_cron_healthcheck' ) );
63 }
64
65 /**
66 * Dispatch
67 *
68 * @access public
69 * @return array|WP_Error
70 */
71 public function dispatch() {
72 // Schedule the cron healthcheck.
73 $this->schedule_event();
74
75 // Perform remote post.
76 return parent::dispatch();
77 }
78
79 /**
80 * Push to queue
81 *
82 * @param mixed $data Data.
83 *
84 * @return $this
85 */
86 public function push_to_queue( $data ) {
87 $this->data[] = $data;
88
89 return $this;
90 }
91
92 /**
93 * Save queue
94 *
95 * @return $this
96 */
97 public function save() {
98 $key = $this->generate_key();
99
100 if ( ! empty( $this->data ) ) {
101 update_site_option( $key, $this->data );
102 }
103
104 return $this;
105 }
106
107 /**
108 * Update queue
109 *
110 * @param string $key Key.
111 * @param array $data Data.
112 *
113 * @return $this
114 */
115 public function update( $key, $data ) {
116 if ( ! empty( $data ) ) {
117 update_site_option( $key, $data );
118 }
119
120 return $this;
121 }
122
123 /**
124 * Delete queue
125 *
126 * @param string $key Key.
127 *
128 * @return $this
129 */
130 public function delete( $key ) {
131 delete_site_option( $key );
132
133 return $this;
134 }
135
136 /**
137 * Generate key
138 *
139 * Generates a unique key based on microtime. Queue items are
140 * given a unique key so that they can be merged upon save.
141 *
142 * @param int $length Length.
143 *
144 * @return string
145 */
146 protected function generate_key( $length = 64 ) {
147 $unique = md5( microtime() . rand() );
148 $prepend = $this->identifier . '_batch_';
149
150 return substr( $prepend . $unique, 0, $length );
151 }
152
153 /**
154 * Maybe process queue
155 *
156 * Checks whether data exists within the queue and that
157 * the process is not already running.
158 */
159 public function maybe_handle() {
160 // Don't lock up other requests while processing
161 session_write_close();
162
163 if ( $this->is_process_running() ) {
164 // Background process already running.
165 wp_die();
166 }
167
168 if ( $this->is_queue_empty() ) {
169 // No data to process.
170 wp_die();
171 }
172
173 check_ajax_referer( $this->identifier, 'nonce' );
174
175 $this->handle();
176
177 wp_die();
178 }
179
180 /**
181 * Is queue empty
182 *
183 * @return bool
184 */
185 protected function is_queue_empty() {
186 global $wpdb;
187
188 $table = $wpdb->options;
189 $column = 'option_name';
190
191 if ( is_multisite() ) {
192 $table = $wpdb->sitemeta;
193 $column = 'meta_key';
194 }
195
196 $key = $this->identifier . '_batch_%';
197
198 $count = $wpdb->get_var( $wpdb->prepare( "
199 SELECT COUNT(*)
200 FROM {$table}
201 WHERE {$column} LIKE %s
202 ", $key ) );
203
204 return ! ( $count > 0 );
205 }
206
207 /**
208 * Is process running
209 *
210 * Check whether the current process is already running
211 * in a background process.
212 */
213 protected function is_process_running() {
214 if ( get_site_transient( $this->identifier . '_process_lock' ) ) {
215 // Process already running.
216 return true;
217 }
218
219 return false;
220 }
221
222 /**
223 * Lock process
224 *
225 * Lock the process so that multiple instances can't run simultaneously.
226 * Override if applicable, but the duration should be greater than that
227 * defined in the time_exceeded() method.
228 */
229 protected function lock_process() {
230 $this->start_time = time(); // Set start time of current process.
231
232 $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
233 $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
234
235 set_site_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
236 }
237
238 /**
239 * Unlock process
240 *
241 * Unlock the process so that other instances can spawn.
242 *
243 * @return $this
244 */
245 protected function unlock_process() {
246 delete_site_transient( $this->identifier . '_process_lock' );
247
248 return $this;
249 }
250
251 /**
252 * Get batch
253 *
254 * @return stdClass Return the first batch from the queue
255 */
256 protected function get_batch() {
257 global $wpdb;
258
259 $table = $wpdb->options;
260 $column = 'option_name';
261 $key_column = 'option_id';
262 $value_column = 'option_value';
263
264 if ( is_multisite() ) {
265 $table = $wpdb->sitemeta;
266 $column = 'meta_key';
267 $key_column = 'meta_id';
268 $value_column = 'meta_value';
269 }
270
271 $key = $this->identifier . '_batch_%';
272
273 $query = $wpdb->get_row( $wpdb->prepare( "
274 SELECT *
275 FROM {$table}
276 WHERE {$column} LIKE %s
277 ORDER BY {$key_column} ASC
278 LIMIT 1
279 ", $key ) );
280
281 $batch = new stdClass();
282 $batch->key = $query->$column;
283 $batch->data = maybe_unserialize( $query->$value_column );
284
285 return $batch;
286 }
287
288 /**
289 * Handle
290 *
291 * Pass each queue item to the task handler, while remaining
292 * within server memory and time limit constraints.
293 */
294 protected function handle() {
295 $this->lock_process();
296
297 do {
298 $batch = $this->get_batch();
299
300 foreach ( $batch->data as $key => $value ) {
301 $task = $this->task( $value );
302
303 if ( false !== $task ) {
304 $batch->data[ $key ] = $task;
305 } else {
306 unset( $batch->data[ $key ] );
307 }
308
309 if ( $this->time_exceeded() || $this->memory_exceeded() ) {
310 // Batch limits reached.
311 break;
312 }
313 }
314
315 // Update or delete current batch.
316 if ( ! empty( $batch->data ) ) {
317 $this->update( $batch->key, $batch->data );
318 } else {
319 $this->delete( $batch->key );
320 }
321 } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
322
323 $this->unlock_process();
324
325 // Start next batch or complete process.
326 if ( ! $this->is_queue_empty() ) {
327 $this->dispatch();
328 } else {
329 $this->complete();
330 }
331
332 wp_die();
333 }
334
335 /**
336 * Memory exceeded
337 *
338 * Ensures the batch process never exceeds 90%
339 * of the maximum WordPress memory.
340 *
341 * @return bool
342 */
343 protected function memory_exceeded() {
344 $memory_limit = $this->get_memory_limit() * 0.9; // 90% of max memory
345 $current_memory = memory_get_usage( true );
346 $return = false;
347
348 if ( $current_memory >= $memory_limit ) {
349 $return = true;
350 }
351
352 return apply_filters( $this->identifier . '_memory_exceeded', $return );
353 }
354
355 /**
356 * Get memory limit
357 *
358 * @return int
359 */
360 protected function get_memory_limit() {
361 if ( function_exists( 'ini_get' ) ) {
362 $memory_limit = ini_get( 'memory_limit' );
363 } else {
364 // Sensible default.
365 $memory_limit = '128M';
366 }
367
368 if ( ! $memory_limit || -1 === $memory_limit ) {
369 // Unlimited, set to 32GB.
370 $memory_limit = '32000M';
371 }
372
373 return wp_convert_hr_to_bytes( $memory_limit );
374 }
375
376 /**
377 * Time exceeded.
378 *
379 * Ensures the batch never exceeds a sensible time limit.
380 * A timeout limit of 30s is common on shared hosting.
381 *
382 * @return bool
383 */
384 protected function time_exceeded() {
385 $finish = $this->start_time + apply_filters( $this->identifier . '_default_time_limit', 20 ); // 20 seconds
386 $return = false;
387
388 if ( time() >= $finish ) {
389 $return = true;
390 }
391
392 return apply_filters( $this->identifier . '_time_exceeded', $return );
393 }
394
395 /**
396 * Complete.
397 *
398 * Override if applicable, but ensure that the below actions are
399 * performed, or, call parent::complete().
400 */
401 protected function complete() {
402 // Unschedule the cron healthcheck.
403 $this->clear_scheduled_event();
404 }
405
406 /**
407 * Schedule cron healthcheck
408 *
409 * @access public
410 * @param mixed $schedules Schedules.
411 * @return mixed
412 */
413 public function schedule_cron_healthcheck( $schedules ) {
414 $interval = apply_filters( $this->identifier . '_cron_interval', 5 );
415
416 if ( property_exists( $this, 'cron_interval' ) ) {
417 $interval = apply_filters( $this->identifier . '_cron_interval', $this->cron_interval );
418 }
419
420 // Adds every 5 minutes to the existing schedules.
421 $schedules[ $this->identifier . '_cron_interval' ] = array(
422 'interval' => MINUTE_IN_SECONDS * $interval,
423 'display' => sprintf( __( 'Every %d minutes', 'woocommerce' ), $interval ),
424 );
425
426 return $schedules;
427 }
428
429 /**
430 * Handle cron healthcheck
431 *
432 * Restart the background process if not already running
433 * and data exists in the queue.
434 */
435 public function handle_cron_healthcheck() {
436 if ( $this->is_process_running() ) {
437 // Background process already running.
438 exit;
439 }
440
441 if ( $this->is_queue_empty() ) {
442 // No data to process.
443 $this->clear_scheduled_event();
444 exit;
445 }
446
447 $this->handle();
448
449 exit;
450 }
451
452 /**
453 * Schedule event
454 */
455 protected function schedule_event() {
456 if ( ! wp_next_scheduled( $this->cron_hook_identifier ) ) {
457 wp_schedule_event( time(), $this->cron_interval_identifier, $this->cron_hook_identifier );
458 }
459 }
460
461 /**
462 * Clear scheduled event
463 */
464 protected function clear_scheduled_event() {
465 $timestamp = wp_next_scheduled( $this->cron_hook_identifier );
466
467 if ( $timestamp ) {
468 wp_unschedule_event( $timestamp, $this->cron_hook_identifier );
469 }
470 }
471
472 /**
473 * Cancel Process
474 *
475 * Stop processing queue items, clear cronjob and delete batch.
476 *
477 */
478 public function cancel_process() {
479 if ( ! $this->is_queue_empty() ) {
480 $batch = $this->get_batch();
481
482 $this->delete( $batch->key );
483
484 wp_clear_scheduled_hook( $this->cron_hook_identifier );
485 }
486
487 }
488
489 /**
490 * Task
491 *
492 * Override this method to perform any actions required on each
493 * queue item. Return the modified item for further processing
494 * in the next pass through. Or, return false to remove the
495 * item from the queue.
496 *
497 * @param mixed $item Queue item to iterate over.
498 *
499 * @return mixed
500 */
501 abstract protected function task( $item );
502
503 }
504