PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.10.4
GiveWP – Donation Plugin and Fundraising Platform v2.10.4
4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / class-give-background-updater.php
give / includes Last commit date
admin 5 years ago api 5 years ago database 5 years ago deprecated 5 years ago donors 5 years ago emails 6 years ago forms 5 years ago frontend 6 years ago gateways 5 years ago libraries 6 years ago payments 5 years ago actions.php 5 years ago ajax-functions.php 5 years ago class-give-async-process.php 6 years ago class-give-background-updater.php 6 years ago class-give-cache-setting.php 5 years ago class-give-cache.php 6 years ago class-give-cli-commands.php 6 years ago class-give-comment.php 6 years ago class-give-cron.php 6 years ago class-give-donate-form.php 6 years ago class-give-donor.php 5 years ago class-give-email-access.php 5 years ago class-give-license-handler.php 5 years ago class-give-logging.php 5 years ago class-give-readme-parser.php 6 years ago class-give-roles.php 6 years ago class-give-scripts.php 5 years ago class-give-session.php 5 years ago class-give-stats.php 6 years ago class-give-template-loader.php 6 years ago class-give-tooltips.php 6 years ago class-give-translation.php 6 years ago class-notices.php 5 years ago country-functions.php 5 years ago currencies-list.php 6 years ago currency-functions.php 5 years ago error-tracking.php 6 years ago filters.php 5 years ago formatting.php 6 years ago install.php 5 years ago login-register.php 6 years ago misc-functions.php 5 years ago plugin-compatibility.php 6 years ago post-types.php 5 years ago price-functions.php 6 years ago process-donation.php 5 years ago setting-functions.php 6 years ago shortcodes.php 6 years ago template-functions.php 5 years ago user-functions.php 5 years ago
class-give-background-updater.php
613 lines
1 <?php
2 /**
3 * Background Updater
4 *
5 * Uses https://github.com/A5hleyRich/wp-background-processing to handle DB
6 * updates in the background.
7 *
8 * @class Give_Background_Updater
9 * @version 2.0.0
10 * @package Give/Classes
11 * @category Class
12 * @author GiveWP
13 */
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Give_Background_Updater Class.
20 */
21 class Give_Background_Updater extends WP_Background_Process {
22
23 /**
24 * @var string
25 */
26 protected $action = 'give_db_updater';
27
28 /**
29 * Dispatch updater.
30 *
31 * Updater will still run via cron job if this fails for any reason.
32 */
33 public function dispatch() {
34 if ( give_test_ajax_works() ) {
35 parent::dispatch();
36 } elseif ( wp_doing_ajax() ) {
37 $this->maybe_handle();
38 }
39 }
40
41
42 /**
43 * Get all batches.
44 *
45 * @since 2.0
46 * @access public
47 * @return stdClass
48 */
49 public function get_all_batch() {
50 return $this->get_batch();
51 }
52
53 /**
54 * Is queue empty
55 *
56 * @since 2.0.3
57 *
58 * @return bool
59 */
60 public function has_queue() {
61 return ( ! $this->is_queue_empty() );
62 }
63
64
65 /**
66 * Lock process
67 *
68 * Lock the process so that multiple instances can't run simultaneously.
69 * Override if applicable, but the duration should be greater than that
70 * defined in the time_exceeded() method.
71 *
72 * @since 2.0.3
73 */
74 protected function lock_process() {
75 // Check if admin want to pause upgrade.
76 if ( get_option( 'give_pause_upgrade' ) ) {
77 self::flush_cache();
78
79 delete_option( 'give_paused_batches' );
80
81 Give_Updates::get_instance()->__pause_db_update( true );
82
83 delete_option( 'give_pause_upgrade' );
84
85 /**
86 * Fire action when pause db updates
87 *
88 * @since 2.0.1
89 */
90 do_action( 'give_pause_db_upgrade', Give_Updates::get_instance() );
91
92 wp_die();
93 }
94
95 $this->start_time = time(); // Set start time of current process.
96
97 $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
98 $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
99
100 set_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
101 }
102
103 /**
104 * Handle cron healthcheck
105 *
106 * Restart the background process if not already running
107 * and data exists in the queue.
108 */
109 public function handle_cron_healthcheck() {
110 if ( $this->is_process_running() || $this->is_paused_process() ) {
111 // Background process already running.
112 return;
113 }
114
115 if ( $this->is_queue_empty() ) {
116 // No data to process.
117 $this->clear_scheduled_event();
118
119 return;
120 }
121
122 $this->handle();
123 }
124
125 /**
126 * Schedule fallback event.
127 */
128 protected function schedule_event() {
129 if ( ! wp_next_scheduled( $this->cron_hook_identifier ) && ! $this->is_paused_process() ) {
130 wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
131 }
132 }
133
134 /**
135 * Is queue empty
136 *
137 * @since 2.4.5
138 *
139 * @return bool
140 */
141 protected function is_queue_empty() {
142 global $wpdb;
143
144 $table = $wpdb->options;
145 $column = 'option_name';
146
147 $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
148
149 $count = $wpdb->get_var(
150 $wpdb->prepare(
151 "
152 SELECT COUNT(*)
153 FROM {$table}
154 WHERE {$column} LIKE %s
155 ",
156 $key
157 )
158 );
159
160 return ! ( $count > 0 );
161 }
162
163 /**
164 * Get batch
165 *
166 * @since 2.4.5
167 *
168 * @return stdClass Return the first batch from the queue
169 */
170 protected function get_batch() {
171 global $wpdb;
172
173 $table = $wpdb->options;
174 $column = 'option_name';
175 $key_column = 'option_id';
176 $value_column = 'option_value';
177
178 $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
179
180 $query = $wpdb->get_row(
181 $wpdb->prepare(
182 "
183 SELECT *
184 FROM {$table}
185 WHERE {$column} LIKE %s
186 ORDER BY {$key_column} ASC
187 LIMIT 1
188 ",
189 $key
190 )
191 );
192
193 $batch = new stdClass();
194 $batch->key = $query->$column;
195 $batch->data = maybe_unserialize( $query->$value_column );
196
197 return $batch;
198 }
199
200 /**
201 * Save queue
202 *
203 * @since 2.4.5
204 *
205 * @return $this
206 */
207 public function save() {
208 $key = $this->generate_key();
209
210 if ( ! empty( $this->data ) ) {
211 update_option( $key, $this->data );
212 }
213
214 return $this;
215 }
216
217 /**
218 * Update queue
219 *
220 * @since 2.4.5
221 *
222 * @param string $key Key.
223 * @param array $data Data.
224 *
225 * @return $this
226 */
227 public function update( $key, $data ) {
228 if ( ! empty( $data ) ) {
229 update_option( $key, $data );
230 }
231
232 return $this;
233 }
234
235 /**
236 * Delete queue
237 *
238 * @since 2.4.5
239 *
240 * @param string $key Key.
241 *
242 * @return $this
243 */
244 public function delete( $key ) {
245 delete_option( $key );
246
247 return $this;
248 }
249
250 /**
251 * Is process running
252 *
253 * @since 2.4.5
254 *
255 * Check whether the current process is already running
256 * in a background process.
257 */
258 public function is_process_running() {
259 if ( get_transient( $this->identifier . '_process_lock' ) ) {
260 // Process already running.
261 return true;
262 }
263
264 return false;
265 }
266
267 /**
268 * Unlock process
269 *
270 * Unlock the process so that other instances can spawn.
271 *
272 * @since 2.4.5
273 *
274 * @return $this
275 */
276 protected function unlock_process() {
277 delete_transient( $this->identifier . '_process_lock' );
278
279 return $this;
280 }
281
282 /**
283 * Task
284 *
285 * Override this method to perform any actions required on each
286 * queue item. Return the modified item for further processing
287 * in the next pass through. Or, return false to remove the
288 * item from the queue.
289 *
290 * @param array $update Update info
291 *
292 * @return mixed
293 */
294 protected function task( $update ) {
295 // Pause upgrade immediately if admin pausing upgrades.
296 if ( $this->is_paused_process() ) {
297 wp_die();
298 }
299
300 if ( empty( $update ) ) {
301 return false;
302 }
303
304 // Delete cache.
305 self::flush_cache();
306
307 /* @var Give_Updates $give_updates */
308 $give_updates = Give_Updates::get_instance();
309 $resume_update = get_option(
310 'give_doing_upgrade',
311 // Default update.
312 array(
313 'update_info' => $update,
314 'step' => 1,
315 'update' => 1,
316 'heading' => sprintf( 'Update %s of {update_count}', 1 ),
317 'percentage' => $give_updates->percentage,
318 'total_percentage' => 0,
319 )
320 );
321
322 // Continuously skip update if previous update does not complete yet.
323 if (
324 $resume_update['update_info']['id'] !== $update['id'] &&
325 ! give_has_upgrade_completed( $resume_update['update_info']['id'] )
326 ) {
327 return $update;
328 }
329
330 // Set params.
331 $resume_update['update_info'] = $update;
332 $give_updates->step = absint( $resume_update['step'] );
333 $give_updates->update = absint( $resume_update['update'] );
334 $is_parent_update_completed = $give_updates->is_parent_updates_completed( $update );
335
336 // Skip update if dependency update does not complete yet.
337 if ( empty( $is_parent_update_completed ) ) {
338 // @todo: set error when you have only one update with invalid dependency
339 if ( ! is_null( $is_parent_update_completed ) ) {
340 return $update;
341 }
342
343 return false;
344 }
345
346 // Pause upgrade immediately if found following:
347 // 1. Running update number greater then total update count
348 // 2. Processing percentage greater then 100%
349 if ( (
350 101 < $resume_update['total_percentage'] ) ||
351 ( $give_updates->get_total_db_update_count() < $resume_update['update'] ) ||
352 ! in_array( $resume_update['update_info']['id'], $give_updates->get_update_ids() )
353 ) {
354 if ( ! $this->is_paused_process() ) {
355 $give_updates->__pause_db_update( true );
356 }
357
358 update_option( 'give_upgrade_error', 1, false );
359
360 $log_data = 'Update Task' . "\n";
361 $log_data .= "Total update count: {$give_updates->get_total_db_update_count()}\n";
362 $log_data .= 'Update IDs: ' . print_r( $give_updates->get_update_ids(), true );
363 $log_data .= 'Update: ' . print_r( $resume_update, true );
364
365 Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
366
367 wp_die();
368 }
369
370 // Disable cache.
371 Give_Cache::disable();
372
373 try {
374 // Run update.
375 if ( is_array( $update['callback'] ) ) {
376 $object = $update['callback'][0];
377 $method_name = $update['callback'][1];
378
379 $object->$method_name();
380
381 } else {
382 $update['callback']();
383 }
384 } catch ( Exception $e ) {
385
386 if ( ! $this->is_paused_process() ) {
387 $give_updates->__pause_db_update( true );
388 }
389
390 $log_data = 'Update Task' . "\n";
391 $log_data .= print_r( $resume_update, true ) . "\n\n";
392 $log_data .= "Error\n {$e->getMessage()}";
393
394 Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
395 update_option( 'give_upgrade_error', 1, false );
396
397 wp_die();
398 }
399
400 // Set update info.
401 $doing_upgrade_args = array(
402 'update_info' => $update,
403 'step' => ++ $give_updates->step,
404 'update' => $give_updates->update,
405 'heading' => sprintf( 'Update %s of %s', $give_updates->update, get_option( 'give_db_update_count' ) ),
406 'percentage' => $give_updates->percentage,
407 'total_percentage' => $give_updates->get_db_update_processing_percentage(),
408 );
409
410 // Cache upgrade.
411 update_option( 'give_doing_upgrade', $doing_upgrade_args, false );
412
413 // Enable cache.
414 Give_Cache::enable();
415
416 // Check if current update completed or not.
417 if ( give_has_upgrade_completed( $update['id'] ) ) {
418 return false;
419 }
420
421 return $update;
422 }
423
424 /**
425 * Complete
426 *
427 * Override if applicable, but ensure that the below actions are
428 * performed, or, call parent::complete().
429 */
430 public function complete() {
431 if ( $this->is_paused_process() ) {
432 return false;
433 }
434
435 parent::complete();
436
437 delete_option( 'give_pause_upgrade' );
438 delete_option( 'give_upgrade_error' );
439 delete_option( 'give_db_update_count' );
440 delete_option( 'give_doing_upgrade' );
441 add_option( 'give_show_db_upgrade_complete_notice', 1, '', false );
442
443 // Flush cache.
444 Give_Cache::flush_cache( true );
445
446 if ( $cache_keys = Give_Cache::get_options_like( '' ) ) {
447 Give_Cache::delete( $cache_keys );
448 }
449 }
450
451 /**
452 * Get memory limit
453 *
454 * @return int
455 */
456 protected function get_memory_limit() {
457 if ( function_exists( 'ini_get' ) ) {
458 $memory_limit = ini_get( 'memory_limit' );
459 } else {
460 // Sensible default.
461 $memory_limit = '128M';
462 }
463
464 if ( ! $memory_limit || '-1' === $memory_limit ) {
465 // Unlimited, set to 32GB.
466 $memory_limit = '32G';
467 }
468
469 return give_let_to_num( $memory_limit );
470 }
471
472 /**
473 * Maybe process queue
474 *
475 * Checks whether data exists within the queue and that
476 * the process is not already running.
477 */
478 public function maybe_handle() {
479 // Don't lock up other requests while processing
480 session_write_close();
481
482 if ( $this->is_process_running() || $this->is_paused_process() ) {
483 // Background process already running.
484 wp_die();
485 }
486
487 if ( $this->is_queue_empty() ) {
488 // No data to process.
489 wp_die();
490 }
491
492 check_ajax_referer( $this->identifier, 'nonce' );
493
494 $this->handle();
495
496 wp_die();
497 }
498
499 /**
500 * Handle
501 *
502 * Pass each queue item to the task handler, while remaining
503 * within server memory and time limit constraints.
504 */
505 protected function handle() {
506 $this->lock_process();
507
508 do {
509 $batch = $this->get_batch();
510
511 foreach ( $batch->data as $key => $value ) {
512 $task = $this->task( $value );
513
514 if ( false !== $task ) {
515 $batch->data[ $key ] = $task;
516 } else {
517 unset( $batch->data[ $key ] );
518 }
519
520 if ( $this->time_exceeded() || $this->memory_exceeded() ) {
521 // Batch limits reached.
522 break;
523 }
524 }
525
526 // Update or delete current batch.
527 if ( ! empty( $batch->data ) ) {
528 $this->update( $batch->key, $batch->data );
529 } else {
530 $this->delete( $batch->key );
531 }
532 } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
533
534 $this->unlock_process();
535
536 // Start next batch or complete process.
537 if ( ! $this->is_queue_empty() ) {
538
539 // Dispatch only if ajax works.
540 if ( give_test_ajax_works() ) {
541 $this->dispatch();
542 }
543 } else {
544 $this->complete();
545 }
546
547 wp_die();
548 }
549
550
551 /**
552 * Check if backgound upgrade paused or not.
553 *
554 * @since 2.0
555 * @access public
556 * @return bool
557 */
558 public function is_paused_process() {
559 // Delete cache.
560 wp_cache_delete( 'give_paused_batches', 'options' );
561
562 $paused_batches = Give_Cache_Setting::get_option( 'give_paused_batches' );
563
564 return ! empty( $paused_batches );
565 }
566
567
568 /**
569 * Get identifier
570 *
571 * @since 2.0
572 * @access public
573 * @return mixed|string
574 */
575 public function get_identifier() {
576 return $this->identifier;
577 }
578
579 /**
580 * Get cron identifier
581 *
582 * @since 2.0
583 * @access public
584 * @return mixed|string
585 */
586 public function get_cron_identifier() {
587 return $this->cron_hook_identifier;
588 }
589
590
591 /**
592 * Flush background update related cache to prevent task to go to stalled state.
593 *
594 * @since 2.0.3
595 */
596 public static function flush_cache() {
597
598 $options = array(
599 'give_completed_upgrades',
600 'give_doing_upgrade',
601 'give_paused_batches',
602 'give_upgrade_error',
603 'give_db_update_count',
604 'give_pause_upgrade',
605 'give_show_db_upgrade_complete_notice',
606 );
607
608 foreach ( $options as $option ) {
609 wp_cache_delete( $option, 'options' );
610 }
611 }
612 }
613