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 / Template.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
Template.php
1469 lines
1 <?php
2
3 use Tribe\Utils\Paths;
4 use Tribe\Utils\Strings;
5
6 class Tribe__Template {
7 /**
8 * The folders into which we will look for the template.
9 *
10 * @since 4.6.2
11 *
12 * @var array
13 */
14 protected $folder = [];
15
16 /**
17 * The origin class for the plugin where the template lives
18 *
19 * @since 4.6.2
20 *
21 * @var object
22 */
23 public $origin;
24
25 /**
26 * The local context for templates, mutable on every self::template() call
27 *
28 * @since 4.6.2
29 *
30 * @var array
31 */
32 protected $context = [];
33
34 /**
35 * The global context for this instance of templates
36 *
37 * @since 4.6.2
38 *
39 * @var array
40 */
41 protected $global = [];
42
43 /**
44 * Used for finding templates for public templates on themes inside of a folder.
45 *
46 * @since 4.10.2
47 *
48 * @var string[]
49 */
50 protected $template_origin_base_folder = [ 'src', 'views' ];
51
52 /**
53 * Allow changing if class will extract data from the local context
54 *
55 * @since 4.6.2
56 *
57 * @var boolean
58 */
59 protected $template_context_extract = false;
60
61 /**
62 * Current template hook name.
63 *
64 * @since 4.12.1
65 *
66 * @var string|null
67 */
68 protected $template_current_hook_name;
69
70 /**
71 * Base template for where to look for template
72 *
73 * @since 4.6.2
74 *
75 * @var array
76 */
77 protected $template_base_path;
78
79 /**
80 * Should we use a lookup into the list of folders to try to find the file
81 *
82 * @since 4.7.20
83 *
84 * @var bool
85 */
86 protected $template_folder_lookup = false;
87
88 /**
89 * Create a class variable for the include path, to avoid conflicting with extract.
90 *
91 * @since 4.11.0
92 *
93 * @var string
94 */
95 protected $template_current_file_path;
96
97 /**
98 * Whether to look for template files in common or not; defaults to true.
99 *
100 * @since 4.12.10
101 *
102 * @var bool
103 */
104 protected $common_lookup = true;
105
106 /**
107 * A map of aliases to add a rewritten version of the paths to the template lists.
108 * The map has format `original => alias`.
109 *
110 * @since 4.12.10
111 *
112 * @var array<string,string>
113 */
114 protected $aliases = [];
115
116 /**
117 * Configures the class origin plugin path
118 *
119 * @since 4.6.2
120 *
121 * @param object|string $origin The base origin for the templates
122 *
123 * @return self
124 */
125 public function set_template_origin( $origin = null ) {
126 if ( empty( $origin ) ) {
127 $origin = $this->origin;
128 }
129
130 if ( is_string( $origin ) ) {
131 // Origin needs to be a class with a `instance` method
132 if ( class_exists( $origin ) && method_exists( $origin, 'instance' ) ) {
133 $origin = call_user_func( [ $origin, 'instance' ] );
134 }
135 }
136
137 if (
138 empty( $origin->plugin_path )
139 && empty( $origin->pluginPath )
140 && ! is_dir( $origin )
141 ) {
142 throw new InvalidArgumentException( 'Invalid Origin Class for Template Instance' );
143 }
144
145 if ( is_string( $origin ) ) {
146 $this->template_base_path = array_filter(
147 (array) explode(
148 '/',
149 untrailingslashit( $origin )
150 )
151 );
152 } else {
153 $this->origin = $origin;
154
155 $this->template_base_path = untrailingslashit(
156 ! empty( $this->origin->plugin_path )
157 ? $this->origin->plugin_path
158 : $this->origin->pluginPath
159 );
160 }
161
162 return $this;
163 }
164
165 /**
166 * Configures the class with the base folder in relation to the Origin
167 *
168 * @since 4.6.2
169 *
170 * @param array|string $folder Which folder we are going to look for templates
171 *
172 * @return self
173 */
174 public function set_template_folder( $folder = null ) {
175 // Allows configuring a already set class
176 if ( ! isset( $folder ) ) {
177 $folder = $this->folder;
178 }
179
180 // If Folder is String make it an Array
181 if ( is_string( $folder ) ) {
182 $folder = (array) explode( '/', $folder );
183 }
184
185 // Cast as Array and save
186 $this->folder = (array) $folder;
187
188 return $this;
189 }
190
191 /**
192 * Returns the array for which folder this template instance is looking into.
193 *
194 * @since 4.11.0
195 *
196 * @return array Current folder we are looking for templates.
197 */
198 public function get_template_folder() {
199 return $this->folder;
200 }
201
202 /**
203 * Configures the class with the base folder in relation to the Origin
204 *
205 * @since 4.7.20
206 *
207 * @param mixed $value Should we look for template files in the list of folders.
208 *
209 * @return self
210 */
211 public function set_template_folder_lookup( $value = true ) {
212 $this->template_folder_lookup = tribe_is_truthy( $value );
213
214 return $this;
215 }
216
217 /**
218 * Gets in this instance of the template engine whether we are looking public folders like themes.
219 *
220 * @since 4.12.1
221 *
222 * @return bool Whether we are looking into theme folders.
223 */
224 public function get_template_folder_lookup() {
225 return $this->template_folder_lookup;
226 }
227
228 /**
229 * Configures the class global context
230 *
231 * @since 4.6.2
232 *
233 * @param array $context Default global Context
234 *
235 * @return self
236 */
237 public function add_template_globals( $context = [] ) {
238 // Cast as Array merge and save
239 $this->global = wp_parse_args( (array) $context, $this->global );
240
241 return $this;
242 }
243
244 /**
245 * Configures if the class will extract context for template
246 *
247 * @since 4.6.2
248 *
249 * @param bool $value Should we extract context for templates
250 *
251 * @return self
252 */
253 public function set_template_context_extract( $value = false ) {
254 // Cast as bool and save
255 $this->template_context_extract = tribe_is_truthy( $value );
256
257 return $this;
258 }
259
260 /**
261 * Set the current hook name for the template include.
262 *
263 * @since 4.12.1
264 *
265 * @param string $value Which value will be saved as the current hook name.
266 *
267 * @return self Allow daisy-chaining.
268 */
269 public function set_template_current_hook_name( $value ) {
270 $this->template_current_hook_name = (string) $value;
271
272 return $this;
273 }
274
275 /**
276 * Gets the hook name for the current template setup.
277 *
278 * @since 4.12.1
279 *
280 * @return string Hook name currently set on the class.
281 */
282 public function get_template_current_hook_name() {
283 return $this->template_current_hook_name;
284 }
285
286 /**
287 * Sets an Index inside of the global or local context.
288 * Final to prevent extending the class when the `get` already exists on the child class.
289 *
290 * @see Tribe__Utils__Array::set()
291 *
292 * @since 4.6.2
293 *
294 * @param array|string $index Specify each nested index in order.
295 * Example: array( 'lvl1', 'lvl2' );
296 * @param mixed $default Default value if the search finds nothing.
297 * @param boolean $is_local Use the Local or Global context.
298 *
299 * @return mixed The value of the specified index or the default if not found.
300 */
301 final public function get( $index, $default = null, $is_local = true ) {
302 $context = $this->get_global_values();
303
304 if ( true === $is_local ) {
305 $context = $this->get_local_values();
306 }
307
308 /**
309 * Allows filtering the the getting of Context variables, also short circuiting
310 * Following the same structure as WP Core
311 *
312 * @since 4.6.2
313 *
314 * @param mixed $value The value that will be filtered.
315 * @param array|string $index Specify each nested index in order.
316 * Example: array( 'lvl1', 'lvl2' );
317 * @param mixed $default Default value if the search finds nothing.
318 * @param boolean $is_local Use the Local or Global context.
319 * @param self $template Current instance of the Tribe__Template.
320 */
321 $value = apply_filters( 'tribe_template_context_get', null, $index, $default, $is_local, $this );
322
323 if ( null !== $value ) {
324 return $value;
325 }
326
327 return Tribe__Utils__Array::get( $context, $index, $default );
328 }
329
330 /**
331 * Sets a Index inside of the global or local context
332 * Final to prevent extending the class when the `set` already exists on the child class
333 *
334 * @since 4.6.2
335 *
336 * @see Tribe__Utils__Array::set
337 *
338 * @param string|array $index To set a key nested multiple levels deep pass an array
339 * specifying each key in order as a value.
340 * Example: array( 'lvl1', 'lvl2', 'lvl3' );
341 * @param mixed $value The value.
342 * @param boolean $is_local Use the Local or Global context
343 *
344 * @return array Full array with the key set to the specified value.
345 */
346 final public function set( $index, $value = null, $is_local = true ) {
347 if ( true === $is_local ) {
348 $this->context = Tribe__Utils__Array::set( $this->context, $index, $value );
349
350 return $this->context;
351 }
352
353 $this->global = Tribe__Utils__Array::set( $this->global, $index, $value );
354
355 return $this->global;
356 }
357
358 /**
359 * Merges local and global context, and saves it locally
360 *
361 * @since 4.6.2
362 *
363 * @param array $context Local Context array of data
364 * @param string $file Complete path to include the PHP File
365 * @param array $name Template name
366 *
367 * @return array
368 */
369 public function merge_context( $context = [], $file = null, $name = null ) {
370 // Allow for simple null usage as well as array() for nothing
371 if ( is_null( $context ) ) {
372 $context = [];
373 }
374
375 // Applies new local context on top of Global + Previous local.
376 $context = wp_parse_args( (array) $context, $this->get_values() );
377
378 /**
379 * Allows filtering the Local context
380 *
381 * @since 4.6.2
382 *
383 * @param array $context Local Context array of data
384 * @param string $file Complete path to include the PHP File
385 * @param array $name Template name
386 * @param self $template Current instance of the Tribe__Template
387 */
388 $this->context = apply_filters( 'tribe_template_context', $context, $file, $name, $this );
389
390 return $this->context;
391 }
392
393 /**
394 * Fetches the path for locating files in the Plugin Folder
395 *
396 * @since 4.7.20
397 *
398 * @return string
399 */
400 protected function get_template_plugin_path() {
401 // Craft the plugin Path
402 $path = array_merge( (array) $this->template_base_path, $this->folder );
403
404 // Implode to avoid Window Problems
405 $path = implode( DIRECTORY_SEPARATOR, $path );
406
407 /**
408 * Allows filtering of the base path for templates
409 *
410 * @since 4.7.20
411 *
412 * @param string $path Complete path to include the base plugin folder
413 * @param self $template Current instance of the Tribe__Template
414 */
415 return apply_filters( 'tribe_template_plugin_path', $path, $this );
416 }
417
418 /**
419 * Fetches the Namespace for the public paths, normally folders to look for
420 * in the theme's directory.
421 *
422 * @since 4.7.20
423 * @since 4.11.0 Added param $plugin_namespace.
424 *
425 * @param string $plugin_namespace Overwrite the origin namespace with a given one.
426 *
427 * @return array Namespace where we to look for templates.
428 */
429 protected function get_template_public_namespace( $plugin_namespace ) {
430 $namespace = [
431 'tribe',
432 ];
433
434 if ( ! empty( $plugin_namespace ) ) {
435 $namespace[] = $plugin_namespace;
436 } elseif ( ! empty( $this->origin->template_namespace ) ) {
437 $namespace[] = $this->origin->template_namespace;
438 }
439
440 /**
441 * Allows filtering of the base path for templates
442 *
443 * @since 4.7.20
444 *
445 * @param array $namespace Which is the namespace we will look for files in the theme
446 * @param self $template Current instance of the Tribe__Template
447 */
448 return apply_filters( 'tribe_template_public_namespace', $namespace, $this );
449 }
450
451 /**
452 * Fetches which base folder we look for templates in the origin plugin.
453 *
454 * @since 4.10.2
455 *
456 * @return array The base folders we look for templates in the origin plugin.
457 */
458 public function get_template_origin_base_folder() {
459 /**
460 * Allows filtering of the base path for templates.
461 *
462 * @since 4.10.2
463 *
464 * @param array $namespace Which is the base folder we will look for files in the plugin.
465 * @param self $template Current instance of the Tribe__Template.
466 */
467 return apply_filters( 'tribe_template_origin_base_folder', $this->template_origin_base_folder, $this );
468 }
469
470 /**
471 * Fetches the path for locating files given a base folder normally theme related.
472 *
473 * @since 4.7.20
474 * @since 4.11.0 Added the param $namespace.
475 *
476 * @param mixed $base Base path to look into.
477 * @param string $namespace Adds the plugin namespace to the path returned.
478 *
479 * @return string The public path for a given base.˙˙
480 */
481 protected function get_template_public_path( $base, $namespace ) {
482
483 // Craft the plugin Path
484 $path = array_merge( (array) $base, (array) $this->get_template_public_namespace( $namespace ) );
485
486 // Pick up if the folder needs to be aded to the public template path.
487 $folder = array_diff( $this->folder, $this->get_template_origin_base_folder() );
488
489 if ( ! empty( $folder ) ) {
490 $path = array_merge( $path, $folder );
491 }
492
493 // Implode to avoid Window Problems
494 $path = implode( DIRECTORY_SEPARATOR, $path );
495
496 /**
497 * Allows filtering of the base path for templates
498 *
499 * @since 4.7.20
500 *
501 * @param string $path Complete path to include the base public folder
502 * @param self $template Current instance of the Tribe__Template
503 */
504 return apply_filters( 'tribe_template_public_path', $path, $this );
505 }
506
507 /**
508 * Fetches the folders in which we will look for a given file
509 *
510 * @since 4.7.20
511 * @since 4.12.10 Add support for common lookup.
512 *
513 * @return array<string,array> A list of possible locations for the template file.
514 */
515 protected function get_template_path_list() {
516 $folders = [];
517
518 $folders['plugin'] = [
519 'id' => 'plugin',
520 'priority' => 20,
521 'path' => $this->get_template_plugin_path(),
522 ];
523
524 if ( $this->common_lookup ) {
525 // After the plugin (due to priority) look into Common too.
526 $folders['common'] = [
527 'id' => 'common',
528 'priority' => 100,
529 'path' => $this->get_template_common_path(),
530 ];
531 }
532
533 $folders = array_merge( $folders, $this->apply_aliases( $folders ) );
534
535 /**
536 * Allows filtering of the list of folders in which we will look for the
537 * template given.
538 *
539 * @since 4.7.20
540 *
541 * @param array $folders Complete path to include the base public folder
542 * @param self $template Current instance of the Tribe__Template
543 */
544 $folders = (array) apply_filters( 'tribe_template_path_list', $folders, $this );
545
546 uasort( $folders, 'tribe_sort_by_priority' );
547
548 return $folders;
549 }
550
551 /**
552 * Get the list of theme related folders we will look up for the template.
553 *
554 * @since 4.11.0
555 *
556 * @param string $namespace Which plugin namespace we are looking for.
557 *
558 * @return array
559 */
560 protected function get_template_theme_path_list( $namespace ) {
561 $folders = [];
562
563 $folders['child-theme'] = [
564 'id' => 'child-theme',
565 'priority' => 10,
566 'path' => $this->get_template_public_path( STYLESHEETPATH, $namespace ),
567 ];
568 $folders['parent-theme'] = [
569 'id' => 'parent-theme',
570 'priority' => 15,
571 'path' => $this->get_template_public_path( TEMPLATEPATH, $namespace ),
572 ];
573
574 /**
575 * Allows filtering of the list of theme folders in which we will look for the template.
576 *
577 * @since 4.11.0
578 *
579 * @param array $folders Complete path to include the base public folder.
580 * @param string $namespace Loads the files from a specified folder from the themes.
581 * @param self $template Current instance of the Tribe__Template.
582 */
583 $folders = (array) apply_filters( 'tribe_template_theme_path_list', $folders, $namespace, $this );
584
585 uasort( $folders, 'tribe_sort_by_priority' );
586
587 return $folders;
588 }
589
590 /**
591 * Tries to locate the correct file we want to load based on the Template class
592 * configuration and it's list of folders
593 *
594 * @since 4.7.20
595 *
596 * @param mixed $name File name we are looking for
597 *
598 * @return string
599 */
600 public function get_template_file( $name ) {
601 // If name is String make it an Array
602 if ( is_string( $name ) ) {
603 $name = (array) explode( '/', $name );
604 }
605
606 $folders = $this->get_template_path_list();
607 $found_file = false;
608 $namespace = false;
609
610 foreach ( $folders as $folder ) {
611 if ( empty( $folder['path'] ) ) {
612 continue;
613 }
614
615 // Build the File Path
616 $file = Paths::merge( $folder['path'], $name );
617
618 // Append the Extension to the file path
619 $file .= '.php';
620
621 // Skip non-existent files
622 if ( file_exists( $file ) ) {
623 $found_file = $file;
624 $namespace = ! empty( $folder['namespace'] ) ? $folder['namespace'] : false;
625 break;
626 }
627 }
628
629 if ( $this->get_template_folder_lookup() ) {
630 $theme_folders = $this->get_template_theme_path_list( $namespace );
631
632 foreach ( $theme_folders as $folder ) {
633 if ( empty( $folder['path'] ) ) {
634 continue;
635 }
636
637 // Build the File Path
638 $file = implode( DIRECTORY_SEPARATOR, array_merge( (array) $folder['path'], $name ) );
639
640 // Append the Extension to the file path
641 $file .= '.php';
642
643 // Skip non-existent files
644 if ( file_exists( $file ) ) {
645 $found_file = $file;
646 break;
647 }
648 }
649 }
650
651 if ( $found_file ) {
652 /**
653 * A more Specific Filter that will include the template name
654 *
655 * @since 4.6.2
656 * @since 4.7.20 The $name param no longer contains the extension
657 *
658 * @param string $file Complete path to include the PHP File
659 * @param array $name Template name
660 * @param self $template Current instance of the Tribe__Template
661 */
662 return apply_filters( 'tribe_template_file', $found_file, $name, $this );
663 }
664
665 // Couldn't find a template on the Stack
666 return false;
667 }
668
669 /**
670 * Runs the entry point hooks and filters.
671 *
672 * @param string $entry_point_name The name of the entry point.
673 * @param boolean $echo If we should also print the entry point content.
674 *
675 * @return null|string `null` if an entry point is disabled or the entry point HTML.
676 */
677 public function do_entry_point( $entry_point_name, $echo = true ) {
678 $hook_name = $this->get_template_current_hook_name();
679
680 /**
681 * Filter if the entry points are enabled.
682 *
683 * @since 4.12.1
684 *
685 * @param boolean $is_enabled Is entry_point enabled.
686 * @param string $hook_name For which template include this entry point belongs.
687 * @param string $entry_point_name Which entry point specifically we are triggering.
688 * @param self $template Current instance of the template class doing this entry point.
689 */
690 $is_entry_point_enabled = apply_filters( 'tribe_template_entry_point_is_enabled', true, $hook_name, $entry_point_name, $this );
691
692 if ( ! $is_entry_point_enabled ) {
693 return null;
694 }
695
696 ob_start();
697
698 if ( has_action( "tribe_template_entry_point:{$hook_name}" ) ) {
699 /**
700 * Generic entry point action for the current template.
701 *
702 * @since 4.12.1
703 *
704 * @param string $hook_name For which template include this entry point belongs.
705 * @param string $entry_point_name Which entry point specifically we are triggering.
706 * @param self $template Current instance of the template class doing this entry point.
707 */
708 do_action( "tribe_template_entry_point:{$hook_name}", $hook_name, $entry_point_name, $this );
709 }
710
711 if ( has_action( "tribe_template_entry_point:{$hook_name}:{$entry_point_name}" ) ) {
712 /**
713 * Specific named entry point action called.
714 *
715 * @since 4.12.1
716 *
717 * @param string $hook_name For which template include this entry point belongs.
718 * @param string $entry_point_name Which entry point specifically we are triggering.
719 * @param self $template Current instance of the template class doing this entry point.
720 */
721 do_action( "tribe_template_entry_point:{$hook_name}:{$entry_point_name}", $hook_name, $entry_point_name, $this );
722 }
723
724 $html = ob_get_clean();
725
726 if ( has_filter( "tribe_template_entry_point_html:{$hook_name}" ) ) {
727 /**
728 * Generic entry point action for the current template.
729 *
730 * @since 4.12.1
731 *
732 * @param string $html HTML returned and/or echoed for this for this entry point.
733 * @param string $hook_name For which template include this entry point belongs.
734 * @param string $entry_point_name Which entry point specifically we are triggering.
735 * @param self $template Current instance of the template class doing this entry point.
736 */
737 $html = apply_filters( "tribe_template_entry_point_html:{$hook_name}", $html, $hook_name, $entry_point_name, $this );
738 }
739
740 if ( has_filter( "tribe_template_entry_point_html:{$hook_name}:{$entry_point_name}" ) ) {
741 /**
742 * Specific named entry point action called.
743 *
744 * @since 4.12.1
745 *
746 * @param string $html HTML returned and/or echoed for this for this entry point.
747 * @param string $hook_name For which template include this entry point belongs.
748 * @param string $entry_point_name Which entry point specifically we are triggering.
749 * @param self $template Current instance of the template class doing this entry point.
750 */
751 $html = apply_filters( "tribe_template_entry_point_html:{$hook_name}:{$entry_point_name}", $html, $hook_name, $entry_point_name, $this );
752 }
753
754 if ( $echo ) {
755 echo $html;
756 }
757
758 return $html;
759 }
760
761 /**
762 * A very simple method to include a Template, allowing filtering and additions using hooks.
763 *
764 * @since 4.6.2
765 *
766 * @param string|array $name Which file we are talking about including.
767 * If an array, each item will add a directory separator to get to the single template.
768 * @param array $context Any context data you need to expose to this file
769 * @param boolean $echo If we should also print the Template
770 *
771 * @return string|false Either the final content HTML or `false` if no template could be found.
772 */
773 public function template( $name, $context = [], $echo = true ) {
774 static $file_exists = [];
775 static $files = [];
776 static $template_names = [];
777
778 /**
779 * Allow users to disable templates before rendering it by returning empty string.
780 *
781 * @since 4.12.0
782 *
783 * @param string null Whether to continue displaying the template or not.
784 * @param array $name Template name.
785 * @param array $context Any context data you need to expose to this file.
786 * @param boolean $echo If we should also print the Template.
787 */
788 $done = apply_filters( 'tribe_template_done', null, $name, $context, $echo );
789
790 if ( null !== $done ) {
791 return false;
792 }
793
794 // Key we'll use for in-memory caching of expensive operations.
795 $cache_name_key = is_array( $name ) ? implode( '/', $name ) : $name;
796
797 // Cache template name massaging so we don't have to repeat these actions.
798 if ( ! isset( $template_names[ $cache_name_key ] ) ) {
799 // If name is String make it an Array
800 if ( is_string( $name ) ) {
801 $name = (array) explode( '/', $name );
802 }
803
804 // Clean this Variable
805 $name = array_map( 'sanitize_title_with_dashes', $name );
806
807 $template_names[ $cache_name_key ] = $name;
808 }
809
810 // Cache file location and existence.
811 if (
812 ! isset( $file_exists[ $cache_name_key ] )
813 || ! isset( $files[ $cache_name_key ] )
814 ) {
815 // Check if the file exists
816 $files[ $cache_name_key ] = $file = $this->get_template_file( $name );
817
818 // Check if it's a valid variable
819 if ( ! $file ) {
820 return $file_exists[ $cache_name_key ] = false;
821 }
822
823 // Before we load the file we check if it exists
824 if ( ! file_exists( $file ) ) {
825 return $file_exists[ $cache_name_key ] = false;
826 }
827
828 $file_exists[ $cache_name_key ] = true;
829 }
830
831 // If the file doesn't exist, bail.
832 if ( ! $file_exists[ $cache_name_key ] ) {
833 return false;
834 }
835
836 // Use filename stored in cache.
837 $file = $files[ $cache_name_key ];
838 $name = $template_names[ $cache_name_key ];
839 $origin_folder_appendix = array_diff( $this->folder, $this->template_origin_base_folder );
840
841 if ( $origin_namespace = $this->template_get_origin_namespace( $file ) ) {
842 $legacy_namespace = array_merge( (array) $origin_namespace, $name );
843 $namespace = array_merge( (array) $origin_namespace, $origin_folder_appendix, $name );
844 } else {
845 $legacy_namespace = $name;
846 $namespace = array_merge( $origin_folder_appendix, $legacy_namespace );
847 }
848
849 // Setup the Hook name.
850 $legacy_hook_name = implode( '/', $legacy_namespace );
851 $hook_name = implode( '/', $namespace );
852 $prev_hook_name = $this->get_template_current_hook_name();
853
854 // Store the current hook name for the purposes of entry-points.
855 $this->set_template_current_hook_name( $hook_name );
856
857 /**
858 * Allow users to filter the HTML before rendering
859 *
860 * @since 4.11.0
861 *
862 * @param string $html The initial HTML
863 * @param string $file Complete path to include the PHP File
864 * @param array $name Template name
865 * @param self $template Current instance of the Tribe__Template
866 */
867 $pre_html = apply_filters( 'tribe_template_pre_html', null, $file, $name, $this );
868
869 /**
870 * Allow users to filter the HTML by the name before rendering
871 *
872 * E.g.:
873 * `tribe_template_pre_html:events/blocks/parts/details`
874 * `tribe_template_pre_html:events/embed`
875 * `tribe_template_pre_html:tickets/login-to-purchase`
876 *
877 * @since 4.11.0
878 *
879 * @param string $html The initial HTML
880 * @param string $file Complete path to include the PHP File
881 * @param array $name Template name
882 * @param self $template Current instance of the Tribe__Template
883 */
884 $pre_html = apply_filters( "tribe_template_pre_html:{$hook_name}", $pre_html, $file, $name, $this );
885
886 if ( null !== $pre_html ) {
887 return $pre_html;
888 }
889
890 // Merges the local data passed to template to the global scope
891 $this->merge_context( $context, $file, $name );
892
893 $before_include_html = $this->actions_before_template( $file, $name, $hook_name );
894 $before_include_html = $this->filter_template_before_include_html( $before_include_html, $file, $name, $hook_name );
895
896 $include_html = $this->template_safe_include( $file );
897 $include_html = $this->filter_template_include_html( $include_html, $file, $name, $hook_name );
898
899 $after_include_html = $this->actions_after_template( $file, $name, $hook_name );
900 $after_include_html = $this->filter_template_after_include_html( $after_include_html, $file, $name, $hook_name );
901
902 // Only fetch the contents after the action
903 $html = $before_include_html . $include_html . $after_include_html;
904
905 $html = $this->filter_template_html( $html, $file, $name, $hook_name );
906
907 // Tries to hook container entry points in the HTML.
908 $html = $this->template_hook_container_entry_points( $html );
909
910 if ( $echo ) {
911 echo $html;
912 }
913
914 // Revert the current hook name.
915 $this->set_template_current_hook_name( $prev_hook_name );
916
917 return $html;
918 }
919
920 /**
921 * Run the hooks for the container entry points.
922 *
923 * @since 4.12.1
924 *
925 * @param string $html The html of the current template.
926 *
927 * @return string|false Either the final entry point content HTML or `false` if no entry point could be found or set to false.
928 */
929 private function template_hook_container_entry_points( $html ) {
930
931 $matches = $this->get_entry_point_matches( $html );
932 $html_matches = $matches[0];
933
934 if ( 0 === count( $html_matches ) ) {
935 return $html;
936 }
937
938 $html_tags = $matches['tag'];
939 $html_tags_ends = $matches['is_end'];
940
941 // Get first and last tags.
942 $first_tag = reset( $html_tags );
943 $last_tag = end( $html_tags );
944
945 // Determine if first last tags are tag ends.
946 $first_tag_is_end = '/' === reset( $html_tags_ends );
947 $last_tag_is_end = '/' === end( $html_tags_ends );
948
949 // When first and last tag are not the same, bail.
950 if ( $first_tag !== $last_tag ) {
951 return $html;
952 }
953
954 // If the first tag is a html tag end, bail.
955 if ( $first_tag_is_end ) {
956 return $html;
957 }
958
959 // If the last tag is not and html tag end, bail.
960 if ( ! $last_tag_is_end ) {
961 return $html;
962 }
963
964 $first_tag_html = reset( $html_matches );
965 $last_tag_html = end( $html_matches );
966
967 $open_container_entry_point_html = $this->do_entry_point( 'after_container_open', false );
968 $close_container_entry_point_html = $this->do_entry_point( 'before_container_close', false );
969
970 $html = Strings::replace_first( $first_tag_html, $first_tag_html . $open_container_entry_point_html, $html );
971 $html = Strings::replace_last( $last_tag_html, $close_container_entry_point_html . $last_tag_html, $html );
972
973 return $html;
974 }
975
976 /**
977 * Based on a path it determines what is the namespace that should be used.
978 *
979 * @since 4.11.0
980 *
981 * @param string $path Which file we are going to load.
982 *
983 * @return string|false The found namespace for that path or false.
984 */
985 public function template_get_origin_namespace( $path ) {
986 $matching_namespace = false;
987 /**
988 * Allows more namespaces to be added based on the path of the file we are loading.
989 *
990 * @since 4.11.0
991 *
992 * @param array $namespace_map Indexed array containing the namespace as the key and path to `strpos`.
993 * @param string $path Path we will do the `strpos` to validate a given namespace.
994 * @param self $template Current instance of the template class.
995 */
996 $namespace_map = (array) apply_filters( 'tribe_template_origin_namespace_map', [], $path, $this );
997
998 foreach ( $namespace_map as $namespace => $contains_string ) {
999 // Normalize the trailing slash to the current OS directory separator.
1000 $contains_string = rtrim( $contains_string, '\\/' ) . DIRECTORY_SEPARATOR;
1001
1002 // Skip when we don't have the namespace path.
1003 if ( false === strpos( $path, $contains_string ) ) {
1004 continue;
1005 }
1006
1007 $matching_namespace = $namespace;
1008
1009 // Once the first namespace is found it breaks out.
1010 break;
1011 }
1012
1013 if ( empty( $matching_namespace ) && ! empty( $this->origin->template_namespace ) ) {
1014 $matching_namespace = $this->origin->template_namespace;
1015 }
1016
1017 return $matching_namespace;
1018 }
1019
1020 /**
1021 * Includes a give PHP inside of a safe context.
1022 *
1023 * This method is required to prevent template files messing with local variables used inside of the
1024 * `self::template` method. Also shelters the template loading from any possible variables that could
1025 * be overwritten by the context.
1026 *
1027 * @since 4.11.0
1028 *
1029 * @param string $file Which file will be included with safe context.
1030 *
1031 * @return string Contents of the included file.
1032 */
1033 public function template_safe_include( $file ) {
1034 ob_start();
1035 // We use this instance variable to prevent collisions.
1036 $this->template_current_file_path = $file;
1037 unset( $file );
1038
1039 // Only do this if really needed (by default it won't).
1040 if ( true === $this->template_context_extract && ! empty( $this->context ) ) {
1041 // Make any provided variables available in the template variable scope.
1042 extract( $this->context ); // @phpcs:ignore
1043 }
1044
1045 include $this->template_current_file_path;
1046
1047 // After the include we reset the variable.
1048 unset( $this->template_current_file_path );
1049 return ob_get_clean();
1050 }
1051
1052 /**
1053 * Sets a number of values at the same time.
1054 *
1055 * @since 4.9.11
1056 *
1057 * @param array $values An associative key/value array of the values to set.
1058 * @param bool $is_local Whether to set the values as global or local; defaults to local as the `set` method does.
1059 *
1060 * @see Tribe__Template::set()
1061 */
1062 public function set_values( array $values = [], $is_local = true ) {
1063 foreach ( $values as $key => $value ) {
1064 $this->set( $key, $value, $is_local );
1065 }
1066 }
1067
1068 /**
1069 * Returns the Template global context.
1070 *
1071 * @since 4.9.11
1072 *
1073 * @return array An associative key/value array of the Template global context.
1074 */
1075 public function get_global_values() {
1076 return $this->global;
1077 }
1078
1079 /**
1080 * Returns the Template local context.
1081 *
1082 * @since 4.9.11
1083 *
1084 * @return array An associative key/value array of the Template local context.
1085 */
1086 public function get_local_values() {
1087 return $this->context;
1088 }
1089
1090 /**
1091 * Returns the Template global and local context values.
1092 *
1093 * Local values will override the template global context values.
1094 *
1095 * @since 4.9.11
1096 *
1097 * @return array An associative key/value array of the Template global and local context.
1098 */
1099 public function get_values() {
1100 return array_merge( $this->get_global_values(), $this->get_local_values() );
1101 }
1102
1103 /**
1104 * Get the Entry Point Matches.
1105 *
1106 * @since 4.12.1
1107 *
1108 * @param string $html The html of the current template.
1109 *
1110 * @return array An array of matches from the regular expression.
1111 */
1112 private function get_entry_point_matches( $html ) {
1113 $regexp = '/<(?<is_end>\/)*(?<tag>[A-Z0-9]*)(?:\b)*[^>]*>/mi';
1114
1115 preg_match_all( $regexp, $html, $matches );
1116
1117 return $matches;
1118 }
1119
1120 /**
1121 * Fetches the path for locating files in the Common folder part of the plugin that is currently providing it.
1122 *
1123 * Note: the Common path will be dependent on the version that is loaded from the plugin that is bundling it.
1124 * E.g. if both TEC and ET are active (both will bundle Common) and the ET version of Common has been loaded as
1125 * most recent and the ET version of Common does not have a template file, then the template file will not be found.
1126 * This will allow versioning the existence and nature of the template files part of common.
1127 *
1128 * @since 4.12.10
1129 *
1130 * @return string The absolute path, with no guarantee of its existence, to the Common version of the template file.
1131 */
1132 protected function get_template_common_path() {
1133 // As base path use the current location of Common, remove the trailing slash.
1134 $common_abs_path = untrailingslashit( Tribe__Main::instance()->plugin_path );
1135 $path = array_merge( (array) $common_abs_path, $this->folder );
1136
1137 // Implode to avoid problems on Windows hosts.
1138 $path = implode( DIRECTORY_SEPARATOR, $path );
1139
1140 /**
1141 * Allows filtering the path to a template provided by Common.
1142 *
1143 * @since 4.12.10
1144 *
1145 * @param string $path Complete path to include the base folder of common part of the plugin.
1146 * @param self $template Current instance of the Tribe__Template.
1147 */
1148 return apply_filters( 'tribe_template_common_path', $path, $this );
1149 }
1150
1151 /**
1152 * Sets the aliases the template should use.
1153 *
1154 * @since 4.12.10
1155 *
1156 * @param array<string,string> $aliases A map of aliases that should be used to add lookup locations, in the format
1157 * `[ original => alias ]`;
1158 *
1159 * @return static This instance, for method chaining.
1160 */
1161 public function set_aliases( array $aliases = [] ) {
1162 $this->aliases = $aliases;
1163
1164 return $this;
1165 }
1166
1167 /**
1168 * Applies the template path aliases, if any, to a list of folders.
1169 *
1170 * @since 4.12.10
1171 *
1172 * @param array<string,array> $folders The list of folder to apply the aliases to, if any.
1173 *
1174 * @return array<string,array> The list of new folder entries to add to the folders, in the same input format of the
1175 * folders.
1176 */
1177 protected function apply_aliases( array $folders ) {
1178 $new_folders = [];
1179 if ( ! empty( $this->aliases ) ) {
1180 foreach ( $folders as $folder_name => $folder ) {
1181 $original_path = $folder['path'];
1182 foreach ( $this->aliases as $original => $alias ) {
1183 // Since an alias could be a path, we take care to handle it with the current directory separator.
1184 list( $normalized_original, $normalized_alias ) = str_replace(['\\','/'] , DIRECTORY_SEPARATOR, [ $original, $alias ] );
1185 if ( false === strpos( $original_path, $normalized_original ) ) {
1186 continue;
1187 }
1188
1189 $alias_path = str_replace( $normalized_original, $normalized_alias, $original_path );
1190
1191 $new = $folder;
1192 $new['path'] = $alias_path;
1193 $new['priority'] = (int) $new['priority'] + 1;
1194 $new_folders[ $folder_name . '_' . $alias ] = $new;
1195 }
1196 }
1197 }
1198 return $new_folders;
1199 }
1200
1201
1202 /**
1203 * Filters the full HTML for the template.
1204 *
1205 * @since 4.13.0
1206 *
1207 * @param string $html The final HTML.
1208 * @param string $file Complete path to include the PHP File.
1209 * @param array $name Template name.
1210 * @param string $hook_name The hook used to create the filter by name.
1211 *
1212 * @return string HTML after filtering.
1213 */
1214 protected function filter_template_html( $html, $file, $name, $hook_name ) {
1215 /**
1216 * Allow users to filter the final HTML.
1217 *
1218 * @since 4.6.2
1219 * @since 4.7.20 The $name param no longer contains the extension
1220 *
1221 * @param string $html The final HTML.
1222 * @param string $file Complete path to include the PHP File.
1223 * @param array $name Template name.
1224 * @param self $template Current instance of the Tribe__Template.
1225 */
1226 $html = apply_filters( 'tribe_template_html', $html, $file, $name, $this );
1227
1228 /**
1229 * Allow users to filter the final HTML by the name.
1230 *
1231 * E.g.:
1232 * `tribe_template_html:events/blocks/parts/details`
1233 * `tribe_template_html:events/embed`
1234 * `tribe_template_html:tickets/login-to-purchase`
1235 *
1236 * @since 4.7.20
1237 *
1238 * @param string $html The final HTML.
1239 * @param string $file Complete path to include the PHP File.
1240 * @param array $name Template name.
1241 * @param self $template Current instance of the Tribe__Template.
1242 */
1243 $html = apply_filters( "tribe_template_html:{$hook_name}", $html, $file, $name, $this );
1244
1245 return $html;
1246 }
1247
1248 /**
1249 * Filters the HTML for the Before include actions.
1250 *
1251 * @since 4.13.0
1252 *
1253 * @param string $html The final HTML.
1254 * @param string $file Complete path to include the PHP File.
1255 * @param array $name Template name.
1256 * @param string $hook_name The hook used to create the filter by name.
1257 *
1258 * @return string HTML after filtering.
1259 */
1260 protected function filter_template_before_include_html( $html, $file, $name, $hook_name ) {
1261 /**
1262 * Allow users to filter the Before include actions.
1263 *
1264 * @since 4.13.0
1265 *
1266 * @param string $html The final HTML.
1267 * @param string $file Complete path to include the PHP File.
1268 * @param array $name Template name.
1269 * @param self $template Current instance of the Tribe__Template.
1270 */
1271 $html = apply_filters( 'tribe_template_before_include_html', $html, $file, $name, $this );
1272
1273 /**
1274 * Allow users to filter the Before include actions by name.
1275 *
1276 * E.g.:
1277 * `tribe_template_before_include_html:events/blocks/parts/details`
1278 * `tribe_template_before_include_html:events/embed`
1279 * `tribe_template_before_include_html:tickets/login-to-purchase`
1280 *
1281 * @since 4.13.0
1282 *
1283 * @param string $html The final HTML.
1284 * @param string $file Complete path to include the PHP File.
1285 * @param array $name Template name.
1286 * @param self $template Current instance of the Tribe__Template.
1287 */
1288 $html = apply_filters( "tribe_template_before_include_html:{$hook_name}", $html, $file, $name, $this );
1289
1290 return $html;
1291 }
1292
1293 /**
1294 * Filters the HTML for the PHP safe include.
1295 *
1296 * @since 4.13.0
1297 *
1298 * @param string $html The final HTML.
1299 * @param string $file Complete path to include the PHP File.
1300 * @param array $name Template name.
1301 * @param string $hook_name The hook used to create the filter by name.
1302 *
1303 * @return string HTML after filtering.
1304 */
1305 protected function filter_template_include_html( $html, $file, $name, $hook_name ) {
1306 /**
1307 * Allow users to filter the PHP template include actions.
1308 *
1309 * @since 4.13.0
1310 *
1311 * @param string $html The final HTML.
1312 * @param string $file Complete path to include the PHP File.
1313 * @param array $name Template name.
1314 * @param self $template Current instance of the Tribe__Template.
1315 */
1316 $html = apply_filters( 'tribe_template_include_html', $html, $file, $name, $this );
1317
1318 /**
1319 * Allow users to filter the PHP template include actions by name.
1320 *
1321 * E.g.:
1322 * `tribe_template_include_html:events/blocks/parts/details`
1323 * `tribe_template_include_html:events/embed`
1324 * `tribe_template_include_html:tickets/login-to-purchase`
1325 *
1326 * @since 4.13.0
1327 *
1328 * @param string $html The final HTML.
1329 * @param string $file Complete path to include the PHP File.
1330 * @param array $name Template name.
1331 * @param self $template Current instance of the Tribe__Template.
1332 */
1333 $html = apply_filters( "tribe_template_include_html:{$hook_name}", $html, $file, $name, $this );
1334
1335 return $html;
1336 }
1337
1338 /**
1339 * Filters the HTML for the after include actions.
1340 *
1341 * @since 4.13.0
1342 *
1343 * @param string $html The final HTML.
1344 * @param string $file Complete path to include the PHP File.
1345 * @param array $name Template name.
1346 * @param string $hook_name The hook used to create the filter by name.
1347 *
1348 * @return string HTML after filtering.
1349 */
1350 protected function filter_template_after_include_html( $html, $file, $name, $hook_name ) {
1351 /**
1352 * Allow users to filter the after include actions.
1353 *
1354 * @since 4.13.0
1355 *
1356 * @param string $html The final HTML.
1357 * @param string $file Complete path to include the PHP File.
1358 * @param array $name Template name.
1359 * @param self $template Current instance of the Tribe__Template.
1360 */
1361 $html = apply_filters( 'tribe_template_after_include_html', $html, $file, $name, $this );
1362
1363 /**
1364 * Allow users to filter the after include actions by name.
1365 *
1366 * E.g.:
1367 * `tribe_template_after_include_html:events/blocks/parts/details`
1368 * `tribe_template_after_include_html:events/embed`
1369 * `tribe_template_after_include_html:tickets/login-to-purchase`
1370 *
1371 * @since 4.13.0
1372 *
1373 * @param string $html The final HTML.
1374 * @param string $file Complete path to include the PHP File.
1375 * @param array $name Template name.
1376 * @param self $template Current instance of the Tribe__Template.
1377 */
1378 $html = apply_filters( "tribe_template_after_include_html:{$hook_name}", $html, $file, $name, $this );
1379
1380 return $html;
1381 }
1382
1383 /**
1384 * Fires of actions before including the template.
1385 *
1386 * @since 4.13.0
1387 *
1388 * @param string $file Complete path to include the PHP File.
1389 * @param array $name Template name.
1390 * @param string $hook_name The hook used to create the filter by name.
1391 *
1392 * @return string HTML printed by the before actions.
1393 */
1394 protected function actions_before_template( $file, $name, $hook_name ) {
1395 ob_start();
1396
1397 /**
1398 * Fires an Action before including the template file
1399 *
1400 * @since 4.13.0
1401 *
1402 * @param string $file Complete path to include the PHP File
1403 * @param array $name Template name
1404 * @param self $template Current instance of the Tribe__Template
1405 */
1406 do_action( 'tribe_template_before_include', $file, $name, $this );
1407
1408 /**
1409 * Fires an Action for a given template name before including the template file,
1410 *
1411 * E.g.:
1412 * `tribe_template_before_include:events/blocks/parts/details`
1413 * `tribe_template_before_include:events/embed`
1414 * `tribe_template_before_include:tickets/login-to-purchase`
1415 *
1416 * @since 4.13.0
1417 *
1418 * @param string $file Complete path to include the PHP File.
1419 * @param array $name Template name.
1420 * @param self $template Current instance of the Tribe__Template.
1421 */
1422 do_action( "tribe_template_before_include:{$hook_name}", $file, $name, $this );
1423
1424 return ob_get_clean();
1425 }
1426
1427 /**
1428 * Fires of actions after including the template.
1429 *
1430 * @since 4.13.0
1431 *
1432 * @param string $file Complete path to include the PHP File.
1433 * @param array $name Template name.
1434 * @param string $hook_name The hook used to create the filter by name.
1435 *
1436 * @return string HTML printed by the after actions.
1437 */
1438 protected function actions_after_template( $file, $name, $hook_name ) {
1439 ob_start();
1440 /**
1441 * Fires an Action after including the template file.
1442 *
1443 * @since 4.13.0
1444 *
1445 * @param string $file Complete path to include the PHP File.
1446 * @param array $name Template name.
1447 * @param self $template Current instance of the Tribe__Template.
1448 */
1449 do_action( 'tribe_template_after_include', $file, $name, $this );
1450
1451 /**
1452 * Fires an Action for a given template name after including the template file.
1453 *
1454 * E.g.:
1455 * `tribe_template_after_include:events/blocks/parts/details`
1456 * `tribe_template_after_include:events/embed`
1457 * `tribe_template_after_include:tickets/login-to-purchase`
1458 *
1459 * @since 4.13.0
1460 *
1461 * @param string $file Complete path to include the PHP File.
1462 * @param array $name Template name.
1463 * @param self $template Current instance of the Tribe__Template.
1464 */
1465 do_action( "tribe_template_after_include:{$hook_name}", $file, $name, $this );
1466 return ob_get_clean();
1467 }
1468 }
1469