PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / trunk
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster vtrunk
2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 1.8.1 All 42 releases
sellkit / includes / core / update / db-updater.php

db-updater.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster trunk, at includes/core/update/db-updater.php

188 lines 4.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Sellkit\Core\Update;
4
5 use Sellkit\Database;
6
7 defined( 'ABSPATH' ) || die();
8
9 /**
10 * Class Data base Updater.
11 *
12 * @package Sellkit\Contact_Segmentation
13 * @SuppressWarnings(ExcessiveClassComplexity)
14 * @since 1.1.0
15 */
16 class Db_Updater extends \WP_Background_Process {
17
18 /**
19 * Whether this site already has migration batches queued or in progress.
20 *
21 * @since 2.4.1
22 * @return bool
23 */
24 public function has_pending_migrations() {
25 return ! $this->is_queue_empty();
26 }
27
28 /**
29 * SellKit db version.
30 *
31 * @since 1.1.0
32 * @var $db_version
33 */
34 public $db_version;
35
36 /**
37 * Queue Action.
38 *
39 * @since 1.1.0
40 * @var string
41 */
42 protected $action = 'sellkit-database-updater';
43
44 /**
45 * When set before the first save()->dispatch() from Install, multisite uses a short network-wide
46 * cooldown so not every subsite fires a loopback HTTP request at the same time after an update.
47 * Chained dispatch() calls from the background handler leave this false and are not gated.
48 *
49 * @var bool
50 */
51 public $gate_multisite_initial_loopback = false;
52
53 /**
54 * Network-wide cooldown in seconds for the initial multisite loopback spawn.
55 *
56 * @var int
57 */
58 protected $initial_loopback_gate_ttl = MINUTE_IN_SECONDS;
59
60 /**
61 * Override this method to perform any actions required on each
62 * queue item. Return the modified item for further processing
63 * in the next pass through. Or, return false to remove the
64 * item from the queue.
65 *
66 * @since 1.1.0
67 * @param mixed $data Queue item to iterate over.
68 */
69 protected function task( $data ) {
70 if ( empty( $data['callback_function'] ) || empty( $data['db_version'] ) ) {
71 return false;
72 }
73
74 $this->db_version = $data['db_version'];
75 $updater_functions = new Updater_Functions();
76
77 call_user_func( [ $updater_functions, $data['callback_function'] ] );
78
79 return false;
80 }
81
82 /**
83 * Spawn loopback to process the queue; on multisite optionally throttle initial storm across subsites.
84 *
85 * @since 2.4.1
86 * @return array|false|WP_Error
87 */
88 public function dispatch() {
89 if ( $this->gate_multisite_initial_loopback && is_multisite() ) {
90 $this->gate_multisite_initial_loopback = false;
91
92 // Allow one initial loopback at a time network-wide; other sites rely on cron until the cooldown expires.
93 if ( ! $this->acquire_multisite_initial_loopback_gate() ) {
94 $this->schedule_event();
95 return false;
96 }
97 }
98
99 return parent::dispatch();
100 }
101
102 /**
103 * Acquire the multisite loopback gate using the main site's options table.
104 *
105 * `add_option()` is backed by a unique index in `wp_options`, which makes it much safer than a
106 * get/set transient pair during concurrent requests across many subsites.
107 *
108 * @return bool
109 */
110 protected function acquire_multisite_initial_loopback_gate() {
111 $network_key = 'sellkit_ms_init_loopback_gate';
112 $expires_at = time() + $this->initial_loopback_gate_ttl;
113 $main_site_id = (int) get_main_site_id();
114 $switched = false;
115
116 if ( $main_site_id > 0 && get_current_blog_id() !== $main_site_id ) {
117 switch_to_blog( $main_site_id );
118 $switched = true;
119 }
120
121 $acquired = add_option( $network_key, $expires_at, '', false );
122
123 if ( ! $acquired ) {
124 $existing_expiry = (int) get_option( $network_key );
125
126 if ( $existing_expiry <= time() ) {
127 delete_option( $network_key );
128 $acquired = add_option( $network_key, $expires_at, '', false );
129 }
130 }
131
132 if ( $switched ) {
133 restore_current_blog();
134 }
135
136 return $acquired;
137 }
138
139 /**
140 * Complete
141 *
142 * Override if applicable, but ensure that the below actions are
143 * performed, or, call parent::complete().
144 *
145 * @since 1.1.0
146 */
147 protected function complete() {
148 parent::complete();
149
150 sellkit_update_option( 'current_db_version', $this->db_version );
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 * @since 2.3.3
160 */
161 public function maybe_handle() {
162 // Don't lock up other requests while processing.
163 session_write_close();
164
165 if ( ! current_user_can( 'manage_options' ) ) {
166 wp_send_json_error( 'Unauthorized', 403 );
167
168 exit;
169 }
170
171 if ( $this->is_process_running() ) {
172 // Background process already running.
173 wp_die();
174 }
175
176 if ( $this->is_queue_empty() ) {
177 // No data to process.
178 wp_die();
179 }
180
181 check_ajax_referer( $this->identifier, 'nonce' );
182
183 $this->handle();
184
185 wp_die();
186 }
187 }
188