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 / Context.php
pods / tribe-common / src / Tribe Last commit date
Admin 2 weeks ago Ajax 2 weeks ago Asset 2 weeks ago Context 2 weeks ago Customizer 2 weeks ago Debug_Bar 2 weeks ago Dialog 2 weeks ago Documentation 2 weeks ago Duplicate 2 weeks ago Editor 2 weeks ago Image 2 weeks ago JSON_LD 2 weeks ago Languages 2 weeks ago Log 2 weeks ago Meta 2 weeks ago Models 2 weeks ago PUE 2 weeks ago Process 2 weeks ago Promoter 2 weeks ago REST 2 weeks ago Repository 2 weeks ago Service_Providers 2 weeks ago Shortcode 2 weeks ago Support 2 weeks ago Tabbed_View 2 weeks ago Tooltip 2 weeks ago Traits 2 weeks ago Utils 2 weeks ago Validator 2 weeks ago Widget 2 weeks ago Abstract_Deactivation.php 2 weeks ago Abstract_Plugin_Register.php 2 weeks ago App_Shop.php 2 weeks ago Assets.php 2 weeks ago Assets_Pipeline.php 2 weeks ago Autoloader.php 2 weeks ago Cache.php 2 weeks ago Cache_Listener.php 2 weeks ago Changelog_Reader.php 2 weeks ago Container.php 2 weeks ago Context.php 2 weeks ago Cost_Utils.php 2 weeks ago Credits.php 2 weeks ago Customizer.php 2 weeks ago DB_Lock.php 2 weeks ago Data.php 2 weeks ago Date_Utils.php 2 weeks ago Db.php 2 weeks ago Debug.php 2 weeks ago Dependency.php 2 weeks ago Deprecation.php 2 weeks ago Editor.php 2 weeks ago Error.php 2 weeks ago Exception.php 2 weeks ago Extension.php 2 weeks ago Extension_Loader.php 2 weeks ago Feature_Detection.php 2 weeks ago Field.php 2 weeks ago Field_Conditional.php 2 weeks ago Freemius.php 2 weeks ago Log.php 2 weeks ago Main.php 2 weeks ago Notices.php 2 weeks ago Plugin_Meta_Links.php 2 weeks ago Plugins.php 2 weeks ago Plugins_API.php 2 weeks ago Post_History.php 2 weeks ago Post_Transient.php 2 weeks ago Promise.php 2 weeks ago Repository.php 2 weeks ago Rewrite.php 2 weeks ago Settings.php 2 weeks ago Settings_Manager.php 2 weeks ago Settings_Tab.php 2 weeks ago Simple_Table.php 2 weeks ago Support.php 2 weeks ago Tabbed_View.php 2 weeks ago Template.php 2 weeks ago Template_Factory.php 2 weeks ago Template_Part_Cache.php 2 weeks ago Templates.php 2 weeks ago Terms.php 2 weeks ago Timezones.php 2 weeks ago Tracker.php 2 weeks ago Updater.php 2 weeks ago Validate.php 2 weeks ago View_Helpers.php 2 weeks ago
Context.php
1644 lines
1 <?php
2
3 use Tribe__Utils__Array as Arr;
4
5 /**
6 * Class Tribe__Context
7 *
8 * @since 4.7.7
9 * @since 4.9.5 Made the context immutable.
10 */
11 class Tribe__Context {
12
13 /**
14 * The value that will be used to indicate no value was found in any location while trying to read it.
15 *
16 * @since 4.9.11
17 */
18 const NOT_FOUND = '__not_found__';
19
20 /**
21 * The key to locate a context value as the value of a request variable.
22 *
23 * @since 4.9.11
24 */
25 const REQUEST_VAR = 'request_var';
26
27 /**
28 * The key to locate a context value as the value of a Tribe option.
29 *
30 * @since 4.9.11
31 */
32 const TRIBE_OPTION = 'tribe_option';
33
34 /**
35 * The key to locate a context value as the value of an option.
36 *
37 * @since 4.9.11
38 */
39 const OPTION = 'option';
40
41 /**
42 * The key to locate a context value as the value of a transient.
43 *
44 * @since 4.9.11
45 */
46 const TRANSIENT = 'transient';
47
48 /**
49 * The key to locate a context value as the value of the main query (global `$wp_query`) query var.
50 *
51 * @since 4.9.11
52 */
53 const QUERY_VAR = 'query_var';
54
55 /**
56 * The key to locate a context value as the value of the main query (global `$wp_query`) property.
57 *
58 * @since 4.9.11
59 */
60 const QUERY_PROP = 'query_prop';
61
62 /**
63 * The key to locate a context value as the value of the main query (global `$wp_query`) method return value.
64 *
65 * @since 4.9.20
66 */
67 const QUERY_METHOD = 'query_method';
68
69 /**
70 * The key to locate a context value as the value of a constant.
71 *
72 * @since 4.9.11
73 */
74 const CONSTANT = 'constant';
75
76 /**
77 * The key to locate a context value as a static class property.
78 *
79 * @since 4.9.11
80 */
81 const STATIC_PROP = 'static_prop';
82
83 /**
84 * The key to locate a context value as property of an object.
85 *
86 * @since 4.9.11
87 */
88 const PROP = 'prop';
89
90 /**
91 * The key to locate a context value as result running a static class method.
92 *
93 * @since 4.9.11
94 */
95 const STATIC_METHOD = 'static_method';
96
97 /**
98 * The key to locate a context value as result running a method on an object.
99 *
100 * @since 4.9.11
101 */
102 const METHOD = 'method';
103
104 /**
105 * The key to locate a context value as result running a callback function (e.g. a callable, a closure).
106 *
107 * @since 4.9.11
108 */
109 const FUNC = 'func';
110
111 /**
112 * The key to locate a context value as result of reading a global value.
113 *
114 * @since 4.9.11
115 */
116 const GLOBAL_VAR = 'global_var';
117
118 /**
119 * The key to locate a context value as result of an `apply_filters` call.
120 *
121 * @since 4.9.11
122 */
123 const FILTER = 'filter';
124
125 /**
126 * The key to locate a context value among the values parsed by `WP::parse_request`.
127 *
128 * @since 4.9.11
129 */
130 const WP_PARSED = 'wp_parsed';
131
132 /**
133 * The key to locate a context value among the values in the query mached by `WP::parse_request`.
134 *
135 * @since 4.9.11
136 */
137 const WP_MATCHED_QUERY = 'wp_matched_query';
138
139 /**
140 * The key to indicate a location should be read by applying a callback to the value of another context location.
141 *
142 * @since 4.9.18
143 */
144 const LOCATION_FUNC = 'location_func';
145
146 /*
147 *
148 * An array defining the properties the context will be able to read and (dangerously) write.
149 *
150 * This is the configuration that should be modified to add/remove/modify values and locations
151 * provided by the global context.
152 * Each entry has the shape [ <key> => [ 'read' => <read_locations>, 'write' => <write_locations> ] ].
153 * The key is used to identify the property that will be accessible with the `get` and
154 * 'dangerously_set_global_context' method, e.g. `$context->get( 'event_display', 'list' );`.
155 * The locations is a list of locations the context will search, top to bottom, left to right, to find a value that's
156 * not empty or the default one, here's a list of supported lookup locations:
157 *
158 * request_var - look into $_GET, $_POST, $_PUT, $_DELETE, $_REQUEST.
159 * query_var - get the value from the main WP_Query object query vars.
160 * query_prop - get the value from a property of the main WP_Query object.
161 * tribe_option - get the value from a Tribe option.
162 * option - get the value from a database option.
163 * transient - get the value from a transient.
164 * constant - get the value from a constant, can also be a class constant with <class>::<const>.
165 * global_var - get the value from a global variable
166 * static_prop - get the value from a class static property, format: `array( $class, $prop )`.
167 * prop - get the value from a tribe() container binding, format `array( $binding, $prop )`.
168 * static_method - get the value from a class static method.
169 * method - get the value calling a method on a tribe() container binding.
170 * func - get the value from a function or a closure.
171 * filter - get the value by applying a filter.
172 * location_func - get the value by applying a callback to the value of a location.
173 *
174 * For each location additional arguments can be specified:
175 * orm_arg - if `false` then the location will never produce an ORM argument, if provided the ORM arg produced bye the
176 * location will have this name.
177 * orm_transform - if provided the value of the location will be obtained by passing it as an argument to a callable.
178 *
179 * As the Context locations increase in number it would be impractical to define them inline here.
180 * The locations will be loaded by the `Tribe__Context::populate_locations` method from the `Context/locations.php`
181 * file.
182 *
183 * @var array
184 */
185 protected static $locations = [];
186
187 /**
188 * A utility static property keeping track of write locations that
189 * will be defined as associative arrays.
190 *
191 * @var array
192 */
193 protected static $associative_locations = [
194 self::TRANSIENT,
195 self::METHOD,
196 self::STATIC_METHOD,
197 self::PROP,
198 self::STATIC_PROP,
199 ];
200
201 /**
202 * Whether the static dynamic locations were set or not.
203 *
204 * @var bool
205 */
206 protected static $did_populate_locations = false;
207
208 /**
209 * A list of override locations to read and write from.
210 *
211 * This list has the same format and options as the static `$locations` property
212 * but allows a context instance to override, or add, read and write locations.
213 *
214 * @var array
215 */
216 protected $override_locations = [];
217
218 /**
219 * Whether the context of the current HTTP request is an AJAX one or not.
220 *
221 * @var bool
222 */
223 protected $doing_ajax;
224
225 /**
226 * Whether the context of the current HTTP request is a Cron one or not.
227 *
228 * @var bool
229 */
230 protected $doing_cron;
231
232 /**
233 * A request-based array cache to store the values fetched by the context.
234 *
235 * @var array
236 */
237 protected $request_cache = [];
238
239 /**
240 * Whether this context should use the default locations or not.
241 * This flag property is set to `false` when a context is obtained using
242 * the `set_locations` method; it will otherwise be set to `true`.
243 *
244 * @var bool
245 */
246 protected $use_default_locations = true;
247
248 /**
249 * Whether we are currently creating a new post, a post of post type(s) or not.
250 *
251 * @since 4.7.7
252 *
253 * @param null $post_type The optional post type to check.
254 *
255 * @return bool Whether we are currently creating a new post, a post of post type(s) or not.
256 */
257 public function is_new_post( $post_type = null ) {
258 global $pagenow;
259 $is_new = 'post-new.php' === $pagenow;
260
261 return $is_new && $this->is_editing_post( $post_type );
262 }
263
264 /**
265 * Whether we are currently editing a post(s), post type(s) or not.
266 *
267 * @since 4.7.7
268 *
269 * @param null|array|string|int $post_or_type A post ID, post type, an array of post types or post IDs, `null`
270 * to just make sure we are currently editing a post.
271 *
272 * @return bool
273 */
274 public function is_editing_post( $post_or_type = null ) {
275 global $pagenow;
276 $is_new = 'post-new.php' === $pagenow;
277 $is_post = 'post.php' === $pagenow;
278 $is_editing = 'edit.php' === $pagenow;
279
280 if ( ! ( $is_new || $is_post || $is_editing ) ) {
281 return false;
282 }
283
284 if ( ! empty( $post_or_type ) ) {
285 $lookup = [ $_GET, $_POST, $_REQUEST ];
286
287 $current_post = Tribe__Utils__Array::get_in_any( $lookup, 'post', get_post() );
288
289 if ( is_numeric( $post_or_type ) ) {
290
291 $post = $is_post ? get_post( $post_or_type ) : null;
292
293 return ! empty( $post ) && $post == $current_post;
294 }
295
296 $post_types = is_array( $post_or_type ) ? $post_or_type : [ $post_or_type ];
297
298 $post = $is_post ? get_post( $current_post ) : null;
299
300 if ( count( array_filter( $post_types, 'is_numeric' ) ) === count( $post_types ) ) {
301 return ! empty( $post ) && in_array( $post->ID, $post_types );
302 }
303
304 if ( $is_post && $post instanceof WP_Post ) {
305 $post_type = $post->post_type;
306 } else {
307 $post_type = Tribe__Utils__Array::get_in_any( $lookup, 'post_type', 'post' );
308 }
309
310 return (bool) count( array_intersect( $post_types, [ $post_type ] ) );
311 }
312
313 return $is_new || $is_post;
314 }
315
316 /**
317 * Helper function to indicate whether the current execution context is AJAX.
318 *
319 * This method exists to allow us test code that behaves differently depending on the execution
320 * context.
321 *
322 * @since 4.7.12
323 * @since 4.9.5 Removed the $doing_ajax parameter.
324 *
325 * @return boolean
326 */
327 public function doing_ajax() {
328 return function_exists( 'wp_doing_ajax' )
329 ? wp_doing_ajax()
330 : defined( 'DOING_AJAX' ) && DOING_AJAX;
331 }
332
333 /**
334 * Checks whether the context of the current HTTP request is a Cron one or not.
335 *
336 * @since 4.7.23
337 * @since 4.9.5 Removed the $doing_cron parameter.
338 *
339 * @return bool Whether the context of the current HTTP request is a Cron one or not.
340 */
341 public function doing_cron() {
342 return function_exists( 'wp_doing_cron' )
343 ? wp_doing_cron()
344 : defined( 'DOING_CRON' ) && DOING_CRON;
345 }
346
347 /**
348 * Gets a value reading it from the location(s) defined in the `Tribe__Context::$props
349 *
350 * @since 4.9.5
351 *
352 * @param string $key The key of the variable to fetch.
353 * @param mixed|null $default The default value to return if not found.
354 * @param bool $force Whether to force the re-fetch of the value from the context or
355 * not; defaults to `false`.
356 *
357 * @return mixed The value from the first location that can provide it or the default
358 * value if not found.
359 */
360 public function get( $key, $default = null, $force = false ) {
361 /**
362 * Filters the value of a context variable skipping all of its logic.
363 *
364 * @since 4.9.5
365 *
366 * @param mixed $value The value for the key before it's fetched from the context.
367 * @param string $key The key of the value to fetch from the context.
368 * @param mixed $default The default value that should be returned if the value is
369 * not set in the context.
370 * @param bool $force Whether to force the re-fetch of the value from the context or
371 * not; defaults to `false`.
372 */
373 $value = apply_filters( "tribe_context_pre_{$key}", null, $key, $default, $force );
374 if ( null !== $value ) {
375 return $value;
376 }
377
378 $value = $default;
379 $locations = $this->get_locations();
380 $found = false;
381
382 if ( ! $force && isset( $this->request_cache[ $key ] ) ) {
383 $value = $this->request_cache[ $key ];
384 } elseif ( ! empty( $locations[ $key ]['read'] ) ) {
385 foreach ( $locations[ $key ]['read'] as $location => $keys ) {
386 $the_value = $this->$location( (array) $keys, $default );
387
388 if ( $default !== $the_value && static::NOT_FOUND !== $the_value ) {
389 $found = true;
390 $value = $the_value;
391 break;
392 }
393 }
394 }
395
396 /**
397 * Filters the value fetched from the context for a key.
398 *
399 * Useful for testing and local override.
400 *
401 * @since 4.9.5
402 *
403 * @param mixed $value The value as fetched from the context.
404 */
405 $value = apply_filters( "tribe_context_{$key}", $value );
406
407 // Only cache if the value was found.
408 if ( $found ) {
409 $this->request_cache[ $key ] = $value;
410 }
411
412 return $value;
413 }
414
415 /**
416 * Alters the context.
417 *
418 * Due to its immutable nature setting values on the context will NOT modify the
419 * context but return a modified clone.
420 * If you need to modify the global context update the location(s) it should read from
421 * and call the `refresh` method.
422 * Example: `$widget_context = tribe_context()->alter( $widget_args );`.
423 *
424 * @since 4.9.5
425 *
426 * @param array $values An associative array of key-value pairs to modify the context.
427 *
428 * @return \Tribe__Context A clone, with modified, values, of the context the method was called on.
429 */
430 public function alter( array $values ) {
431 $clone = clone $this;
432
433 $clone->request_cache = array_merge( $clone->request_cache, $values );
434
435 return $clone;
436 }
437
438 /**
439 * Clears the context cache forcing a re-fetch of the variables from the context.
440 *
441 * @since 4.9.5
442 *
443 * @param string $key An optional specific key to refresh, if passed only this key
444 * will be refreshed.
445 */
446 public function refresh( $key = null ) {
447 if ( null !== $key ) {
448 unset( $this->request_cache[ $key ] );
449 } else {
450 $this->request_cache = [];
451 }
452 }
453
454 /**
455 * Returns the read and write locations set on the context.
456 *
457 * @since 4.9.5
458 *
459 * @return array An array of read and write location in the shape of the `Tribe__Context::$locations` one,
460 * `[ <location> => [ 'read' => <read_locations>, 'write' => <write_locations> ] ]`.
461 */
462 public function get_locations() {
463 $this->populate_locations();
464
465 $locations = $this->use_default_locations
466 ? array_merge( self::$locations, $this->override_locations )
467 : $this->override_locations;
468
469 if ( $this->use_default_locations ) {
470 /**
471 * Filters the locations registered in the Context.
472 *
473 * @since 4.10.2
474 *
475 * @param $locations array An array of read and write location in the shape of the `Tribe__Context::$locations` one,
476 * `[ <location> => [ 'read' => <read_locations>, 'write' => <write_locations> ] ]`.
477 * @param $context Tribe__Context Current instance of the context.
478 */
479 $locations = apply_filters( 'tribe_context_locations', $locations, $this );
480 }
481
482 return $locations;
483 }
484
485 /**
486 * Reads the value from one or more $_REQUEST vars.
487 *
488 * @since 4.9.5
489 *
490 * @param array $request_vars The list of request vars to lookup, in order.
491 * @param mixed $default The default value to return.
492 *
493 * @return mixed The first valid value found or the default value.
494 */
495 protected function request_var( array $request_vars, $default ) {
496 $value = $default;
497
498 foreach ( $request_vars as $request_var ) {
499 $the_value = tribe_get_request_var( $request_var, self::NOT_FOUND );
500 if ( $the_value !== self::NOT_FOUND ) {
501 $value = $the_value;
502 break;
503 }
504 }
505
506 return $value;
507 }
508
509 /**
510 * Reads the value from one or more global WP_Query object query variables.
511 *
512 * @since 4.9.5
513 *
514 * @param array $query_vars The list of query vars to look up, in order.
515 * @param mixed $default The default value to return.
516 *
517 * @return mixed The first valid value found or the default value.
518 */
519 protected function query_var( array $query_vars, $default ) {
520 $value = $default;
521
522 global $wp_query;
523
524 if ( ! $wp_query instanceof \WP_Query ) {
525 return $value;
526 }
527
528 foreach ( $query_vars as $query_var ) {
529 $the_value = $wp_query->get( $query_var, self::NOT_FOUND );
530 if ( $the_value !== self::NOT_FOUND ) {
531 $value = $the_value;
532 break;
533 }
534 }
535
536 return $value;
537 }
538
539 /**
540 * Reads the value from one or more global WP_Query object properties.
541 *
542 * @since 4.9.5
543 *
544 * @param array $query_props The list of properties to look up, in order.
545 * @param mixed $default The default value to return.
546 *
547 * @return mixed The first valid value found or the default value.
548 */
549 protected function query_prop( array $query_props, $default ) {
550 $value = $default;
551
552 global $wp_query;
553 foreach ( $query_props as $query_prop ) {
554 $the_value = isset( $wp_query->{$query_prop} ) ? $wp_query->{$query_prop} : self::NOT_FOUND;
555 if ( $the_value !== self::NOT_FOUND ) {
556 $value = $the_value;
557 break;
558 }
559 }
560
561 return $value;
562 }
563
564 /**
565 * Reads the value from one more more `tribe_option`s.
566 *
567 * @since 4.9.5
568 *
569 * @param array $tribe_options The list of `tribe_option`s to lookup, in order.
570 * @param mixed $default The default value to return.
571 *
572 * @return mixed The first valid value found or the default value.
573 */
574 protected function tribe_option( array $tribe_options, $default ) {
575 $value = $default;
576
577 foreach ( $tribe_options as $option_name ) {
578 $the_value = tribe_get_option( $option_name, self::NOT_FOUND );
579 if ( $the_value !== self::NOT_FOUND ) {
580 $value = $the_value;
581 break;
582 }
583 }
584
585 return $value;
586 }
587
588 /**
589 * Reads the value from one or more options.
590 *
591 * @since 4.9.5
592 *
593 * @param array $options The list of options to lookup, in order.
594 * @param mixed $default The default value to return.
595 *
596 * @return mixed The first valid value found or the default value.
597 */
598 protected function option( array $options, $default ) {
599 $value = $default;
600
601 foreach ( $options as $option_name ) {
602 $the_value = get_option( $option_name, self::NOT_FOUND );
603 if ( $the_value !== self::NOT_FOUND ) {
604 $value = $the_value;
605 break;
606 }
607 }
608
609 return $value;
610 }
611
612 /**
613 * Reads the value from one or more transients.
614 *
615 * @since 4.9.5
616 *
617 * @param array $transients The list of transients to lookup, in order.
618 * @param mixed $default The default value to return.
619 *
620 * @return mixed The first valid value found or the default value.
621 */
622 protected function transient( array $transients, $default ) {
623 $value = $default;
624
625 foreach ( $transients as $transient ) {
626 $the_value = get_transient( $transient );
627 if ( false !== $the_value ) {
628 $value = $the_value;
629 /*
630 * This will fail when the value is actually `false`.
631 */
632 break;
633 }
634 }
635
636 return $value;
637 }
638
639 /**
640 * Reads the value from one or more constants.
641 *
642 * @since 4.9.5
643 *
644 * @param array $constants The list of constants to lookup, in order.
645 * @param mixed $default The default value to return.
646 *
647 * @return mixed The first valid value found or the default value.
648 */
649 protected function constant( array $constants, $default ) {
650 $value = $default;
651
652 foreach ( $constants as $constant ) {
653 $the_value = defined( $constant ) ? constant( $constant ) : self::NOT_FOUND;
654 if ( $the_value !== self::NOT_FOUND ) {
655 $value = $the_value;
656 break;
657 }
658 }
659
660 return $value;
661 }
662
663 /**
664 * Reads the value from one or more global variable.
665 *
666 * @since 4.9.5
667 *
668 * @param array $global_vars The list of global variables to look up, in order.
669 * @param mixed $default The default value to return.
670 *
671 * @return mixed The first valid value found or the default value.
672 */
673 protected function global_var( array $global_vars, $default ) {
674 $value = $default;
675
676 foreach ( $global_vars as $var ) {
677 $the_value = isset( $GLOBALS[ $var ] ) ? $GLOBALS[ $var ] : self::NOT_FOUND;
678 if ( $the_value !== self::NOT_FOUND ) {
679 $value = $the_value;
680 break;
681 }
682 }
683
684 return $value;
685 }
686
687 /**
688 * Reads the value from one or more class static properties.
689 *
690 * @since 4.9.5
691 *
692 * @param array $classes_and_props An associative array in the shape [ <class> => <prop> ].
693 * @param mixed $default The default value to return.
694 *
695 * @return mixed The first valid value found or the default value.
696 */
697 protected function static_prop( array $classes_and_props, $default ) {
698 $value = $default;
699
700 foreach ( $classes_and_props as $class => $prop ) {
701 if ( class_exists( $class ) ) {
702 // PHP 5.2 compat, on PHP 5.3+ $class::$$prop
703 $vars = get_class_vars( $class );
704 $the_value = isset( $vars[ $prop ] ) ? $vars[ $prop ] : self::NOT_FOUND;
705
706 if ( $the_value !== self::NOT_FOUND ) {
707 $value = $the_value;
708 break;
709 }
710 }
711 }
712
713 return $value;
714 }
715
716 /**
717 * Reads the value from one or more properties of implementations bound in the `tribe()` container.
718 *
719 * @since 4.9.5
720 *
721 * @param array $bindings_and_props An associative array in the shape [ <binding> => <prop> ].
722 * @param mixed $default The default value to return.
723 *
724 * @return mixed The first valid value found or the default value.
725 */
726 protected function prop( array $bindings_and_props, $default ) {
727 $value = $default;
728
729 foreach ( $bindings_and_props as $binding => $prop ) {
730 $the_value = tribe()->offsetExists( $binding ) && property_exists( tribe( $binding ), $prop )
731 ? tribe( $binding )->{$prop}
732 : self::NOT_FOUND;
733
734 if ( $the_value !== self::NOT_FOUND ) {
735 $value = $the_value;
736 break;
737 }
738 }
739
740 return $value;
741 }
742
743 /**
744 * Reads the values from one or more static class methods.
745 *
746 * @since 4.9.5
747 *
748 * @param array $classes_and_methods An associative array in the shape [ <class> => <method> ].
749 * @param mixed $default The default value to return.
750 *
751 * @return mixed The first value that's not equal to the default one, the default value
752 * otherwise.
753 */
754 protected function static_method( array $classes_and_methods, $default ) {
755 $value = $default;
756
757 foreach ( $classes_and_methods as $class => $method ) {
758 $the_value = class_exists( $class ) && method_exists( $class, $method )
759 ? call_user_func( [ $class, $method ] )
760 : self::NOT_FOUND;
761
762 if ( $the_value !== self::NOT_FOUND ) {
763 $value = $the_value;
764 break;
765 }
766 }
767
768 return $value;
769 }
770
771 /**
772 * Reads the value from one or more methods called on implementations bound in the `tribe()` container.
773 *
774 * @since 4.9.5
775 *
776 * @param array $bindings_and_methods An associative array in the shape [ <binding> => <method> ].
777 * @param mixed $default The default value to return.
778 *
779 * @return mixed The first value that's not equal to the default one, the default value
780 * otherwise.
781 */
782 protected function method( array $bindings_and_methods, $default ) {
783 $value = $default;
784 $the_value = self::NOT_FOUND;
785
786 foreach ( $bindings_and_methods as $binding => $method ) {
787 if ( tribe()->offsetExists( $binding ) ) {
788 $implementation = tribe( $binding );
789 if ( method_exists( $implementation, $method ) ) {
790 $the_value = $implementation->$method();
791 }
792 }
793
794 if ( $the_value !== self::NOT_FOUND ) {
795 $value = $the_value;
796 break;
797 }
798 }
799
800 return $value;
801 }
802
803 /**
804 * Reads the value from one or more functions until one returns a value that's not the default one.
805 *
806 * @since 4.9.5
807 *
808 * @param array $functions An array of functions to call, in order.
809 * @param mixed $default The default value to return.
810 *
811 * @return mixed The first value that's not equal to the default one, the default value
812 * otherwise.
813 */
814 protected function func( array $functions, $default ) {
815 $value = $default;
816 $the_value = self::NOT_FOUND;
817
818 foreach ( $functions as $function ) {
819 if ( is_callable( $function ) || function_exists( $function ) ) {
820 $the_value = $function();
821 }
822
823 if ( $the_value !== self::NOT_FOUND ) {
824 $value = $the_value;
825 break;
826 }
827 }
828
829 return $value;
830 }
831
832 /**
833 * Modifies the global context using the defined write locations to persist the altered values.
834 *
835 * Please keep in mind this will set the the global context for the whole request and, when the
836 * write location is an option, to the database.
837 * With great power comes great responsibility: think a lot before using this.
838 *
839 * @param array|null $fields An optional whitelist or blacklist of fields to write
840 * depending on the value of the `$whitelist` parameter;
841 * defaults to writing all available fields.
842 * @param bool $whitelist Whether the list of fields provided in the `$fields`
843 * parameter should be treated as a whitelist (`true`) or
844 * blacklist (`false`).
845 *
846 * @since 4.9.5
847 */
848 public function dangerously_set_global_context( array $fields = null, $whitelist = true ) {
849 $locations = $this->get_locations();
850
851 if ( null !== $fields ) {
852 $locations = $whitelist
853 ? array_intersect_key( $locations, array_combine( $fields, $fields ) )
854 : array_diff_key( $locations, array_combine( $fields, $fields ) );
855 }
856
857 /**
858 * Here we intersect with the request cache to only write values we've actually read
859 * or modified. If none of the two happened then there's no need to write anything.
860 */
861 foreach ( array_intersect_key( $this->request_cache, $locations ) as $key => $value ) {
862 if ( ! isset( $locations[ $key ]['write'] ) ) {
863 continue;
864 }
865
866 foreach ( (array) $locations[ $key ]['write'] as $location => $targets ) {
867 $targets = (array) $targets;
868 $write_func = 'write_' . $location;
869
870 foreach ( $targets as $arg_1 => $arg_2 ) {
871 if ( self::FUNC === $location && is_array( $arg_2 ) && is_callable( $arg_2 ) ) {
872 // Handles write functions specified as an array.
873 $location_args = [ $arg_2 ];
874 } else {
875 $location_args = in_array( $location, self::$associative_locations, true )
876 ? [ $arg_1, $arg_2 ]
877 : (array) $arg_2;
878 }
879
880 $args = array_merge( $location_args, [ $value ] );
881
882 call_user_func_array( [ $this, $write_func ], $args );
883 }
884 }
885 }
886 }
887
888 /**
889 * Writes an altered context value to a request var.
890 *
891 * @since 4.9.5
892 *
893 * @param string $request_var The request var to write.
894 * @param mixed $value The value to set on the request var.
895 */
896 protected function write_request_var( $request_var, $value ) {
897 if ( isset( $_REQUEST ) ) {
898 $_REQUEST[ $request_var ] = $value;
899 }
900 if ( isset( $_GET ) ) {
901 $_GET[ $request_var ] = $value;
902 }
903 if ( isset( $_POST ) ) {
904 $_POST[ $request_var ] = $value;
905 }
906 }
907
908 /**
909 * Writes an altered context value to a global WP_Query object properties.
910 *
911 * @since 4.9.5
912 *
913 * @param string $query_prop The global WP_Query object property to write.
914 * @param mixed $value The value to set on the query property.
915 */
916 protected function write_query_prop( $query_prop, $value ) {
917 global $wp_query;
918
919 if ( ! $wp_query instanceof WP_Query ) {
920 return;
921 }
922
923 $wp_query->{$query_prop} = $value;
924 }
925
926 /**
927 * Writes an altered context value to a global WP_Query object query var.
928 *
929 * @since 4.9.5
930 *
931 * @param string $query_var The global WP_Query query var to write.
932 * @param mixed $value The value to set on the query var.
933 */
934 protected function write_query_var( $query_var, $value ) {
935 global $wp_query;
936
937 if ( ! $wp_query instanceof WP_Query ) {
938 return;
939 }
940
941 $wp_query->set( $query_var, $value );
942 }
943
944 /**
945 * Writes an altered context value to a `tribe_option`.
946 *
947 * @since 4.9.5
948 *
949 * @param string $tribe_option The `tribe_option` to write.
950 * @param mixed $value The value to set on the `tribe_option`.
951 */
952 protected function write_tribe_option( $tribe_option, $value ) {
953 tribe_update_option( $tribe_option, $value );
954 }
955
956 /**
957 * Writes an altered context value to an option.
958 *
959 * @since 4.9.5
960 *
961 * @param string $option_name The option to write.
962 * @param mixed $value The value to set on the option.
963 */
964 protected function write_option( $option_name, $value ) {
965 update_option( $option_name, $value );
966 }
967
968 /**
969 * Writes an altered context value to a transient.
970 *
971 * @since 4.9.5
972 *
973 * @param string $transient The transient to write.
974 * @param int $expiration The transient expiration time, in seconds.
975 * @param mixed $value The value to set on the transient.
976 */
977 protected function write_transient( $transient, $expiration, $value ) {
978 set_transient( $transient, $value, $expiration );
979 }
980
981 /**
982 * Writes an altered context value to a constant.
983 *
984 * @since 4.9.5
985 *
986 * @param string $constant The constant to define.
987 * @param mixed $value The value to set on the constant.
988 */
989 protected function write_constant( $constant, $value ) {
990 if ( defined( $constant ) ) {
991 return;
992 }
993 define( $constant, $value );
994 }
995
996 /**
997 * Writes an altered context value to a global var.
998 *
999 * @since 4.9.5
1000 *
1001 * @param string $global_var The global var to set.
1002 * @param mixed $value The value to set on the global_var.
1003 */
1004 protected function write_global_var( $global_var, $value ) {
1005 $GLOBALS[ $global_var ] = $value;
1006 }
1007
1008 /**
1009 * Writes an altered context value setting a public static property on a class.
1010 *
1011 * @since 4.9.5
1012 *
1013 * @param string $class The class to set the static public property on.
1014 * @param string $prop The static public property to set.
1015 * @param mixed $value The value to set on the property.
1016 */
1017 protected function write_static_prop( $class, $prop, $value ) {
1018 if ( ! ( class_exists( $class ) && property_exists( $class, $prop ) ) ) {
1019 return;
1020 }
1021
1022 $class::$$prop = $value;
1023 }
1024
1025 /**
1026 * Writes an altered context value setting a public property on a `tribe()` binding.
1027 *
1028 * @since 4.9.5
1029 *
1030 * @param string $binding The container binding to set the public property on.
1031 * @param string $prop The public property to set.
1032 * @param mixed $value The value to set on the property.
1033 */
1034 protected function write_prop( $binding, $prop, $value ) {
1035 if ( ! tribe()->offsetExists( $binding ) ) {
1036 return;
1037 }
1038
1039 $implementation = tribe( $binding );
1040
1041 if ( ! property_exists( $implementation, $prop ) ) {
1042 return;
1043 }
1044
1045 $implementation->{$prop} = $value;
1046 }
1047
1048 /**
1049 * Writes an altered context value calling a public static method on a class.
1050 *
1051 * @since 4.9.5
1052 *
1053 * @param string $class The class to call the public static method on.
1054 * @param string $method The static method to call.
1055 * @param mixed $value The value to pass to the public static method.
1056 */
1057 protected function write_static_method( $class, $method, $value ) {
1058 if ( ! class_exists( $class ) ) {
1059 return;
1060 }
1061 call_user_func( [ $class, $method ], $value );
1062 }
1063
1064 /**
1065 * Writes an altered context value calling a public method on a `tribe()` binding.
1066 *
1067 * @since 4.9.5
1068 *
1069 * @param string $binding The `tribe()` container binding to call the public method on.
1070 * @param string $method The method to call.
1071 * @param mixed $value The value to pass to the public method.
1072 */
1073 protected function write_method( $binding, $method, $value ) {
1074 if ( ! tribe()->offsetExists( $binding ) ) {
1075 return;
1076 }
1077 call_user_func( [ tribe( $binding ), $method ], $value );
1078 }
1079
1080 /**
1081 * Writes an altered context value calling a function or closure.
1082 *
1083 * @since 4.9.5
1084 *
1085 * @param callable $func function, closure or callable to call.
1086 * @param mixed $value The value to pass to the callable.
1087 */
1088 protected function write_func( $func, $value ) {
1089 if ( ! is_callable( $func ) ) {
1090 return;
1091 }
1092 call_user_func( $func, $value );
1093 }
1094
1095 /**
1096 * Adds/replaces read and write locations to a context.
1097 *
1098 * Locations are merged with an `array_merge` call. To refine the locations get them first with the
1099 * `get_locations` method.
1100 *
1101 * @since 4.9.5
1102 *
1103 * @param array $locations An array of read and write locations to add to the context.
1104 * The array should have the same shape as the static `$locations`
1105 * one: `[ <location> => [ 'read' => <read_locations>, 'write' => <write_locations> ] ]`.
1106 *
1107 *
1108 * @return \Tribe__Context A clone of the current context with the additional read and
1109 * write locations added.
1110 */
1111 public function add_locations( array $locations ) {
1112 $clone = clone $this;
1113 $clone->override_locations = array_merge( $clone->override_locations, $locations );
1114
1115 return $clone;
1116 }
1117
1118 /**
1119 * Sets, replacing them, the locations used by this context.
1120 *
1121 *
1122 * @since 4.9.5
1123 *
1124 * @param array $locations An array of locations to replace the current ones.
1125 * @param bool $use_default_locations Whether the context should use the default
1126 * locations defined in the static `$locations`
1127 * property or not.
1128 *
1129 * @return \Tribe__Context A clone of the current context with modified locations.
1130 */
1131 public function set_locations( array $locations, $use_default_locations = true ) {
1132 $clone = clone $this;
1133 $clone->override_locations = $locations;
1134 $clone->use_default_locations = (bool) $use_default_locations;
1135
1136 return $clone;
1137 }
1138
1139 /**
1140 * Returns an array representation of the context.
1141 *
1142 * @since 4.9.5
1143 *
1144 * @return array An associative array of the context keys and values.
1145 */
1146 public function to_array( ) {
1147 $locations = array_keys( array_merge( $this->get_locations(), $this->request_cache ) );
1148 $dump = [];
1149
1150 foreach ( $locations as $location ) {
1151 $the_value = $this->get( $location, self::NOT_FOUND );
1152
1153 if ( self::NOT_FOUND === $the_value ) {
1154 continue;
1155 }
1156
1157 $dump[ $location ] = $the_value;
1158 }
1159
1160 return $dump;
1161 }
1162
1163 /**
1164 * Returns the current context state in a format suitable to hydrate a Redux-like
1165 * store on the front-end.
1166 *
1167 * This method is a filtered wrapper around the the `Tribe__Context::to_array` method to allow the
1168 * customization of the format when producing a store-compatible state.
1169 *
1170 * @param array|null $fields An optional whitelist or blacklist of fields to include
1171 * depending on the value of the `$whitelist` parameter;
1172 * defaults to returning all available fields.
1173 * @param bool $whitelist Whether the list of fields provided in the `$fields`
1174 * parameter should be treated as a whitelist (`true`) or
1175 * blacklist (`false`).
1176 *
1177 * @since 4.9.5
1178 *
1179 * @return array
1180 */
1181 public function get_state( array $fields = null, $whitelist = true ) {
1182 $state = $this->to_array();
1183 $is_global_context = tribe_context() === $this;
1184
1185 if ( null !== $fields ) {
1186 $state = $whitelist
1187 ? array_intersect_key( $state, array_combine( $fields, $fields ) )
1188 : array_diff_key( $state, array_combine( $fields, $fields ) );
1189 }
1190
1191 /**
1192 * Filters the Redux store compatible state produced from the current context.
1193 *
1194 * @since 4.9.5
1195 *
1196 * @param array $state The Redux store compatible state produced from the current context.
1197 * @param bool $is_global_context Whether the context producing the state is the global one
1198 * or a modified clone of it.
1199 * @param Tribe__Context The context object producing the state.
1200 */
1201 $state = apply_filters( 'tribe_context_state', $state, $is_global_context, $this );
1202
1203 if ( $is_global_context ) {
1204 /**
1205 * Filters the Redux store compatible state produced from the global context.
1206 *
1207 * While the `tribe_context_state` filter will apply to all contexts producing a
1208 * state this filter will only apply to the global context.
1209 *
1210 * @since 4.9.5
1211 *
1212 * @param array $state The Redux store compatible state produced from the global context.
1213 * @param Tribe__Context The global context object producing the state.
1214 */
1215 $state = apply_filters( 'tribe_global_context_state', $state, $this );
1216 }
1217
1218 return $state;
1219 }
1220
1221 /**
1222 * Returns an array of ORM arguments generated from the current context values.
1223 *
1224 * @since 4.9.5
1225 *
1226 * @param array|null $fields An optional whitelist or blacklist of fields to include
1227 * depending on the value of the `$whitelist` parameter;
1228 * defaults to returning all available fields.
1229 * @param bool $whitelist Whether the list of fields provided in the `$fields`
1230 * parameter should be treated as a whitelist (`true`) or
1231 * blacklist (`false`).
1232 *
1233 * @return array A map of ORM fields produced from the context current values.
1234 */
1235 public function get_orm_args( array $fields = null, $whitelist = true ) {
1236 $locations = $this->get_locations();
1237 $dump = $this->to_array();
1238 $orm_args = [];
1239 $is_global_context = tribe_context() === $this;
1240
1241 foreach ( $dump as $key => $value ) {
1242 $alias = isset( $locations[ $key ]['orm_arg'] )
1243 ? $locations[ $key ]['orm_arg']
1244 : $key;
1245
1246 if ( false === $alias ) {
1247 // Do not provide the variable as an ORM arg.
1248 continue;
1249 }
1250
1251 if ( isset( $locations[ $key ]['orm_transform'] ) ) {
1252 $value = call_user_func( $locations[ $key ]['orm_transform'], $value );
1253 }
1254
1255 $orm_args[ $alias ] = $value;
1256 }
1257
1258 if ( null !== $fields ) {
1259 /*
1260 * Only keep wanted fields, the filtering is done on the resolved aliases,
1261 * from the perspective of the client code that might ignore the source keys.
1262 */
1263 $orm_args = $whitelist
1264 ? array_intersect_key( $orm_args, array_combine( $fields, $fields ) )
1265 : array_diff_key( $orm_args, array_combine( $fields, $fields ) );
1266 }
1267
1268 /**
1269 * Filters the ORM arguments produced from the current context.
1270 *
1271 * @since 4.9.5
1272 *
1273 * @param array $orm_args The ORM args produced from the current context.
1274 * @param bool $is_global_context Whether the context producing the ORM args is the global one
1275 * or a modified clone of it.
1276 * @param Tribe__Context The context object producing the ORM args.
1277 */
1278 $orm_args = apply_filters( 'tribe_context_orm_args', $orm_args, $is_global_context, $this );
1279
1280 if ( $is_global_context ) {
1281 /**
1282 * Filters the ORM arguments produced from the global context.
1283 *
1284 * While the `tribe_context_orm_args` filter will apply to all contexts producing ORM
1285 * args this filter will only apply to the global context.
1286 *
1287 * @since 4.9.5
1288 *
1289 * @param array $orm_args The ORM args produced from the global context.
1290 * @param Tribe__Context The global context object producing the ORM args.
1291 */
1292 $orm_args = apply_filters( 'tribe_global_context_orm_args', $orm_args, $this );
1293 }
1294
1295 return $orm_args;
1296 }
1297
1298 /**
1299 * Sets some locations that can only be set at runtime.
1300 *
1301 * Using a flag locations are added only once per request.
1302 *
1303 * @since 4.9.8
1304 */
1305 protected function populate_locations() {
1306 if ( static::$did_populate_locations ) {
1307 return;
1308 }
1309
1310 // To improve the class readability, and as a small optimization, locations are loaded from a file.
1311 static::$locations = include __DIR__ . '/Context/locations.php';
1312
1313 /**
1314 * Filters the locations registered in the Context.
1315 *
1316 * @since 4.9.8
1317 *
1318 * @param array $locations An array of locations registered on the Context object.
1319 */
1320 static::$locations = apply_filters( 'tribe_context_locations', static::$locations, $this );
1321
1322 static::$did_populate_locations = true;
1323 }
1324
1325 /**
1326 * Just dont...
1327 * Unless you very specifically know what you are doing **DO NOT USE THIS METHOD**!
1328 *
1329 * Please keep in mind this will set force the context to repopulate all locations for the whole request, expensive
1330 * and very dangerous overall since it could affect all this things we hold dear in the request.
1331 *
1332 * With great power comes great responsibility: think a lot before using this.
1333 *
1334 * @since 4.13.0
1335 */
1336 public function dangerously_repopulate_locations() {
1337 static::$did_populate_locations = false;
1338 $this->populate_locations();
1339 }
1340
1341 /**
1342 * Reads (gets) the value applying one or more filters.
1343 *
1344 * @since 4.9.8
1345 *
1346 * @param array $filters The list of filters to apply, in order.
1347 * @param mixed $default The default value to return.
1348 *
1349 * @return mixed The first valid value found or the default value.
1350 */
1351 public function filter( array $filters, $default ) {
1352 foreach ( $filters as $filter ) {
1353 $the_value = apply_filters( $filter, $default );
1354 if ( $the_value !== $default ) {
1355 return $the_value;
1356 }
1357 }
1358
1359 return $default;
1360 }
1361
1362 /**
1363 * Reads (gets) the value reading it from a query var parsed from the global `$wp` object.
1364 *
1365 * @since 4.9.8
1366 *
1367 * @param array $vars The list of variables to read, in order.
1368 * @param mixed $default The default value to return if no variable was parsed.
1369 *
1370 * @return mixed The first valid value found or the default value.
1371 */
1372 public function wp_parsed( array $vars, $default ) {
1373 /** @var WP $wp */
1374 global $wp;
1375
1376 if ( ! $wp instanceof WP || empty($wp->query_vars) ) {
1377 return $default;
1378 }
1379
1380 return Arr::get_first_set( (array) $wp->query_vars, $vars, $default );
1381 }
1382
1383 /**
1384 * Reads (gets) the value reading it from a query var parsed from the query matched by the global `$wp` object.
1385 *
1386 * @since 4.9.8
1387 *
1388 * @param array $vars The list of variables to read, in order.
1389 * @param mixed $default The default value to return if no variable was parsed.
1390 *
1391 * @return mixed The first valid value found or the default value.
1392 */
1393 public function wp_matched_query( array $vars, $default ) {
1394 /** @var WP $wp */
1395 global $wp;
1396
1397 if ( ! $wp instanceof WP || empty( $wp->matched_query ) ) {
1398 return $default;
1399 }
1400
1401 parse_str( $wp->matched_query, $query_vars );
1402
1403 return Arr::get_first_set( (array) $query_vars, $vars, $default );
1404 }
1405
1406 /**
1407 * Maps an input array to the corresponding read locations.
1408 *
1409 * The resulting array can be used as input for the `alter_values` method.
1410 * The main use of this method is to leverage the Context knowledge of the read locations, and their types, to
1411 * "translate" an array of values to an array of valid read sources. As an example this is useful to "translate"
1412 * the locations to an array of query vars:
1413 * $input = [ 'event_display' => 'some-view', 'event_date' => '2018-01-03' ];
1414 * $query_args = tribe_context()->map_to_read( $input, Tribe__Context::REQUEST_VAR );
1415 * $url = add_query_arg( $query_args, home_url() );
1416 *
1417 * @since 4.9.11
1418 *
1419 * @param array $input An associative array of values in the shape `[ <location> => <value> ]`;
1420 * where `location` is the name of the location registered in the Context
1421 * locations.
1422 * @param string|array|null $types A white-list of read location types to include in the mapped output;
1423 * `null`
1424 * means all types are allowed.
1425 * @param bool $passthru Whether to pass unknown locations in the output or not; if `false` then
1426 * any input key that's not a context location will not appear in the output;
1427 * defaults to `false` to remove unknown locations from the output.
1428 *
1429 * @return array An associative array in the shape `[ <read_location> => <input_value> ]`. Since some read
1430 * locations could have multiple sources the number of elements in this array will likely NOT be the
1431 * same as the number of elements in the input array. When a read location as more than 1 source then
1432 * the value will be duplicated, in the output array, to both sources.
1433 */
1434 public function map_to_read( array $input, $types = null, $passthru = false ) {
1435 $mapped = [];
1436 $processed = [];
1437 $types = null !== $types ? (array) $types : null;
1438
1439 $locations = $this->get_locations();
1440
1441 // Take the current read locations
1442 foreach ( $locations as $key => $location ) {
1443 if ( ! isset( $location['read'], $input[ $key ] ) ) {
1444 continue;
1445 }
1446
1447 $processed[] = $key;
1448
1449 foreach ( $location['read'] as $type => $name ) {
1450 if ( null !== $types && ! in_array( $type, $types, true ) ) {
1451 continue;
1452 }
1453
1454 foreach ( (array) $name as $destination ) {
1455 $mapped[ $destination ] = $input[ $key ];
1456 }
1457 }
1458 }
1459
1460 if ( $passthru ) {
1461 $mapped = array_merge(
1462 $mapped,
1463 array_diff_key( $input, array_keys( $locations ), array_combine( $processed, $processed ) )
1464 );
1465 }
1466
1467 ksort( $mapped );
1468
1469 return $mapped;
1470 }
1471
1472 /**
1473 * Translates sub-locations to their respective location key.
1474 *
1475 * This method leverages the inherent knowledge of aliases stored in the Context locations to "translate" a
1476 * sub-location to its location key.
1477 * E.g. assume the `car` location is `read` from the [ 'carriage', 'vehicle', 'transport_mean' ] query var; calling
1478 * `$context->populate_aliases( [ 'vehicle' => 'hyunday' ], 'read', Context::QUERY_VAR )` would yield
1479 * `[ 'car' => 'hyunday' ]`.
1480 *
1481 * @since 4.9.12
1482 *
1483 * @param array $values An associative array of value to use as "masters" to populate the aliases.
1484 * @param string $type The type of Context location to use, e.g. `Tribe__Context::QUERY_VAR`.
1485 * @param string $direction The direction to use for the location, one of `read` or `write`.
1486 *
1487 * @return array The original array, merged with the populated values.
1488 */
1489 public function translate_sub_locations( array $values, $type, $direction = 'read' ) {
1490 if ( ! in_array( $direction, [ 'read', 'write' ], true ) ) {
1491 throw new \InvalidArgumentException(
1492 "Direction must be one of `read` or `write`; `{$direction}` is not valid."
1493 );
1494 }
1495
1496 $filled = [];
1497 $locations = $this->get_locations();
1498 $matching_locations = array_filter( $locations, static function ( $location ) use ( $type, $direction ) {
1499 return isset( $location[ $direction ][ $type ] );
1500 } );
1501
1502 foreach ( $matching_locations as $key => $location ) {
1503 $entry = (array)$location[ $direction ][ $type ];
1504 $found = array_intersect( array_keys( $values ), array_merge( $entry, [ $key ] ) );
1505 if ( $found ) {
1506 $filled[ $key ] = $values[ reset( $found ) ];
1507 }
1508 }
1509
1510 return $filled;
1511 }
1512
1513 /**
1514 * Convenience method to get and check if a location has a truthy value or not.
1515 *
1516 * @since 4.9.18
1517 *
1518 * @param string $flag_key The location to check.
1519 * @param bool $default The default value to return if the location is not set.
1520 *
1521 * @return bool Whether the location has a truthy value or not.
1522 */
1523 public function is( $flag_key, $default = false ) {
1524 $val = $this->get( $flag_key, $default );
1525
1526 return ! empty( $val ) || tribe_is_truthy( $val );
1527 }
1528
1529 /**
1530 * Reads the value from one callback, passing it the value of another Context location.
1531 *
1532 * @since 4.9.18
1533 *
1534 * @param array $location_and_callback An array of two elements: the location key and the callback to call on the
1535 * location value. The callback will receive the location value as argument.
1536 *
1537 * @return mixed The return value of the callback, called on the location value.
1538 */
1539 public function location_func( array $location_and_callback ) {
1540 list( $location, $callback ) = $location_and_callback;
1541
1542 return $callback( $this->get( $location ) );
1543 }
1544
1545 /**
1546 * Checks whether the current request is a REST API one or not.
1547 *
1548 * @since 4.9.20
1549 *
1550 * @return bool Whether the current request is a REST API one or not.
1551 */
1552 public function doing_rest() {
1553 return defined( 'REST_REQUEST' ) && REST_REQUEST;
1554 }
1555
1556 /**
1557 * Reads the value from one or more global WP_Query object methods.
1558 *
1559 * @since 4.9.20
1560 *
1561 * @param array $query_vars The list of query methods to call, in order.
1562 * @param mixed $default The default value to return if no method was defined on the global `WP_Query` object.
1563 *
1564 * @return mixed The first valid value found or the default value.
1565 */
1566 public function query_method( $methods, $default ) {
1567 global $wp_query;
1568 $found = $default;
1569
1570 foreach ( $methods as $method ) {
1571 $this_value = $wp_query instanceof WP_Query && method_exists( $wp_query, $method )
1572 ? call_user_func( [ $wp_query, $method ] )
1573 : static::NOT_FOUND;
1574
1575 if ( static::NOT_FOUND !== $this_value ) {
1576 return $this_value;
1577 }
1578 }
1579
1580 return $found;
1581 }
1582
1583 /**
1584 * Whether the current request is for a PHP-rendered initial state or not.
1585 *
1586 * This method is a shortcut to make sure we're not doing an AJAX, REST or Cron request.
1587 *
1588 * @since 4.9.20
1589 *
1590 * @return bool Whether the current request is for a PHP-rendered initial state or not.
1591 */
1592 public function doing_php_initial_state() {
1593 return ! $this->doing_rest() && ! $this->doing_ajax() && ! $this->doing_cron();
1594 }
1595
1596 /**
1597 * Returns the first key, if there are many, that will be used to read a location.
1598 *
1599 * The type ar
1600 *
1601 * @since 4.9.20
1602 *
1603 * @param string $location The location to get the read key for.
1604 * @param string|null $type The type of read location to return the key for; default to `static::REQUEST_VAR`.
1605 *
1606 * @return string Either the first key for the type of read location, or the input location if not found.
1607 */
1608 public function get_read_key_for( $location, $type = null ) {
1609 $type = $type ?: static::REQUEST_VAR;
1610 $locations = $this->get_locations();
1611 if ( isset( $locations[ $location ]['read'][ $type ] ) ) {
1612 $keys = (array) $locations[ $location ]['read'][ $type ];
1613 return reset( $keys );
1614 }
1615
1616 return $location;
1617 }
1618
1619 /**
1620 * Safely set the value of a group of locations.
1621 *
1622 * This method can only augment the context, without altering it; it can only add new values.
1623 *
1624 * @since 4.10.2
1625 *
1626 * @param array|string $values The values to set, if not already set or the key of the value to set, requires
1627 * the `$value` to be passed.
1628 * @param mixed|null $value The value to set for the key, this parameter will be ignored if the `$values_or_key`
1629 * parameter is not a string.
1630 */
1631 public function safe_set( $values_or_key, $value = null ) {
1632 $values = func_num_args() === 2
1633 ? [ $values_or_key => $value ]
1634 : $values_or_key;
1635
1636 foreach ( $values as $key => $val ) {
1637 if ( static::NOT_FOUND !== $this->get( $key, static::NOT_FOUND ) ) {
1638 continue;
1639 }
1640 $this->request_cache[ $key ] = $val;
1641 }
1642 }
1643 }
1644