PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 2.8.23.4
Pods – Custom Content Types and Fields v2.8.23.4
2.7.31.4 2.8.23.5 2.9.19.5 3.0.10.5 3.1.4.3 3.2.8.4 3.3.9.2 2.8.23.4 2.9.19.4 3.0.10.4 3.1.4.2 3.2.8.3 3.3.9.1 trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / tribe-common / src / Tribe / Process / Handler.php
pods / tribe-common / src / Tribe / Process Last commit date
Handler.php 2 weeks ago Post_Thumbnail_Setter.php 2 weeks ago Queue.php 2 weeks ago Tester.php 2 weeks ago
Handler.php
362 lines
1 <?php
2
3 /**
4 * Class Tribe__Process__Handler
5 *
6 * The base class for all The Events Calendar async process handlers.
7 *
8 * @since 4.7.12
9 * @since 4.9.5 Removed dependency on `WP_Async_Request` class.
10 *
11 * @see Tribe__Service_Providers__Processes for more insight about this class utility.
12 */
13 abstract class Tribe__Process__Handler {
14 /**
15 * The default handler action name.
16 *
17 * @var string
18 */
19 protected $action = 'async_request';
20
21 /**
22 * The handler identifier.
23 *
24 * @var string
25 */
26 protected $identifier;
27
28 /**
29 * An array of data for the process.
30 *
31 * @var array
32 */
33 protected $data = [];
34
35 /**
36 * This handler cron identifier.
37 *
38 * @var string
39 */
40 protected $healthcheck_cron_hook_id;
41 /**
42 * @var string The common identified prefix to all our async process handlers.
43 */
44 protected $prefix = 'tribe_process';
45 /**
46 * An instance of the object abstracting the feature detection functionality.
47 *
48 * @var Tribe__Feature_Detection
49 */
50 protected $feature_detection;
51
52 /**
53 * An array of query arguments that should be used in place of the default ones.
54 * Extending classes can override/set this to replace the default entirely.
55 *
56 * @var array
57 */
58 protected $query_args;
59
60 /**
61 * The absolute URL that should be used to POST requests.
62 * Extending classes can override/set this to replace the default entirely.
63 *
64 * @var string
65 */
66 protected $query_url;
67
68 /**
69 * An array of arguments that should be used as body of the POST request.
70 * Extending classes can override/set this to replace the default entirely.
71 *
72 * @var array
73 */
74 protected $post_args;
75
76 /**
77 * Tribe__Process__Handler constructor.
78 *
79 * @since 4.7.12
80 */
81 public function __construct() {
82 $class = get_class( $this );
83 $this->action = call_user_func( [ $class, 'action' ] );
84 $this->identifier = $this->prefix . '_' . $this->action;
85
86 add_action( 'wp_ajax_' . $this->identifier, [ $this, 'maybe_handle' ] );
87
88 /**
89 * Filters whether background processing should be triggered and handled on
90 * non-private AJAX requests as the ones triggered by a non logged in user.
91 * Defaults to `true` to exploit any possible chance to process.
92 *
93 * @since 4.9.5
94 *
95 * @param bool $allow_nopriv Whether background processing should be triggered and handled on
96 * non-private AJAX requests or not.
97 * @param static $this This handler instance.
98 */
99 $allow_nopriv = apply_filters( 'tribe_process_allow_nopriv_handling', true, $this );
100
101 if ( $allow_nopriv ) {
102 add_action( 'wp_ajax_nopriv_' . $this->identifier, [ $this, 'maybe_handle' ] );
103 }
104
105 $this->healthcheck_cron_hook_id = $this->identifier;
106 $this->feature_detection = tribe( 'feature-detection' );
107
108 /*
109 * This object might have been built while processing crons so
110 * we hook on the the object cron identifier to handle the task
111 * if the cron-triggered action ever fires.
112 */
113 add_action( $this->healthcheck_cron_hook_id, [ $this, 'maybe_handle' ] );
114 }
115
116 /**
117 * Returns the async process action name.
118 *
119 * Extending classes must override this method to return their unique action slug.
120 *
121 * @since 4.7.12
122 *
123 * @return string
124 *
125 * @throws RuntimeException If the extending class does not override this method.
126 */
127 public static function action() {
128 $class = static::class;
129 throw new RuntimeException( "Class {$class} should override the `action` method to define its own unique identifier." );
130 }
131
132 /**
133 * Handles the process request if valid and if authorized.
134 *
135 * @since 4.7.23
136 * @since 4.9.5 Pulled the `maybe_handle` implementation of the `WP_Async_Request` class.
137 *
138 * @param array|null $data_source A source of data if not provided in the request; used for
139 * cron-based fallback.
140 */
141 public function maybe_handle( $data_source = null ) {
142 $data_source = (array) $data_source;
143
144 if ( $this->feature_detection->supports_async_process() ) {
145 // Don't lock up other requests while processing.
146 session_write_close();
147
148 check_ajax_referer( $this->identifier, 'nonce' );
149
150 // Let's make sure to hydrate date from the request if not set.
151 if ( count( array_filter( $data_source ) ) < 1 ) {
152 $data_source = $_POST;
153 }
154
155 do_action(
156 'tribe_log',
157 'debug',
158 $this->identifier,
159 [
160 'action' => 'async_handling',
161 'data_source' => $data_source,
162 'payload' => $_POST,
163 ]
164 );
165
166 $this->handle( $data_source );
167
168 wp_die();
169 }
170
171 /*
172 * If the environment does not support AJAX-based async processing then
173 * fallback to use the cron-based approach and just call the handle method
174 * removing it first from the action to avoid multiple calls.
175 */
176 wp_clear_scheduled_hook( $this->healthcheck_cron_hook_id, [ $data_source ] );
177
178 do_action(
179 'tribe_log',
180 'debug',
181 $this->identifier,
182 array_merge( [ 'action' => 'cron_handling' ], $data_source ) );
183
184 $this->handle( $data_source );
185 }
186
187 /**
188 * Overrides the base `dispatch` method to allow for constants and/or environment vars to run
189 * async requests in sync mode.
190 *
191 * @since 4.7.12
192 * @since 4.9.5 Pulled `dispatch` method logic from the `WP_Async_Request` class.
193 *
194 * @return mixed
195 */
196 public function dispatch() {
197 if (
198 ( defined( 'TRIBE_NO_ASYNC' ) && true === TRIBE_NO_ASYNC )
199 || true === (bool) getenv( 'TRIBE_NO_ASYNC' )
200 ) {
201 do_action( 'tribe_log', 'debug', $this->identifier, [ 'action' => 'sync_handle', 'data' => $this->data ] );
202
203 return $this->sync_handle( $this->data );
204 }
205
206 if ( $this->feature_detection->supports_async_process() ) {
207 $url = add_query_arg( $this->get_query_args(), $this->get_query_url() );
208 $args = $this->get_post_args();
209
210 do_action( 'tribe_log', 'debug', $this->identifier, [ 'action' => 'async_dispatch', 'data' => $this->data ] );
211
212 return wp_remote_post( esc_url_raw( $url ), $args );
213 }
214
215 /*
216 * If async AJAX-based processing is not available then we "dispatch"
217 * by scheduling a single cron event immediately (as soon as possible)
218 * for this handler cron identifier.
219 */
220 if ( ! wp_next_scheduled( $this->healthcheck_cron_hook_id, [ $this->data ] ) ) {
221 // Schedule the event to happen as soon as possible.
222 $scheduled = wp_schedule_single_event( time() - 1, $this->healthcheck_cron_hook_id, [ $this->data ] );
223
224 if ( false === $scheduled ) {
225 /** @var Tribe__Log__Logger $logger */
226 $logger = tribe( 'logger' );
227 $class = get_class( $this );
228 $src = call_user_func( [ $class, 'action' ] );
229 $logger->log( 'Could not schedule event for cron-based handling', Tribe__Log::ERROR, $src );
230
231 do_action(
232 'tribe_log',
233 'error',
234 $this->identifier,
235 [ 'action' => 'schedule_cron', 'data' => $this->data ]
236 );
237 }
238
239 do_action(
240 'tribe_log',
241 'debug',
242 $this->identifier,
243 [ 'action' => 'schedule_cron', 'data' => $this->data ]
244 );
245 }
246
247 return true;
248 }
249
250 /**
251 * Handles the process immediately, not in an async manner.
252 *
253 * @since 4.7.12
254 *
255 * @param array|null $data_source If not provided the method will read the handler data from the
256 * request array.
257 *
258 * @return mixed|null The result of the synchronous handling.
259 */
260 abstract public function sync_handle( array $data_source = null );
261
262 /**
263 * Returns an array of arguments that will be used to send the POST request.
264 *
265 * @since 4.9.5 Pulled from the `WP_Async_Request` class.
266 *
267 * @return array An array of arguments for the POST request.
268 */
269 protected function get_query_args() {
270 if ( null !== $this->query_args ) {
271 return $this->query_args;
272 }
273
274 return [
275 'action' => $this->identifier,
276 'nonce' => wp_create_nonce( $this->identifier ),
277 ];
278 }
279
280 /**
281 * Returns the URL that wil be used to post the request.
282 *
283 * @since 4.9.5 Pulled from the `WP_Async_Request` class.
284 *
285 * @return string The URL that will be used to POST the dispatch request; defaults
286 * to the `admin-ajax.php` one.
287 */
288 protected function get_query_url() {
289 if ( null !== $this->query_url ) {
290 return $this->query_url;
291 }
292
293 return admin_url( 'admin-ajax.php' );
294 }
295
296 /**
297 * Returns the arguments that will be used to send the POST request.
298 *
299 * @since 4.9.5 Pulled from the `WP_Async_Request` class.
300 *
301 * @return array An array of arguments that will be used to send the POST request.
302 */
303 protected function get_post_args() {
304 if ( null !== $this->post_args ) {
305 return $this->post_args;
306 }
307
308 return [
309 'timeout' => 0.01,
310 'blocking' => false,
311 'body' => $this->data,
312 'cookies' => $_COOKIE,
313 'sslverify' => apply_filters( 'https_local_ssl_verify', false ),
314 ];
315 }
316
317 /**
318 * Returns this handler cron hook identifier.
319 *
320 * The handler cron hook identifier is the one that the handler
321 * will use to schedule a single cron event when the `dispatch`
322 * method is called and the environment does not support async
323 * processing.
324 *
325 * @since 4.7.23
326 *
327 * @return string The complete cron hook name (identifier) for
328 * this handler.
329 */
330 public function get_healthcheck_cron_hook_id() {
331 return $this->healthcheck_cron_hook_id;
332 }
333
334 /**
335 * Sets the that will be used during the request.
336 *
337 * @since 4.9.5 Pulled from the `WP_Async_Request` class.
338 *
339 * @param array $data Data.
340 *
341 * @return $this This handler instance.
342 */
343 public function data( $data ) {
344 $this->data = $data;
345
346 return $this;
347 }
348
349 /**
350 * Handles the request and performs an action.
351 *
352 * @since 4.9.5 Pulled from the `WP_Async_Request` class.
353 *
354 * @param array|null $data_source A source of data if not provided in the request; used for
355 * cron-based fallback.
356 *
357 * @return null|array Depending on the context of the call, cron or async, either the result
358 * of the handling (cron) or nothing (async).
359 */
360 abstract protected function handle( array $data_source = null );
361 }
362