PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / trunk
Pods – Custom Content Types and Fields vtrunk
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 / components / Templates / includes / functions-view_template.php
pods / components / Templates / includes Last commit date
auto-template 4 months ago element-pod_reference-content.php 4 months ago element-pod_reference.php 4 months ago element-view_template.php 4 months ago functions-pod_reference.php 4 months ago functions-view_template.php 4 months ago
functions-view_template.php
989 lines
1 <?php
2
3 // Don't load directly.
4 if ( ! defined( 'ABSPATH' ) ) {
5 die( '-1' );
6 }
7
8 /**
9 * Utility function for processesing frontier based templates
10 *
11 * @package Pods_Frontier_Template_Editor\view_template
12 */
13
14 use Pods\Whatsit\Pod;
15 use Pods\Whatsit\Field;
16
17 // add filters
18 add_filter( 'pods_templates_post_template', 'frontier_end_template', 25, 4 );
19 add_filter( 'pods_templates_do_template', 'frontier_do_shortcode', 25, 1 );
20
21 // template shortcode handlers
22 add_shortcode( 'pod_once_template', 'frontier_template_once_blocks' );
23 add_shortcode( 'pod_after_template', 'frontier_template_blocks' );
24 add_shortcode( 'pod_before_template', 'frontier_template_blocks' );
25 add_shortcode( 'pod_if_field', 'frontier_if_block' );
26
27 /**
28 * Return array of valid frontier type shortcode tags
29 *
30 * @return array
31 */
32 function frontier_get_shortcodes() {
33
34 $shortcodes = [
35 'each',
36 'pod_sub_template',
37 'once',
38 'pod_once_template',
39 'before',
40 'pod_before_template',
41 'after',
42 'pod_after_template',
43 'if',
44 'pod_if_field',
45 ];
46
47 return $shortcodes;
48 }
49
50 /**
51 * @param $content
52 *
53 * @return string
54 * @since 2.4.3
55 */
56 function frontier_do_shortcode( $content ) {
57 // Run only Pods template shortcodes (each, once, before, after, if, and else).
58 return pods_do_shortcode( $content, frontier_get_shortcodes() );
59 }
60
61 /**
62 * @param $content
63 *
64 * @return string
65 * @since 2.8.6
66 */
67 function frontier_do_other_shortcodes( $content ) {
68 // Run all other shortcodes but ignore the Pods template shortcodes (each, once, before, after, if, and else).
69 return pods_do_shortcode( $content, [], frontier_get_shortcodes() );
70 }
71
72 /**
73 * decodes a like nested shortcode based template
74 *
75 * @param string encoded template to be decoded
76 * @param array attributed provided from parent
77 *
78 * @return string
79 * @since 2.4.0
80 */
81 function frontier_decode_template( $code, $atts ) {
82 $code = base64_decode( $code );
83
84 if ( isset( $atts['pod'] ) ) {
85 $code = str_replace( '{@pod}', $atts['pod'], $code );
86 }
87 if ( isset( $atts['id'] ) ) {
88 $code = str_replace( '{@EntryID}', $atts['id'], $code );
89 }
90 if ( isset( $atts['index'] ) ) {
91 $code = str_replace( '{_index}', $atts['index'], $code );
92 }
93
94 return $code;
95 }
96
97 /**
98 * processes if condition within a template
99 *
100 * @param array $attributes attributes from template
101 * @param string $code encoded template to be decoded
102 *
103 * @return string
104 * @since 2.4.0
105 */
106 function frontier_if_block( $attributes, $code ) {
107 $attributes = array_merge( [
108 'pod' => null,
109 'id' => null,
110 'field' => null,
111 'value' => null,
112 'compare' => null,
113 'index' => null,
114 ], $attributes );
115
116 $pod = Pods_Templates::get_obj( $attributes['pod'], $attributes['id'] );
117
118 if ( ! $pod || ! $pod->exists() ) {
119 return '';
120 }
121
122 $code = explode( '[else]', frontier_decode_template( $code, $attributes ) );
123
124 // field data
125 $field_data = null;
126 $field_type = 'text';
127
128 if ( ! empty( $attributes['field'] ) ) {
129 $supported_calculations = [
130 '_zebra' => 'number',
131 '_position' => 'number',
132 '_total' => 'number',
133 '_total_found' => 'number',
134 '_total_all_rows' => 'number',
135 '_total_pages' => 'number',
136 '_current_page' => 'number',
137 ];
138
139 if ( isset( $supported_calculations[ $attributes['field'] ] ) ) {
140 // Support [if field="_position" value="2"] and other calculation value handlers.
141 $field_data = $pod->field( $attributes['field'] );
142 $field_type = $supported_calculations[ $attributes['field'] ];
143 } elseif ( '_index' === $attributes['field'] ) {
144 $field_data = pods_v( 'index', $attributes );
145 } else {
146 $field_data = $pod->field( $attributes['field'] );
147 $field_type = $pod->fields( $attributes['field'], 'type' );
148 }
149 }
150
151 $is_empty = true;
152
153 if ( null !== $field_data ) {
154 if ( empty( $field_type ) ) {
155 $field_type = 'text';
156 }
157
158 $is_empty = PodsForm::field_method( $field_type, 'values_are_empty', $field_data );
159 }
160
161 $has_value_compare_attribute = null !== $attributes['value'] || null !== $attributes['compare'];
162
163 if ( ! $is_empty || $has_value_compare_attribute ) {
164 // Check if we do not have a value to compare with.
165 if ( ! $has_value_compare_attribute ) {
166 $template = $code[0];
167
168 // Maybe run any shortcode.
169 if ( defined( 'PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES' ) && PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES ) {
170 $template = frontier_do_other_shortcodes( $template );
171 }
172
173 // Field exists and is not empty, use [IF] content
174 $template = $pod->do_magic_tags( $template );
175
176 return frontier_do_shortcode( $template );
177 }
178
179 $first_character = $attributes['value'] ? substr( (string) $attributes['value'], 0, 1 ) : null;
180
181 // check if + or - are present
182 if ( '+' === $first_character ) {
183 // is greater
184 $attributes['value'] = (float) substr( (string) $attributes['value'], 1 ) + 1;
185 $attributes['compare'] = '>';
186 } elseif ( '-' === $first_character ) {
187 // is smaller
188 $attributes['value'] = (float) substr( (string) $attributes['value'], 1 ) - 1;
189 $attributes['compare'] = '<';
190 }
191
192 if ( empty( $attributes['compare'] ) ) {
193 $attributes['compare'] = '=';
194 }
195
196 $attributes['compare'] = pods_replace_gt_et_placeholders( $attributes['compare'] );
197 $attributes['compare'] = strtoupper( $attributes['compare'] );
198
199 // Normalize the compare.
200 $comparisons = [
201 '=',
202 '!=',
203 'IN',
204 'NOT IN',
205 'EXISTS',
206 'NOT EXISTS',
207 '>',
208 '>=',
209 '<',
210 '<=',
211 'LIKE',
212 'NOT LIKE',
213 'EMPTY',
214 'NOT EMPTY',
215 ];
216
217 // Comparison not supported, assume it does not match.
218 if ( ! in_array( $attributes['compare'], $comparisons, true ) ) {
219 return '';
220 }
221
222 $pass = false;
223
224 $maybe_array = is_array( $field_data ) || is_array( $attributes['value'] );
225
226 // Handle comparison.
227 if ( '=' === $attributes['compare'] ) {
228 if ( $maybe_array ) {
229 $pass = in_array( (string) $attributes['value'], (array) $field_data, false );
230 } else {
231 $pass = (string) $field_data === (string) $attributes['value'];
232 }
233 } elseif ( '!=' === $attributes['compare'] ) {
234 if ( $maybe_array ) {
235 $pass = ! in_array( (string) $attributes['value'], (array) $field_data, false );
236 } else {
237 $pass = (string) $field_data !== (string) $attributes['value'];
238 }
239 } elseif ( 'EXISTS' === $attributes['compare'] ) {
240 $pass = null !== $field_data && [] !== $field_data;
241 } elseif ( 'NOT EXISTS' === $attributes['compare'] ) {
242 $pass = null === $field_data || [] === $field_data;
243 } elseif ( $maybe_array ) {
244 // We do not support comparisons for array values beyond equals.
245 $pass = false;
246 } elseif ( 'IN' === $attributes['compare'] ) {
247 $pass = in_array( (string) $field_data, explode( ',', $attributes['value'] ), false );
248 } elseif ( 'NOT IN' === $attributes['compare'] ) {
249 $pass = ! in_array( (string) $field_data, explode( ',', $attributes['value'] ), false );
250 } elseif ( '>' === $attributes['compare'] ) {
251 $pass = (float) $field_data > (float) $attributes['value'];
252 } elseif ( '>=' === $attributes['compare'] ) {
253 $pass = (float) $field_data >= (float) $attributes['value'];
254 } elseif ( '<' === $attributes['compare'] ) {
255 $pass = (float) $field_data < (float) $attributes['value'];
256 } elseif ( '<=' === $attributes['compare'] ) {
257 $pass = (float) $field_data <= (float) $attributes['value'];
258 } elseif ( 'LIKE' === $attributes['compare'] || 'NOT LIKE' === $attributes['compare'] ) {
259 $field_data = (string) $field_data;
260
261 $attributes['value'] = (string) $attributes['value'];
262
263 if ( false !== strpos( $attributes['value'], '%' ) ) {
264 // Handle % LIKE values.
265 $attributes['value'] = str_replace( '%', '.*', preg_quote( $attributes['value'], '/' ) );
266
267 $found = preg_match( '/^' . $attributes['value'] . '$/Uim', $field_data );
268
269 if ( 0 === $found ) {
270 $found = false;
271 }
272 } else {
273 $found = stripos( $field_data, $attributes['value'] );
274 }
275
276 if ( 'LIKE' === $attributes['compare'] ) {
277 // Check if the string contains the match.
278 $pass = false !== $found;
279 } elseif ( 'NOT LIKE' === $attributes['compare'] ) {
280 // Check if the string does not contain the match.
281 $pass = false === $found;
282 }
283 } elseif ( 'EMPTY' === $attributes['compare'] ) {
284 $pass = $is_empty;
285 } elseif ( 'NOT EMPTY' === $attributes['compare'] ) {
286 $pass = ! $is_empty;
287 }
288
289 if ( $pass ) {
290 $template = $code[0];
291
292 // Maybe run any shortcode.
293 if ( defined( 'PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES' ) && PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES ) {
294 $template = frontier_do_other_shortcodes( $template );
295 }
296
297 // IF statement true, use [IF] content as template.
298 $template = $pod->do_magic_tags( $template );
299
300 return frontier_do_shortcode( $template );
301 }
302
303 if ( isset( $code[1] ) ) {
304 $template = $code[1];
305
306 // Maybe run any shortcode.
307 if ( defined( 'PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES' ) && PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES ) {
308 $template = frontier_do_other_shortcodes( $template );
309 }
310
311 // There is an [ELSE] tag
312 $template = $pod->do_magic_tags( $template );
313
314 return frontier_do_shortcode( $template );
315 }
316
317 // Value did not match (and no [ELSE]), nothing should be displayed.
318 return '';
319 }
320
321 if ( isset( $code[1] ) ) {
322 $template = $code[1];
323
324 // Maybe run any shortcode.
325 if ( defined( 'PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES' ) && PODS_TEMPLATES_ALLOW_OTHER_SHORTCODES ) {
326 $template = frontier_do_other_shortcodes( $template );
327 }
328
329 // No value or field is empty and there is an [ELSE] tag. Use [ELSE].
330 $template = $pod->do_magic_tags( $template );
331
332 return frontier_do_shortcode( $template );
333 }
334
335 // No match at all for the format we support.
336 return '';
337 }
338
339 /**
340 * processes before and after template blocks
341 *
342 * @param array attributes from template
343 * @param string encoded template to be decoded
344 * @param string shortcode slug used to process
345 *
346 * @return null
347 * @since 2.4.0
348 */
349 function frontier_template_blocks( $atts, $code, $slug ) {
350
351 global $pods_template_post_blocks;
352 if ( ! isset( $pods_template_post_blocks ) ) {
353 $pods_template_post_blocks = [
354 'before' => null,
355 'after' => null,
356 ];
357 }
358 if ( $slug === 'pod_before_template' ) {
359 if ( ! isset( $pods_template_post_blocks['before'][ $atts['pod'] ] ) ) {
360 $pods_template_post_blocks['before'][ $atts['pod'] ] = pods_do_shortcode(
361 frontier_decode_template( $code, $atts ), [
362 'if',
363 'else',
364 ]
365 );
366 }
367 } elseif ( $slug === 'pod_after_template' ) {
368 if ( ! isset( $pods_template_post_blocks['after'][ $atts['pod'] ] ) ) {
369 $pods_template_post_blocks['after'][ $atts['pod'] ] = pods_do_shortcode(
370 frontier_decode_template( $code, $atts ), [
371 'if',
372 'else',
373 ]
374 );
375 }
376 }
377
378 return null;
379 }
380
381 /**
382 * processes once blocks
383 *
384 * @param array attributes from template
385 * @param string encoded template to be decoded
386 *
387 * @return string template code
388 * @since 2.4.0
389 */
390 function frontier_template_once_blocks( $atts, $code ) {
391
392 global $frontier_once_hashes;
393
394 if ( ! isset( $frontier_once_hashes ) ) {
395 $frontier_once_hashes = [];
396 }
397
398 $blockhash = md5( $code . $atts['id'] );
399 if ( in_array( $blockhash, $frontier_once_hashes, true ) ) {
400 return '';
401 }
402 $frontier_once_hashes[] = $blockhash;
403
404 return pods_do_shortcode( frontier_decode_template( $code, $atts ), frontier_get_shortcodes() );
405 }
406
407 /**
408 * processes template code within an each command from the base template
409 *
410 * @param array attributes from template
411 * @param string template to be processed
412 *
413 * @return null
414 * @since 2.4.0
415 */
416 function frontier_do_subtemplate( $atts, $content ) {
417 $out = '';
418 $field_name = $atts['field'];
419
420 $pod = Pods_Templates::get_obj( $atts['pod'], $atts['id'] );
421
422 if ( ! $pod || ! $pod->exists() ) {
423 return '';
424 }
425
426 $field = $pod->fields( $field_name );
427
428 $is_repeatable_field = $field && $field->is_repeatable();
429
430 $entries = $pod->field( [
431 'name' => $field_name,
432 'display' => $is_repeatable_field,
433 'display_process_individually' => $is_repeatable_field,
434 ] );
435
436 if ( $field && ! empty( $entries ) ) {
437 $entries = (array) $entries;
438
439 // Force array even for single items since the logic below is using loops.
440 if (
441 (
442 $is_repeatable_field
443 || 'single' === $field->get_single_multi()
444 )
445 && ! isset( $entries[0] )
446 ) {
447 $entries = [ $entries ];
448 }
449
450 // Object types that could be Pods
451 $object_types = [ 'post_type', 'pod' ];
452
453 if ( $is_repeatable_field ) {
454 foreach ( $entries as $key => $entry ) {
455 $template = frontier_decode_template( $content, $atts );
456
457 $template = str_replace( '{_key}', '{@_index}', $template );
458 $template = str_replace( '{@_key}', '{@_index}', $template );
459 $template = str_replace( '{_index}', '{@_index}', $template );
460
461 $entry = [
462 '_index' => $key,
463 '_value' => $entry,
464 ];
465
466 $out .= frontier_pseudo_magic_tags( $template, $entry, $pod, true );
467 }
468 } /**
469 * Note on the change below for issue #3018:
470 * ... || 'taxonomy' == $pod->fields[ $atts[ 'field' ] ][ 'type' ]
471 *
472 * calling field() above for a taxonomy object field will populate
473 * $pod->fields[ $field_name ] for the object field's data, in this
474 * case a taxonomy object field. Without calling
475 * $pod->field( $field_name ), it would not normally be available in
476 * the $pod->fields array and is something to not expect to be there in
477 * 3.0 as this was unintentional.
478 */
479 elseif ( 'taxonomy' === $field['type'] || in_array( $field['pick_object'], $object_types, true ) ) {
480 // Match any Pod object or taxonomy
481 foreach ( $entries as $key => $entry ) {
482 $subpod = pods_get_instance( $field['pick_val'] );
483
484 if ( ! $subpod || ! $subpod->valid() ) {
485 continue;
486 }
487
488 $subatts = [
489 'id' => $entry[ $subpod->pod_data['field_id'] ],
490 'pod' => $field['pick_val'],
491 ];
492
493 $template = frontier_decode_template( $content, array_merge( $atts, $subatts ) );
494 $template = str_replace( '{_key}', $key, $template );
495 $template = str_replace( '{@_key}', $key, $template );
496 $template = str_replace( '{_index}', $key, $template );
497 $template = str_replace( '{@' . $field_name . '.', '{@', $template );
498
499 // Kludge to work with taxonomies, pending a better solution: see issue #3018
500 $target_id = null;
501 if ( isset( $entry['ID'] ) ) {
502 $target_id = $entry['ID'];
503 } elseif ( isset( $entry['id'] ) ) {
504 // Advanced Content Types have lowercase 'id'
505 $target_id = $entry['id'];
506 } elseif ( isset( $entry['term_id'] ) ) {
507 $target_id = $entry['term_id'];
508 }
509
510 $out .= pods_shortcode_run_safely(
511 [
512 'name' => $field['pick_val'],
513 'slug' => $target_id,
514 'index' => $key,
515 ],
516 $template,
517 false
518 );
519
520 }//end foreach
521 } elseif ( 'file' === $field['type'] ) {
522 $template = frontier_decode_template( $content, $atts );
523 $media_pod = pods( 'media' );
524
525 foreach ( $entries as $key => $entry ) {
526 $template = str_replace( '{_key}', $key, $template );
527 $template = str_replace( '{@_key}', $key, $template );
528 $template = str_replace( '{_index}', $key, $template );
529
530 if ( $media_pod && $media_pod->valid() && $media_pod->fetch( $entry['ID'] ) ) {
531 $template = str_replace( '{@' . $field_name . '.', '{@', $template );
532
533 $entry_pod = $media_pod;
534 } else {
535 $template = str_replace( '{@_img', '{@image_attachment.' . $entry['ID'], $template );
536 $template = str_replace( '{@_src', '{@image_attachment_url.' . $entry['ID'], $template );
537 $template = str_replace( '{@' . $field_name . '}', '{@image_attachment.' . $entry['ID'] . '}', $template );
538
539 // Fix for lowercase ID's.
540 $entry['id'] = $entry['ID'];
541
542 // Allow array-like tags.
543 $template = frontier_pseudo_magic_tags( $template, $entry, $pod, true );
544
545 // Fallback to parent Pod so above tags still work.
546 $entry_pod = $pod;
547 }
548
549 $out .= pods_do_shortcode( $entry_pod->do_magic_tags( $template ), frontier_get_shortcodes() );
550 }
551 } elseif ( isset( $field['table_info'], $field['table_info']['pod'] ) ) {
552 // Relationship to something that is extended by Pods
553 $entries = $pod->field( [ 'name' => $field_name, 'output' => 'pod' ] );
554 foreach ( $entries as $key => $entry ) {
555 if ( ! is_object( $entry ) ) {
556 continue;
557 }
558
559 $subatts = [
560 'id' => $entry->id,
561 'pod' => $entry->pod,
562 'index' => $key,
563 ];
564
565 $template = frontier_decode_template( $content, array_merge( $atts, $subatts ) );
566
567 $template = str_replace( '{_key}', $key, $template );
568 $template = str_replace( '{@_key}', $key, $template );
569 $template = str_replace( '{_index}', $key, $template );
570 $template = str_replace( '{@' . $field_name . '.', '{@', $template );
571
572 $out .= pods_do_shortcode( $entry->do_magic_tags( $template ), frontier_get_shortcodes() );
573 }
574 } else {
575 $template = frontier_decode_template( $content, $atts );
576
577 // Relationship to something other than a Pod (ie: user)
578 foreach ( $entries as $key => $entry ) {
579 $template = frontier_decode_template( $content, $atts );
580
581 $template = str_replace( '{_key}', '{@_index}', $template );
582 $template = str_replace( '{@_key}', '{@_index}', $template );
583 $template = str_replace( '{_index}', '{@_index}', $template );
584
585 if ( ! is_array( $entry ) ) {
586 $entry = [
587 '_index' => $key,
588 '_value' => $entry,
589 ];
590 }
591
592 $out .= pods_do_shortcode( frontier_pseudo_magic_tags( $template, $entry, $pod ), frontier_get_shortcodes() );
593 }
594 }//end if
595 }//end if
596
597 return pods_do_shortcode( $out, frontier_get_shortcodes() );
598 }
599
600 /**
601 * Search and replace like Pods magic tags but with an array of data instead of a Pod
602 *
603 * @param Pod $pod
604 * @param string $template
605 * @param array $data
606 * @param boolean $skip_unknown If true then values not in $data will not be touched
607 *
608 * @return string
609 * @since 2.7.0
610 */
611 function frontier_pseudo_magic_tags( $template, $data, $pod = null, $skip_unknown = false ) {
612 return preg_replace_callback(
613 '/({@(.*?)})/m',
614 function ( $tag ) use ( $pod, $data, $skip_unknown ) {
615 // This is essentially Pods->process_magic_tags() but with the Pods specific code ripped out
616 if ( is_array( $tag ) ) {
617 if ( ! isset( $tag[2] ) && strlen( trim( $tag[2] ) ) < 1 ) {
618 return '';
619 }
620
621 $original_tag = $tag[0];
622 $tag = $tag[2];
623 }
624
625 $tag = trim( $tag, ' {@}' );
626 $tag = explode( ',', $tag );
627
628 if ( empty( $tag ) || ! isset( $tag[0] ) || strlen( trim( $tag[0] ) ) < 1 ) {
629 return '';
630 }
631
632 foreach ( $tag as $k => $v ) {
633 $tag[ $k ] = trim( $v );
634 }
635
636 $field_name = $tag[0];
637
638 $helper_name = '';
639 $before = '';
640 $after = '';
641
642 if ( isset( $data[ $field_name ] ) ) {
643 $value = $data[ $field_name ];
644 if ( isset( $tag[1] ) && ! empty( $tag[1] ) ) {
645 $helper_name = $tag[1];
646
647 if ( isset( $pod ) ) {
648 $value = $pod->helper( $helper_name, $value, $field_name );
649 }
650 }
651 } else {
652 if ( $skip_unknown ) {
653 return $original_tag;
654 }
655 $value = '';
656 }
657
658 if ( isset( $tag[2] ) && ! empty( $tag[2] ) ) {
659 $before = $tag[2];
660 }
661
662 if ( isset( $tag[3] ) && ! empty( $tag[3] ) ) {
663 $after = $tag[3];
664 }
665
666 $value = apply_filters( 'pods_do_magic_tags', $value, $field_name, $helper_name, $before, $after );
667
668 if ( is_array( $value ) ) {
669 $value = pods_serial_comma(
670 $value, [
671 'field' => $field_name,
672 'fields' => $pod->fields,
673 ]
674 );
675 }
676
677 if ( null !== $value && false !== $value ) {
678 return $before . $value . $after;
679 }
680
681 return '';
682 },
683 $template
684 );
685 }
686
687 /**
688 * processes template code within an each command from the base template
689 *
690 * @param string|null $code The code to filter.
691 * @param string $template The template to be processed.
692 * @param Pods $pod The Pods object.
693 *
694 * @return null
695 * @since 2.4.0
696 */
697 function frontier_prefilter_template( $code, $template, $pod ) {
698 $code = (string) $code;
699
700 global $frontier_once_tags;
701
702 $commands = [
703 'each' => 'pod_sub_template',
704 'once' => 'pod_once_template',
705 'before' => 'pod_before_template',
706 'after' => 'pod_after_template',
707 'if' => 'pod_if_field',
708 ];
709
710 if ( ! shortcode_exists( 'pod_sub_template' ) ) {
711 add_shortcode( 'pod_sub_template', 'frontier_do_subtemplate' );
712 }
713
714 $commands = array_merge( $commands, get_option( 'pods_frontier_extra_commands', [] ) );
715
716 /**
717 * Add additional control blocks to Pods templates
718 *
719 * Can also be use to remove each/once/before/after/if functionality from Pods Templates
720 *
721 * @param array $commands The control blocks in the form of 'tag' => 'shortcode'
722 *
723 * @return array An array of control blocks, and shortcodes used to power them.
724 *
725 * @since 1.0.0
726 */
727 $commands = apply_filters( 'pods_frontier_template_commands', $commands );
728
729 $aliases = [];
730 foreach ( $commands as $command => $shortcode ) {
731 //preg_match_all( '/(\[' . $command . '(?<attributes>.*?)]|\[\/' . $command . '\])/m', $code, $matches );
732 preg_match_all( '/('
733 . '\[' . preg_quote( $command, '/' ) . '\s*'
734 . '(?<field_attr>field="(?<field>[^"]*)")*' . '\s*'
735 . '(?<value_attr>value="(?<value>[^"]*)")*' . '\s*'
736 . '(?<compare_attr>compare="(?<compare>[^"]*)")*' . '\s*'
737 . '(?<other_attributes>[^\]]*)'
738 . ']|\[\/' . preg_quote( $command, '/' ) . '\]'
739 . ')/m', $code, $matches );
740
741 if ( ! empty( $matches[0] ) ) {
742 // holder for found tags.
743 $tags = [];
744 $indexCount = 0;
745 foreach ( $matches[0] as $key => $tag ) {
746 if ( false !== strpos( $tag, '[/' ) ) {
747 // close tag
748 $indexCount --;
749 $newclose = $tags[ $indexCount ];
750 $code = preg_replace( '/(' . preg_quote( $tag, '/' ) . ')/m', '[/' . $newclose . ']', $code, 1 );
751
752 continue;
753 }//end if
754
755 // Handle open tags.
756
757 $field = null;
758 $value = null;
759 $compare = null;
760
761 $pod_name = '{@pod}';
762 $ID = '{@EntryID}';
763
764 if ( '' !== $matches['field_attr'][ $key ] ) {
765 $field = $matches['field'][ $key ];
766
767 if ( '' !== $matches['value_attr'][ $key ] ) {
768 $value = $matches['value'][ $key ];
769 }
770
771 if ( '' !== $matches['compare_attr'][ $key ] ) {
772 $compare = $matches['compare'][ $key ];
773 }
774 } elseif ( '' !== $matches['other_attributes'][ $key ] ) {
775 // get atts if any
776 // $atts = shortcode_parse_atts(str_replace('.', '____', $matches[2][$key]));
777 $pattern = '/(?<field>[\w\.\_\-]+)\s*=\s*"(?<value>[^"]*)"(?:\s|$)/';
778 $field = trim( $matches['other_attributes'][ $key ] );
779 $text = preg_replace( "/[\x{00a0}\x{200b}]+/u", ' ', $field );
780
781 if ( preg_match_all( $pattern, $text, $field_value_match, PREG_SET_ORDER ) ) {
782 $field = $field_value_match[0]['field'];
783 $value = $field_value_match[0]['value'];
784 }
785 }//end if
786
787 if ( $field && false !== strpos( (string) $field, '.' ) ) {
788 // Take the last element off of the array and use the ID.
789 $field_path = explode( '.', (string) $field );
790 $last_field = array_pop( $field_path );
791 $field_path = implode( '.', $field_path );
792
793 $related_field = $pod->pod_data->get_field( $field_path );
794
795 if ( $related_field instanceof Field && 1 === $related_field->get_limit() ) {
796 $related_pod = $related_field->get_related_object();
797
798 if ( $related_pod instanceof Pod ) {
799 $table_field_id = $related_pod->get_arg( 'field_id' );
800
801 if ( $table_field_id ) {
802 // Use the other pod.
803 $pod_name = $related_pod->get_name();
804
805 // Rebuild the ID used for the lookup.
806 $ID = '{@' . $field_path . '.' . $table_field_id . '}';
807
808 // Override the field to use.
809 $field = $last_field;
810 }
811 }
812 }
813 }
814
815 $atts = ' pod="' . esc_attr( $pod_name ) . '"';
816 $atts .= ' id="' . esc_attr( $ID ) . '"';
817
818 if ( $field ) {
819 $atts .= ' field="' . esc_attr( $field ) . '"';
820 }
821
822 if ( null !== $value ) {
823 $atts .= ' value="' . esc_attr( $value ) . '"';
824 }
825
826 if ( null !== $compare ) {
827 $atts .= ' compare="' . esc_attr( $compare ) . '"';
828 }
829
830 $newtag = $shortcode . '__' . $key;
831 $tags[ $indexCount ] = $newtag;
832 $aliases[] = $newtag;
833
834 $code = preg_replace( '/(' . preg_quote( $tag, '/' ) . ')/m', '[' . $newtag . $atts . ' index="{_index}"]', $code, 1 );
835
836 $indexCount ++;
837 }//end foreach
838 }//end if
839 }//end foreach
840 // get new aliased shortcodes
841 if ( ! empty( $aliases ) ) {
842 $code = frontier_backtrack_template( $code, $aliases );
843 }
844 $code = str_replace( '{@pod}', $pod->pod, $code );
845 $code = str_replace( '{@EntryID}', '{@' . $pod->pod_data['field_id'] . '}', $code );
846
847 return $code;
848 }
849
850 /**
851 * @param $code
852 * @param $aliases
853 *
854 * @return mixed
855 */
856 function frontier_backtrack_template( $code, $aliases ) {
857
858 $regex = frontier_get_regex( $aliases );
859 preg_match_all( '/' . $regex . '/s', $code, $used );
860
861 if ( ! empty( $used[2] ) ) {
862 foreach ( $used[2] as $key => $alias ) {
863 $shortcodes = explode( '__', $alias );
864 $content = $used[5][ $key ];
865 $atts = shortcode_parse_atts( $used[3][ $key ] );
866
867 $new_shortcode_name = $shortcodes[0];
868
869 $new_shortcode_atts_data = [
870 'seq' => $shortcodes[1],
871 ];
872
873 if ( ! empty( $atts ) ) {
874 if ( ! empty( $atts['field'] ) && false !== strpos( $atts['field'], '.' ) ) {
875 $content = str_replace( $atts['field'] . '.', '', $content );
876 }
877
878 preg_match_all( '/' . $regex . '/s', $content, $subused );
879
880 if ( ! empty( $subused[2] ) ) {
881 $content = frontier_backtrack_template( $content, $aliases );
882 }
883
884 $new_shortcode_atts_data[] = trim( $used[3][ $key ] );
885 }
886
887 $new_shortcode_atts = '';
888
889 foreach ( $new_shortcode_atts_data as $new_shortcode_att_key => $new_shortcode_att_data ) {
890 if ( is_int( $new_shortcode_att_key ) ) {
891 $new_shortcode_atts .= ' ' . $new_shortcode_att_data;
892 } else {
893 $new_shortcode_atts .= ' ' . $new_shortcode_att_key . '="' . esc_attr( $new_shortcode_att_data ) . '"';
894 }
895 }
896
897 // Build the new shortcode.
898 $new_shortcode = sprintf(
899 '[%1$s %2$s]%3$s[/%1$s]',
900 $new_shortcode_name,
901 $new_shortcode_atts,
902 base64_encode( $content )
903 );
904
905 $code = str_replace( $used[0][ $key ], $new_shortcode, $code );
906 }
907 }//end if
908
909 return $code;
910 }
911
912 /**
913 * @param $codes
914 *
915 * @return string
916 */
917 function frontier_get_regex( $codes ) {
918
919 // A custom version of the shortcode regex as to only use podsfrontier codes.
920 // this makes it easier to cycle through and get the used codes for inclusion
921 $validcodes = join( '|', array_map( 'preg_quote', $codes ) );
922
923 $regex_pieces = [
924 // Opening bracket
925 '\\[',
926 // 1: Optional second opening bracket for escaping shortcodes: [[tag]]
927 '(\\[?)',
928 // 2: selected codes only
929 "($validcodes)",
930 // Word boundary
931 '\\b',
932 // 3: Unroll the loop: Inside the opening shortcode tag
933 '(',
934 // Not a closing bracket or forward slash
935 '[^\\]\\/]*',
936 // A forward slash not followed by a closing bracket
937 '(?:' . '\\/(?!\\])',
938 // Not a closing bracket or forward slash
939 '[^\\]\\/]*',
940 // 4: Self closing tag ...
941 ')*?' . ')' . '(?:' . '(\\/)',
942 // ... and closing bracket
943 '\\]',
944 // Closing bracket
945 '|' . '\\]',
946 // 5: Unroll the loop: Optionally, anything between the opening and closing shortcode tags
947 '(?:' . '(',
948 // Not an opening bracket
949 '[^\\[]*+',
950 // An opening bracket not followed by the closing shortcode tag
951 '(?:' . '\\[(?!\\/\\2\\])',
952 // Not an opening bracket
953 '[^\\[]*+',
954 // Closing shortcode tag
955 ')*+' . ')' . '\\[\\/\\2\\]',
956 // 6: Optional second closing brocket for escaping shortcodes: [[tag]]
957 ')?' . ')' . '(\\]?)',
958 ];
959
960 return implode( '', $regex_pieces );
961 }
962
963 /**
964 * @param $code
965 * @param $base
966 * @param $template
967 * @param $pod
968 *
969 * @return string
970 */
971 function frontier_end_template( $code, $base, $template, $pod ) {
972
973 global $pods_template_post_blocks;
974
975 if ( ! empty( $pods_template_post_blocks['before'][ $pod->pod ] ) ) {
976 $code = $pods_template_post_blocks['before'][ $pod->pod ] . $code;
977
978 unset( $pods_template_post_blocks['before'][ $pod->pod ] );
979 }
980
981 if ( ! empty( $pods_template_post_blocks['after'][ $pod->pod ] ) ) {
982 $code .= $pods_template_post_blocks['after'][ $pod->pod ];
983
984 unset( $pods_template_post_blocks['after'][ $pod->pod ] );
985 }
986
987 return pods_do_shortcode( $code, frontier_get_shortcodes() );
988 }
989