PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.8.6
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.8.6
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / BackgroundProcessing / WithQueueAwareness.php
wp-staging / Framework / BackgroundProcessing Last commit date
Exceptions 5 years ago Action.php 2 years ago BackgroundProcessingServiceProvider.php 2 years ago Demo.php 4 years ago FeatureDetection.php 2 years ago Queue.php 1 year ago QueueActionAware.php 4 years ago QueueProcessor.php 1 year ago WithQueueAwareness.php 1 year ago
WithQueueAwareness.php
198 lines
1 <?php
2
3 /**
4 * Provides methods to be aware of the queue system and its inner workings.
5 *
6 * @package WPStaging\Framework\BackgroundProcessing
7 */
8
9 namespace WPStaging\Framework\BackgroundProcessing;
10
11 use WP_Error;
12 use WPStaging\Framework\Facades\Hooks;
13
14 use function WPStaging\functions\debug_log;
15
16 /**
17 * Trait WithQueueAwareness
18 *
19 * @package WPStaging\Framework\BackgroundProcessing
20 */
21 trait WithQueueAwareness
22 {
23 /**
24 * Whether this Queue instance did fire the AJAX action request or not.
25 *
26 * @var bool
27 */
28 private $didFireAjaxAction = false;
29
30 /**
31 * Returns the Queue default priority that will be used to schedule actions when the
32 * priority is not specified or is specified as an invalid value.
33 *
34 * @return int The Queue default priority.
35 */
36 public static function getDefaultPriority()
37 {
38 return 0;
39 }
40
41 /**
42 * Fires a non-blocking request to the WordPress admin AJAX endpoint that will,
43 * in turn, trigger the processing of more Actions.
44 *
45 * @param mixed|null $bodyData An optional set of data to customize the processing request
46 * for. If not provided, then the request will be fired for the
47 * next available Actions (normal operations).
48 *
49 * @return bool A value that will indicate whether the request was correctly dispatched
50 * or not.
51 */
52 public function fireAjaxAction($bodyData = null)
53 {
54 if ($this->didFireAjaxAction) {
55 // Let's not fire the AJAX request more than once per HTTP request, per Queue.
56 return false;
57 }
58
59 $ajaxUrl = add_query_arg([
60 'action' => QueueProcessor::QUEUE_PROCESS_ACTION,
61 '_ajax_nonce' => wp_create_nonce(QueueProcessor::QUEUE_PROCESS_ACTION)
62 ], admin_url('admin-ajax.php'));
63
64 $useGetMethod = false;
65 $requestSent = false;
66 // If we are in a cron job, check if GET/POST method works and set it in a transient for caching
67 $useGetMethod = get_site_transient(QueueProcessor::TRANSIENT_REQUEST_GET_METHOD);
68 // Transient return false for non existing or expired values, for type safety we will use string 'Yes' or 'No' for GET method usage
69 if ($useGetMethod === false) {
70 // By default we use POST method, so if that doesn't work we will use GET method
71 $useGetMethod = $this->checkGetRequestNeededForQueue($ajaxUrl, $bodyData);
72 // We already sent the POST method request. Let not double sent request if we continue use POST method
73 $requestSent = !$useGetMethod;
74 // Let set the transient for 24 hours
75 set_site_transient(QueueProcessor::TRANSIENT_REQUEST_GET_METHOD, $useGetMethod ? 'Yes' : 'No', 60 * 60 * 24);
76 } else {
77 $useGetMethod = $useGetMethod === 'Yes';
78 }
79
80 // If request already sent let early bail
81 if ($requestSent) {
82 $this->didFireAjaxAction = true;
83
84 Hooks::doAction('wpstg_queue_fire_ajax_request', $this);
85
86 return true;
87 }
88
89 // If filter is present lets override it!
90 $useGetMethod = Hooks::applyFilters(QueueProcessor::FILTER_REQUEST_FORCE_GET_METHOD, $useGetMethod);
91
92 $response = wp_remote_request(esc_url_raw($ajaxUrl), [
93 'headers' => [
94 'X-WPSTG-Request' => QueueProcessor::QUEUE_PROCESS_ACTION,
95 ],
96 'method' => $useGetMethod ? 'GET' : 'POST',
97 'blocking' => false,
98 'timeout' => 0.01,
99 'cookies' => !empty($_COOKIE) ? $_COOKIE : [],
100 'sslverify' => apply_filters('https_local_ssl_verify', false),
101 'body' => $this->normalizeAjaxRequestBody($bodyData),
102 ]);
103
104 //debug_log('fireAjaxAction: ' . wp_json_encode($response, JSON_PRETTY_PRINT));
105
106 /*
107 * A non-blocking request will either return a WP_Error instance, or
108 * a mock response. The response is a mock as we cannot really build
109 * a good response without waiting for it to be processed from the server.
110 */
111 if ($response instanceof WP_Error) {
112 \WPStaging\functions\debug_log(json_encode([
113 'root' => 'Queue processing admin-ajax request failed.',
114 'class' => get_class($this),
115 'code' => $response->get_error_code(),
116 'message' => $response->get_error_message(),
117 'data' => $response->get_error_data()
118 ], JSON_PRETTY_PRINT));
119
120 return false;
121 }
122
123 $this->didFireAjaxAction = true;
124
125 /**
126 * Fires an Action to indicate the Queue did fire the AJAX request that will
127 * trigger side-processing in another PHP process.
128 *
129 * @param Queue $this A reference to the instance of the Queue that actually fired
130 * the AJAX request.
131 */
132 do_action('wpstg_queue_fire_ajax_request', $this);
133
134 return true;
135 }
136
137 /**
138 * Normalizes the data to be sent along the non-blocking AJAX request
139 * that will trigger the Queue processing of an Action.
140 *
141 * @param mixed|null $bodyData The data to normlize to a format suitable for
142 * the remote request.
143 *
144 * @return array The normalized body data to be sent along the non-blocking
145 * AJAX request.
146 */
147 private function normalizeAjaxRequestBody($bodyData)
148 {
149 $normalized = (array)$bodyData;
150
151 $normalized['_referer'] = __CLASS__;
152
153 return $normalized;
154 }
155
156 /**
157 * @param string $ajaxUrl
158 * @param mixed|null $bodyData
159 * @return bool
160 */
161 private function checkGetRequestNeededForQueue(string $ajaxUrl, $bodyData = null): bool
162 {
163 // Let send a blocking request to check if POST method works
164 $response = wp_remote_post(esc_url_raw($ajaxUrl), [
165 'headers' => [
166 'X-WPSTG-Request' => QueueProcessor::QUEUE_PROCESS_ACTION,
167 ],
168 'blocking' => true,
169 'timeout' => 10,
170 'cookies' => !empty($_COOKIE) ? $_COOKIE : [],
171 'sslverify' => apply_filters('https_local_ssl_verify', false),
172 'body' => $this->normalizeAjaxRequestBody($bodyData),
173 ]);
174
175 debug_log('checkGetRequestNeededForQueue: ' . wp_json_encode($response, JSON_PRETTY_PRINT), 'info', false);
176
177 // If we get WP_Error, then we can assume that POST method doesn't work
178 if ($response instanceof WP_Error) {
179 return true;
180 }
181
182 if (!is_array($response)) {
183 return false;
184 }
185
186 // If we get 404 response code, then we can assume that POST method doesn't work
187 if (
188 array_key_exists('response', $response) &&
189 array_key_exists('code', $response['response']) &&
190 $response['response']['code'] === 404
191 ) {
192 return true;
193 }
194
195 return false;
196 }
197 }
198