PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.2.2
GiveWP – Donation Plugin and Fundraising Platform v3.2.2
4.16.3 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 2 years ago api 3 years ago database 2 years ago deprecated 3 years ago donors 2 years ago emails 3 years ago forms 2 years ago frontend 6 years ago gateways 2 years ago libraries 2 years ago payments 2 years ago actions.php 5 years ago ajax-functions.php 2 years ago class-give-async-process.php 2 years ago class-give-background-updater.php 2 years ago class-give-cache-setting.php 2 years ago class-give-cache.php 3 years ago class-give-cli-commands.php 3 years ago class-give-comment.php 6 years ago class-give-cron.php 6 years ago class-give-donate-form.php 4 years ago class-give-donor.php 3 years ago class-give-email-access.php 5 years ago class-give-license-handler.php 4 years ago class-give-logging.php 5 years ago class-give-readme-parser.php 4 years ago class-give-roles.php 6 years ago class-give-scripts.php 2 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 4 years ago class-notices.php 2 years ago country-functions.php 5 years ago currencies-list.php 3 years ago currency-functions.php 3 years ago error-tracking.php 6 years ago filters.php 3 years ago formatting.php 2 years ago install.php 2 years ago login-register.php 4 years ago misc-functions.php 2 years ago plugin-compatibility.php 6 years ago post-types.php 5 years ago price-functions.php 6 years ago process-donation.php 4 years ago setting-functions.php 6 years ago shortcodes.php 2 years ago template-functions.php 4 years ago user-functions.php 3 years ago
class-give-background-updater.php
638 lines
1 <?php
2
3 use Give\Framework\WordPressLibraries\WPBackgroundProcess;
4
5 /**
6 * Background Updater
7 *
8 * Uses https://github.com/A5hleyRich/wp-background-processing to handle DB
9 * updates in the background.
10 *
11 * @package Give/Classes
12 *
13 * @class Give_Background_Updater
14 * @version 2.0.0
15 * @category Class
16 * @author GiveWP
17 *
18 * @since 2.32.0 updated to extend WPBackgroundProcess
19 */
20 if ( ! defined('ABSPATH')) {
21 exit;
22 }
23
24 /**
25 * Give_Background_Updater Class.
26 */
27 class Give_Background_Updater extends WPBackgroundProcess
28 {
29
30 /**
31 * @var string
32 */
33 protected $action = 'give_db_updater';
34
35 /**
36 * Dispatch updater.
37 *
38 * Updater will still run via cron job if this fails for any reason.
39 */
40 public function dispatch()
41 {
42 if (give_test_ajax_works()) {
43 parent::dispatch();
44 } elseif (wp_doing_ajax()) {
45 $this->maybe_handle();
46 }
47 }
48
49
50 /**
51 * Get all batches.
52 *
53 * @since 2.0
54 * @access public
55 * @return stdClass
56 */
57 public function get_all_batch()
58 {
59 return $this->get_batch();
60 }
61
62 /**
63 * Is queue empty
64 *
65 * @since 2.0.3
66 *
67 * @return bool
68 */
69 public function has_queue()
70 {
71 return ( ! $this->is_queue_empty());
72 }
73
74
75 /**
76 * Lock process
77 *
78 * Lock the process so that multiple instances can't run simultaneously.
79 * Override if applicable, but the duration should be greater than that
80 * defined in the time_exceeded() method.
81 *
82 * @since 2.0.3
83 */
84 protected function lock_process()
85 {
86 // Check if admin want to pause upgrade.
87 if (get_option('give_pause_upgrade')) {
88 self::flush_cache();
89
90 delete_option('give_paused_batches');
91
92 Give_Updates::get_instance()->__pause_db_update(true);
93
94 delete_option('give_pause_upgrade');
95
96 /**
97 * Fire action when pause db updates
98 *
99 * @since 2.0.1
100 */
101 do_action('give_pause_db_upgrade', Give_Updates::get_instance());
102
103 wp_die();
104 }
105
106 $this->start_time = time(); // Set start time of current process.
107
108 $lock_duration = (property_exists($this, 'queue_lock_time')) ? $this->queue_lock_time : 60; // 1 minute
109 $lock_duration = apply_filters($this->identifier . '_queue_lock_time', $lock_duration);
110
111 set_transient($this->identifier . '_process_lock', microtime(), $lock_duration);
112 }
113
114 /**
115 * Handle cron healthcheck
116 *
117 * Restart the background process if not already running
118 * and data exists in the queue.
119 */
120 public function handle_cron_healthcheck()
121 {
122 if ($this->is_process_running() || $this->is_paused_process()) {
123 // Background process already running.
124 return;
125 }
126
127 if ($this->is_queue_empty()) {
128 // No data to process.
129 $this->clear_scheduled_event();
130
131 return;
132 }
133
134 $this->handle();
135 }
136
137 /**
138 * Schedule fallback event.
139 */
140 protected function schedule_event()
141 {
142 if ( ! wp_next_scheduled($this->cron_hook_identifier) && ! $this->is_paused_process()) {
143 wp_schedule_event(time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier);
144 }
145 }
146
147 /**
148 * Is queue empty
149 *
150 * @since 2.4.5
151 *
152 * @return bool
153 */
154 protected function is_queue_empty()
155 {
156 global $wpdb;
157
158 $table = $wpdb->options;
159 $column = 'option_name';
160
161 $key = $wpdb->esc_like($this->identifier . '_batch_') . '%';
162
163 $count = $wpdb->get_var(
164 $wpdb->prepare(
165 "
166 SELECT COUNT(*)
167 FROM {$table}
168 WHERE {$column} LIKE %s
169 ",
170 $key
171 )
172 );
173
174 return ! ($count > 0);
175 }
176
177 /**
178 * Get batch
179 *
180 * @since 2.4.5
181 *
182 * @return stdClass Return the first batch from the queue
183 */
184 protected function get_batch()
185 {
186 global $wpdb;
187
188 $table = $wpdb->options;
189 $column = 'option_name';
190 $key_column = 'option_id';
191 $value_column = 'option_value';
192
193 $key = $wpdb->esc_like($this->identifier . '_batch_') . '%';
194
195 $query = $wpdb->get_row(
196 $wpdb->prepare(
197 "
198 SELECT *
199 FROM {$table}
200 WHERE {$column} LIKE %s
201 ORDER BY {$key_column} ASC
202 LIMIT 1
203 ",
204 $key
205 )
206 );
207
208 $batch = new stdClass();
209 $batch->key = $query->$column;
210 $batch->data = maybe_unserialize($query->$value_column);
211
212 return $batch;
213 }
214
215 /**
216 * Save queue
217 *
218 * @since 2.4.5
219 *
220 * @return $this
221 */
222 public function save()
223 {
224 $key = $this->generate_key();
225
226 if ( ! empty($this->data)) {
227 update_option($key, $this->data);
228 }
229
230 return $this;
231 }
232
233 /**
234 * Update queue
235 *
236 * @since 2.4.5
237 *
238 * @param string $key Key.
239 * @param array $data Data.
240 *
241 * @return $this
242 */
243 public function update($key, $data)
244 {
245 if ( ! empty($data)) {
246 update_option($key, $data);
247 }
248
249 return $this;
250 }
251
252 /**
253 * Delete queue
254 *
255 * @since 2.4.5
256 *
257 * @param string $key Key.
258 *
259 * @return $this
260 */
261 public function delete($key)
262 {
263 delete_option($key);
264
265 return $this;
266 }
267
268 /**
269 * Is process running
270 *
271 * @since 2.4.5
272 *
273 * Check whether the current process is already running
274 * in a background process.
275 */
276 public function is_process_running()
277 {
278 if (get_transient($this->identifier . '_process_lock')) {
279 // Process already running.
280 return true;
281 }
282
283 return false;
284 }
285
286 /**
287 * Unlock process
288 *
289 * Unlock the process so that other instances can spawn.
290 *
291 * @since 2.4.5
292 *
293 * @return $this
294 */
295 protected function unlock_process()
296 {
297 delete_transient($this->identifier . '_process_lock');
298
299 return $this;
300 }
301
302 /**
303 * Task
304 *
305 * Override this method to perform any actions required on each
306 * queue item. Return the modified item for further processing
307 * in the next pass through. Or, return false to remove the
308 * item from the queue.
309 *
310 * @param array $update Update info
311 *
312 * @return mixed
313 */
314 protected function task($update)
315 {
316 // Pause upgrade immediately if admin pausing upgrades.
317 if ($this->is_paused_process()) {
318 wp_die();
319 }
320
321 if (empty($update)) {
322 return false;
323 }
324
325 // Delete cache.
326 self::flush_cache();
327
328 /* @var Give_Updates $give_updates */
329 $give_updates = Give_Updates::get_instance();
330 $resume_update = get_option(
331 'give_doing_upgrade',
332 // Default update.
333 [
334 'update_info' => $update,
335 'step' => 1,
336 'update' => 1,
337 'heading' => sprintf('Update %s of {update_count}', 1),
338 'percentage' => $give_updates->percentage,
339 'total_percentage' => 0,
340 ]
341 );
342
343 // Continuously skip update if previous update does not complete yet.
344 if (
345 $resume_update['update_info']['id'] !== $update['id'] &&
346 ! give_has_upgrade_completed($resume_update['update_info']['id'])
347 ) {
348 return $update;
349 }
350
351 // Set params.
352 $resume_update['update_info'] = $update;
353 $give_updates->step = absint($resume_update['step']);
354 $give_updates->update = absint($resume_update['update']);
355 $is_parent_update_completed = $give_updates->is_parent_updates_completed($update);
356
357 // Skip update if dependency update does not complete yet.
358 if (empty($is_parent_update_completed)) {
359 // @todo: set error when you have only one update with invalid dependency
360 if ( ! is_null($is_parent_update_completed)) {
361 return $update;
362 }
363
364 return false;
365 }
366
367 // Pause upgrade immediately if found following:
368 // 1. Running update number greater then total update count
369 // 2. Processing percentage greater then 100%
370 if ((
371 101 < $resume_update['total_percentage']) ||
372 ($give_updates->get_total_db_update_count() < $resume_update['update']) ||
373 ! in_array($resume_update['update_info']['id'], $give_updates->get_update_ids())
374 ) {
375 if ( ! $this->is_paused_process()) {
376 $give_updates->__pause_db_update(true);
377 }
378
379 update_option('give_upgrade_error', 1, false);
380
381 $log_data = 'Update Task' . "\n";
382 $log_data .= "Total update count: {$give_updates->get_total_db_update_count()}\n";
383 $log_data .= 'Update IDs: ' . print_r($give_updates->get_update_ids(), true);
384 $log_data .= 'Update: ' . print_r($resume_update, true);
385
386 Give()->logs->add('Update Error', $log_data, 0, 'update');
387
388 wp_die();
389 }
390
391 // Disable cache.
392 Give_Cache::disable();
393
394 try {
395 // Run update.
396 if (is_array($update['callback'])) {
397 $object = $update['callback'][0];
398 $method_name = $update['callback'][1];
399
400 $object->$method_name();
401 } else {
402 $update['callback']();
403 }
404 } catch (Exception $e) {
405 if ( ! $this->is_paused_process()) {
406 $give_updates->__pause_db_update(true);
407 }
408
409 $log_data = 'Update Task' . "\n";
410 $log_data .= print_r($resume_update, true) . "\n\n";
411 $log_data .= "Error\n {$e->getMessage()}";
412
413 Give()->logs->add('Update Error', $log_data, 0, 'update');
414 update_option('give_upgrade_error', 1, false);
415
416 wp_die();
417 }
418
419 // Set update info.
420 $doing_upgrade_args = [
421 'update_info' => $update,
422 'step' => ++$give_updates->step,
423 'update' => $give_updates->update,
424 'heading' => sprintf('Update %s of %s', $give_updates->update, get_option('give_db_update_count')),
425 'percentage' => $give_updates->percentage,
426 'total_percentage' => $give_updates->get_db_update_processing_percentage(),
427 ];
428
429 // Cache upgrade.
430 update_option('give_doing_upgrade', $doing_upgrade_args, false);
431
432 // Enable cache.
433 Give_Cache::enable();
434
435 // Check if current update completed or not.
436 if (give_has_upgrade_completed($update['id'])) {
437 return false;
438 }
439
440 return $update;
441 }
442
443 /**
444 * Complete
445 *
446 * Override if applicable, but ensure that the below actions are
447 * performed, or, call parent::complete().
448 */
449 public function complete()
450 {
451 if ($this->is_paused_process()) {
452 return false;
453 }
454
455 parent::complete();
456
457 delete_option('give_pause_upgrade');
458 delete_option('give_upgrade_error');
459 delete_option('give_db_update_count');
460 delete_option('give_doing_upgrade');
461 add_option('give_show_db_upgrade_complete_notice', 1, '', false);
462
463 // Flush cache.
464 Give_Cache::flush_cache(true);
465
466 if ($cache_keys = Give_Cache::get_options_like('')) {
467 Give_Cache::delete($cache_keys);
468 }
469 }
470
471 /**
472 * Get memory limit
473 *
474 * @return int
475 */
476 protected function get_memory_limit()
477 {
478 if (function_exists('ini_get')) {
479 $memory_limit = ini_get('memory_limit');
480 } else {
481 // Sensible default.
482 $memory_limit = '128M';
483 }
484
485 if ( ! $memory_limit || '-1' === $memory_limit) {
486 // Unlimited, set to 32GB.
487 $memory_limit = '32G';
488 }
489
490 return give_let_to_num($memory_limit);
491 }
492
493 /**
494 * Maybe process queue
495 *
496 * Checks whether data exists within the queue and that
497 * the process is not already running.
498 */
499 public function maybe_handle()
500 {
501 // Don't lock up other requests while processing
502 session_write_close();
503
504 if ($this->is_process_running() || $this->is_paused_process()) {
505 // Background process already running.
506 wp_die();
507 }
508
509 if ($this->is_queue_empty()) {
510 // No data to process.
511 wp_die();
512 }
513
514 check_ajax_referer($this->identifier, 'nonce');
515
516 $this->handle();
517
518 wp_die();
519 }
520
521 /**
522 * Handle
523 *
524 * Pass each queue item to the task handler, while remaining
525 * within server memory and time limit constraints.
526 */
527 protected function handle()
528 {
529 $this->lock_process();
530
531 do {
532 $batch = $this->get_batch();
533
534 foreach ($batch->data as $key => $value) {
535 $task = $this->task($value);
536
537 if (false !== $task) {
538 $batch->data[$key] = $task;
539 } else {
540 unset($batch->data[$key]);
541 }
542
543 if ($this->time_exceeded() || $this->memory_exceeded()) {
544 // Batch limits reached.
545 break;
546 }
547 }
548
549 // Update or delete current batch.
550 if ( ! empty($batch->data)) {
551 $this->update($batch->key, $batch->data);
552 } else {
553 $this->delete($batch->key);
554 }
555 } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty());
556
557 $this->unlock_process();
558
559 // Start next batch or complete process.
560 if ( ! $this->is_queue_empty()) {
561 // Dispatch only if ajax works.
562 if (give_test_ajax_works()) {
563 $this->dispatch();
564 }
565 } else {
566 $this->complete();
567 }
568
569 wp_die();
570 }
571
572
573 /**
574 * Check if backgound upgrade paused or not.
575 *
576 * @since 2.0
577 * @access public
578 * @return bool
579 */
580 public function is_paused_process()
581 {
582 // Delete cache.
583 wp_cache_delete('give_paused_batches', 'options');
584
585 $paused_batches = Give_Cache_Setting::get_option('give_paused_batches');
586
587 return ! empty($paused_batches);
588 }
589
590
591 /**
592 * Get identifier
593 *
594 * @since 2.0
595 * @access public
596 * @return mixed|string
597 */
598 public function get_identifier()
599 {
600 return $this->identifier;
601 }
602
603 /**
604 * Get cron identifier
605 *
606 * @since 2.0
607 * @access public
608 * @return mixed|string
609 */
610 public function get_cron_identifier()
611 {
612 return $this->cron_hook_identifier;
613 }
614
615
616 /**
617 * Flush background update related cache to prevent task to go to stalled state.
618 *
619 * @since 2.0.3
620 */
621 public static function flush_cache()
622 {
623 $options = [
624 'give_completed_upgrades',
625 'give_doing_upgrade',
626 'give_paused_batches',
627 'give_upgrade_error',
628 'give_db_update_count',
629 'give_pause_upgrade',
630 'give_show_db_upgrade_complete_notice',
631 ];
632
633 foreach ($options as $option) {
634 wp_cache_delete($option, 'options');
635 }
636 }
637 }
638