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