PluginProbe ʕ •ᴥ•ʔ
Strong Testimonials / 3.3.2
Strong Testimonials v3.3.2
3.3.2 3.3.1 trunk 1.0.1 2.30.9 2.31.10 2.32 2.32.1 2.32.2 2.32.3 2.32.4 2.33 2.34 2.35 2.36 2.37 2.38 2.38.1 2.39 2.39.1 2.39.2 2.39.3 2.40.0 2.40.1 2.40.2 2.40.3 2.40.4 2.40.5 2.40.6 2.40.7 2.41.0 2.41.1 2.50.0 2.50.1 2.50.2 2.50.3 2.50.4 2.51.0 2.51.1 2.51.2 2.51.3 2.51.4 2.51.5 2.51.6 2.51.7 2.51.8 2.51.9 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0
strong-testimonials / includes / class-strong-testimonials-render.php
strong-testimonials / includes Last commit date
elementor 1 year ago logs 1 month ago strong-testimonials-beaver-block 1 year ago submodules 8 months ago class-strong-gutemberg.php 1 year ago class-strong-log.php 1 year ago class-strong-mail.php 1 year ago class-strong-testimonials-average-shortcode.php 1 year ago class-strong-testimonials-count-shortcode.php 1 year ago class-strong-testimonials-defaults.php 1 month ago class-strong-testimonials-form.php 1 month ago class-strong-testimonials-order.php 1 year ago class-strong-testimonials-privacy.php 1 year ago class-strong-testimonials-render.php 1 month ago class-strong-testimonials-templates.php 1 year ago class-strong-testimonials-view-shortcode.php 1 week ago class-strong-testimonials-view-widget.php 1 year ago class-strong-view-display.php 1 day ago class-strong-view-form.php 1 day ago class-strong-view-slideshow.php 1 day ago class-strong-view.php 1 day ago class-walker-strong-category-checklist-front.php 1 year ago deprecated.php 1 year ago filters.php 1 month ago functions-activation.php 1 month ago functions-content.php 11 months ago functions-image.php 5 months ago functions-rating.php 1 year ago functions-template-form.php 1 week ago functions-template.php 4 months ago functions-views.php 1 year ago functions.php 1 month ago l10n-polylang.php 1 year ago l10n-wpml.php 1 year ago post-types.php 1 week ago retro.php 1 year ago scripts.php 1 month ago
class-strong-testimonials-render.php
732 lines
1 <?php
2 /**
3 * Class Strong_Testimonials_Render
4 *
5 * @since 2.28.0
6 */
7 class Strong_Testimonials_Render {
8
9 public $styles = array();
10
11 public $scripts = array();
12
13 public $script_vars = array();
14
15 public $css = array();
16
17 public $shortcode;
18
19 public $view_defaults = array();
20
21 public $view_atts = array();
22
23 public $query;
24
25 /**
26 * Strong_Testimonials_Render constructor.
27 */
28 public function __construct() {
29 $this->set_view_defaults();
30 $this->set_shortcodes();
31 $this->add_enqueue_actions();
32 }
33
34 /**
35 * Set the defaults for a view.
36 */
37 public function set_view_defaults() {
38 $this->view_defaults = wpmtst_get_view_default();
39 }
40
41 /**
42 * Get the shortcode defaults.
43 *
44 * @return array
45 */
46 public function get_view_defaults() {
47 return $this->view_defaults;
48 }
49
50 /**
51 * Set shortcode.
52 */
53 public function set_shortcodes() {
54 $this->shortcode = WPMST()->shortcode->get_shortcode();
55 }
56
57 /**
58 * Store view attributes.
59 *
60 * @param $atts
61 */
62 public function set_atts( $atts ) {
63 $this->view_atts = $atts;
64 }
65
66 /**
67 * Load scripts and styles.
68 *
69 * @since 2.28.0
70 */
71 private function add_enqueue_actions() {
72 $options = apply_filters( 'wpmtst_compat_options', get_option( 'wpmtst_compat_options', array() ) );
73
74 /**
75 * Fallback.
76 * Provision each view when the shortcode is rendered.
77 * Enqueue both stylesheets and scripts in footer.
78 * _!_ Required for template function. _!_
79 */
80 add_action( 'wpmtst_view_rendered', array( $this, 'view_rendered' ) );
81 add_action( 'wpmtst_form_rendered', array( $this, 'view_rendered' ) );
82 add_action( 'wpmtst_form_success', array( $this, 'view_rendered' ) );
83
84 $prerender = isset( $options['prerender'] ) ? $options['prerender'] : 'current';
85
86 switch ( $prerender ) {
87 case 'none':
88 /**
89 * Use fallback only.
90 */
91 break;
92
93 case 'all':
94 /**
95 * Provision all views.
96 * Enqueue stylesheets in head, scripts in footer.
97 */
98 add_action( 'wp_enqueue_scripts', array( $this, 'provision_all_views' ), 1 );
99 add_action( 'wp_enqueue_scripts', array( $this, 'view_rendered' ) );
100 break;
101
102 default:
103 /**
104 * Provision views in current page only.
105 * Enqueue stylesheets in head, scripts in footer.
106 */
107 $this->provision_current_page();
108 add_action( 'wp_enqueue_scripts', array( $this, 'view_rendered' ) );
109 }
110 }
111
112 /**
113 * Find shortcodes in content and prerender the view.
114 *
115 * In order to load stylesheets in normal sequence to prevent FOUC.
116 */
117 private function provision_current_page() {
118 // Look for our shortcodes in post content and widgets.
119 add_action( 'wp_enqueue_scripts', array( $this, 'find_views' ), 1 );
120 add_action( 'wp_enqueue_scripts', array( $this, 'find_views_in_postmeta' ), 1 );
121 add_action( 'wp_enqueue_scripts', array( $this, 'find_views_in_postexcerpt' ), 1 );
122 add_action( 'wp_enqueue_scripts', array( $this, 'find_widgets' ), 1 );
123
124 // Page Builder by Site Origin
125 if ( defined( 'SITEORIGIN_PANELS_VERSION' ) ) {
126 add_action( 'wp_enqueue_scripts', array( $this, 'find_pagebuilder_widgets' ), 1 );
127 }
128
129 // Beaver Builder
130 if ( defined( 'FL_BUILDER_VERSION' ) ) {
131 add_action( 'wp_enqueue_scripts', array( $this, 'find_beaverbuilder_widgets' ), 1 );
132 }
133
134 // Black Studio TinyMCE Widget
135 if ( class_exists( 'Black_Studio_TinyMCE_Plugin' ) ) {
136 add_action( 'wp_enqueue_scripts', array( $this, 'find_blackstudio_widgets' ), 1 );
137 }
138 }
139
140 /**
141 * Provision all views.
142 *
143 * @since 2.28.0
144 */
145 public function provision_all_views() {
146 $views = wpmtst_get_views();
147 foreach ( $views as $view ) {
148 // Array( [id] => 1, [name] => TEST, [value] => {serialized_array} )
149 $view_data = maybe_unserialize( $view['value'] );
150 if ( isset( $view_data['mode'] ) && 'single_template' !== $view_data['mode'] ) {
151 $atts = array(
152 'id' => $view['id'],
153 'view' => $view['id'],
154 );
155 $this->prerender( $atts );
156 }
157 }
158 }
159
160 /**
161 * Load stylesheet and scripts.
162 *
163 * Refer to add_enqueue_actions() for sequence.
164 *
165 * For compatibility with
166 * (1) page builders,
167 * (2) plugins like [Posts For Page] and [Custom Content Shortcode]
168 * that pull in other posts so this plugin cannot prerender them,
169 * (3) using the form in popup makers.
170 */
171 public function view_rendered() {
172 $this->load_styles();
173 $this->load_scripts();
174
175 /**
176 * Print script variables on footer hook.
177 * @since 2.25.2
178 */
179 add_action( 'wp_footer', array( $this, 'view_rendered_after' ) );
180 }
181
182 /**
183 * Add script variables only after view is rendered.
184 * To prevent duplicate variables.
185 *
186 * @since 2.24.1
187 */
188 public function view_rendered_after() {
189 $this->localize_scripts();
190 }
191
192 /**
193 * Add a stylesheet handle for enqueueing.
194 *
195 * @access private
196 *
197 * @param string $style_name The stylesheet handle.
198 *
199 *
200 */
201 public function add_style( $style_name ) {
202
203 if ( ! in_array( $style_name, $this->styles, true ) ) {
204 $this->styles[] = $style_name;
205 }
206 }
207
208 /**
209 * Add a script handle for enqueueing.
210 *
211 * @param string $script_name The script handle.
212 *
213 * @since 2.17.4 Using script handle as key.
214 */
215 public function add_script( $script_name ) {
216 $this->scripts[ $script_name ] = $script_name;
217 }
218
219 /**
220 * Add a script variable for localizing.
221 *
222 * @param string $script_name The script handle.
223 * @param string $var_name The script variable name.
224 * @param array $var The script variable.
225 *
226 * @since 2.17.5 Replace using variable name as key.
227 */
228 public function add_script_var( $script_name, $var_name, $var_val ) {
229 unset( $this->script_vars[ $var_name ] );
230 $this->script_vars[ $var_name ] = array(
231 'script_name' => $script_name,
232 'var_name' => $var_name,
233 'var' => $var_val,
234 );
235 }
236
237 /**
238 * Enqueue stylesheets for the view being processed.
239 *
240 * @since 2.22.3
241 */
242 public function load_styles() {
243 $styles = apply_filters( 'wpmtst_styles', $this->styles );
244 if ( $styles ) {
245 foreach ( $styles as $key => $style ) {
246 if ( ! wp_style_is( $style ) ) {
247 wp_enqueue_style( $style );
248 }
249 }
250 }
251 }
252
253 /**
254 * Enqueue scripts for the view being processed.
255 *
256 * @since 2.22.3
257 */
258 public function load_scripts() {
259 $scripts = apply_filters( 'wpmtst_scripts', $this->scripts );
260 if ( $scripts ) {
261 foreach ( $scripts as $key => $script ) {
262 if ( ! wp_script_is( $script ) ) {
263 wp_enqueue_script( $script );
264 }
265 }
266 }
267 }
268
269 /**
270 * Print script variables for the view being processed.
271 *
272 * @since 2.22.3
273 */
274 public function localize_scripts() {
275 $vars = apply_filters( 'wpmtst_script_vars', $this->script_vars );
276 if ( $vars ) {
277 foreach ( $vars as $key => $var ) {
278 wp_localize_script( $var['script_name'], $var['var_name'], $var['var'] );
279 }
280 }
281 }
282
283 /**
284 * Check the content for our shortcode.
285 *
286 * @param $content
287 *
288 * @return bool
289 */
290 private function check_content( $content ) {
291 if ( false === strpos( $content, '[' . $this->shortcode ) ) {
292 return false;
293 }
294
295 return true;
296 }
297
298 /**
299 * Check and process a widget.
300 *
301 * @since 2.28.0
302 *
303 * @param $widget
304 */
305 private function check_widget( $widget ) {
306 if ( isset( $widget['view'] ) && $widget['view'] ) {
307 $atts = array( 'view' => $widget['view'] );
308 $this->prerender( $atts );
309 }
310 }
311
312 /**
313 * Build list of all shortcode views on a page.
314 *
315 * @access public
316 */
317 public function find_views() {
318 global $post;
319 if ( empty( $post ) ) {
320 return;
321 }
322
323 $content = $post->post_content;
324 if ( ! $this->check_content( $content ) ) {
325 return;
326 }
327
328 $this->process_content( $content );
329 }
330
331 /**
332 * Build list of all shortcode views in a page's meta fields.
333 *
334 * To handle page builders that store shortcodes and widgets in post meta.
335 *
336 * @access public
337 * @since 1.15.11
338 */
339 public function find_views_in_postmeta() {
340 global $post;
341 if ( empty( $post ) ) {
342 return;
343 }
344
345 $meta_content = get_post_meta( $post->ID );
346 $meta_content_serialized = maybe_serialize( $meta_content );
347 if ( ! $this->check_content( $meta_content_serialized ) ) {
348 return;
349 }
350
351 $this->process_content( $meta_content_serialized );
352 }
353
354 /**
355 * Build list of all shortcode views in a page's excerpt.
356 *
357 * WooCommerce stores product short description in post_excerpt field.
358 *
359 * @access public
360 * @since 1.15.12
361 */
362 public function find_views_in_postexcerpt() {
363 global $post;
364 if ( empty( $post ) ) {
365 return;
366 }
367
368 if ( ! $this->check_content( $post->post_excerpt ) ) {
369 return;
370 }
371
372 $this->process_content( $post->post_excerpt );
373 }
374
375 /**
376 * Find widgets in a page to gather styles, scripts and script vars.
377 *
378 * For standard widgets NOT in [Page Builder by SiteOrigin] panels.
379 *
380 * Thanks to Matthew Harris for catching strict pass-by-reference error
381 * on $id = array_pop( explode( '-', $widget_name ) ).
382 * @link https://github.com/cdillon/strong-testimonials/issues/3
383 *
384 * @access public
385 */
386 public function find_widgets() {
387 // Get all widgets
388 $all_widgets = get_option( 'sidebars_widgets' );
389 if ( ! $all_widgets ) {
390 return;
391 }
392
393 // Get active strong widgets
394 $strong_widgets = get_option( 'widget_strong-testimonials-view-widget' );
395
396 foreach ( $all_widgets as $sidebar => $widgets ) {
397 // active widget areas only
398 if ( ! $widgets || empty( $widgets ) || 'wp_inactive_widgets' === $sidebar || 'array_version' === $sidebar ) {
399 continue;
400 }
401
402 foreach ( $widgets as $key => $widget_name ) {
403 if ( 0 === strpos( $widget_name, 'strong-testimonials-view-widget-' ) ) {
404 // Our plugin widget
405
406 if ( $strong_widgets ) {
407 $name_parts = explode( '-', $widget_name );
408 $id = array_pop( $name_parts );
409
410 if ( isset( $strong_widgets[ $id ] ) ) {
411 $widget = $strong_widgets[ $id ];
412 $this->check_widget( $widget );
413 }
414 }
415 } elseif ( 0 === strpos( $widget_name, 'text-' ) ) {
416 // Text widgets
417
418 // Get text widget content to scan for shortcodes.
419 $text_widgets = get_option( 'widget_text' );
420
421 if ( $text_widgets ) {
422 $name_parts = explode( '-', $widget_name );
423 $id = array_pop( $name_parts );
424
425 if ( isset( $text_widgets[ $id ] ) ) {
426 $widget = $text_widgets[ $id ];
427 if ( isset( $widget['text'] ) ) {
428 $this->process_content( $widget['text'] );
429 }
430 }
431 }
432 } elseif ( 0 === strpos( $widget_name, 'custom_html-' ) ) {
433 // Custom HTML widgets
434
435 // Get text widget content to scan for shortcodes.
436 $custom_html_widgets = get_option( 'widget_custom_html' );
437
438 if ( $custom_html_widgets ) {
439 $name_parts = explode( '-', $widget_name );
440 $id = array_pop( $name_parts );
441
442 if ( isset( $custom_html_widgets[ $id ] ) ) {
443 $widget = $custom_html_widgets[ $id ];
444 if ( isset( $widget['content'] ) ) {
445 $this->process_content( $widget['content'] );
446 }
447 }
448 }
449 }
450 } // foreach $widgets
451 } // foreach $all_widgets
452 }
453
454 /**
455 * Find widgets in a page to gather styles, scripts and script vars.
456 *
457 * For widgets in Page Builder by SiteOrigin.
458 */
459 public function find_pagebuilder_widgets() {
460 // Get all widgets
461 $panels_data = get_post_meta( get_the_ID(), 'panels_data', true );
462 if ( ! $panels_data ) {
463 return;
464 }
465
466 $all_widgets = $panels_data['widgets'];
467 if ( ! $all_widgets ) {
468 return;
469 }
470
471 // Need to group by cell to replicate Page Builder rendering order,
472 // whether these are Strong widgets or not.
473 $cells = array();
474 foreach ( $all_widgets as $key => $widget ) {
475 $cell_id = $widget['panels_info']['cell'];
476 $cells[ $cell_id ][] = $widget;
477 }
478
479 foreach ( $cells as $cell_widgets ) {
480 foreach ( $cell_widgets as $key => $widget ) {
481 if ( 'Strong_Testimonials_View_Widget' === $widget['panels_info']['class'] ) {
482 $this->check_widget( $widget );
483 } elseif ( 'WP_Widget_Text' === $widget['panels_info']['class'] ) {
484 // Is a Text widget?
485 $this->process_content( $widget['text'] );
486 }
487 }
488 }
489 }
490
491 /**
492 * Find widgets in a page to gather styles, scripts and script vars.
493 *
494 * For widgets in Beaver Builder.
495 */
496 public function find_beaverbuilder_widgets() {
497 $nodes = get_post_meta( get_the_ID(), '_fl_builder_data', true );
498 if ( ! $nodes ) {
499 return;
500 }
501
502 foreach ( $nodes as $key => $node ) {
503 if ( 'module' !== $node->type ) {
504 continue;
505 }
506
507 if ( 'widget' !== $node->settings->type ) {
508 continue;
509 }
510
511 if ( 'Strong_Testimonials_View_Widget' === $node->settings->widget ) {
512 $settings = (array) $node->settings;
513 $widget = (array) $settings['widget-strong-testimonials-view-widget'];
514 $this->check_widget( $widget );
515 }
516 }
517 }
518
519
520 /**
521 * Build list of all shortcode views in Black Studio TinyMCE Widget.
522 *
523 * @access public
524 * @since 1.16.14
525 */
526 public function find_blackstudio_widgets() {
527 global $post;
528 if ( empty( $post ) ) {
529 return;
530 }
531
532 $widget_content = get_option( 'widget_black-studio-tinymce' );
533 if ( ! $widget_content ) {
534 return;
535 }
536
537 $widget_content_serialized = maybe_serialize( $widget_content );
538 if ( ! $this->check_content( $widget_content_serialized ) ) {
539 return;
540 }
541
542 $this->process_content( $widget_content_serialized );
543 }
544
545 /**
546 * @param $atts
547 *
548 * @return bool
549 */
550 private function view_not_found( $atts ) {
551 return ( isset( $atts['view_not_found'] ) && $atts['view_not_found'] );
552 }
553
554 /**
555 * Process content for shortcodes.
556 *
557 * A combination of has_shortcode and shortcode_parse_atts.
558 * This seems to solve the unenclosed shortcode issue too.
559 *
560 * @access private
561 *
562 * @param string $content Post content or widget content.
563 */
564 private function process_content( $content ) {
565 preg_match_all( '/' . get_shortcode_regex() . '/s', $content, $matches, PREG_SET_ORDER );
566 if ( empty( $matches ) ) {
567 return;
568 }
569
570 foreach ( $matches as $key => $shortcode ) {
571 if ( $this->shortcode === $shortcode[2] ) {
572 /**
573 * Retrieve all attributes from the shortcode.
574 *
575 * @since 1.16.13 Adding html_entity_decode.
576 */
577 $atts = shortcode_parse_atts( html_entity_decode( $shortcode[3] ) );
578 $this->prerender( $atts );
579 } else {
580 /**
581 * Recursively process nested shortcodes.
582 *
583 * Handles:
584 * Elegant Themes page builder.
585 *
586 * @since 1.15.5
587 */
588 $this->process_content( $shortcode[5] );
589 }
590 }
591 }
592
593 /**
594 * Prerender a view to gather styles, scripts, and script vars.
595 *
596 * Similar to Strong_Testimonials_View_Shortcode::render_view().
597 *
598 * @param $atts
599 *
600 * @since 1.25.0
601 * @since 2.16.0 Move all processing to Strong_View class.
602 */
603 public function prerender( $atts ) {
604 // Just like the shortcode function:
605 $atts = shortcode_atts(
606 array(),
607 $atts,
608 $this->shortcode
609 );
610 if ( $this->view_not_found( $atts ) ) {
611 return;
612 }
613
614 $this->set_atts( $atts );
615
616 switch ( $atts['mode'] ) {
617 case 'form':
618 $view = new Strong_View_Form( $atts );
619 break;
620 case 'slideshow':
621 $view = new Strong_View_Slideshow( $atts );
622 break;
623 default:
624 $view = new Strong_View_Display( $atts );
625 }
626 $view->process();
627
628 /**
629 * Allow themes and plugins to do stuff like add extra stylesheets.
630 *
631 * @since 2.22.0
632 */
633 do_action( 'wpmtst_view_found', $atts );
634 }
635
636 /**
637 * Parse view attributes.
638 *
639 * This is used by the shortcode filter and prerendering to assemble
640 * the view attributes.
641 *
642 * @param array $out The output array of shortcode attributes.
643 * @param array $pairs The supported attributes and their defaults.
644 * @param array $atts The user defined shortcode attributes.
645 *
646 * @return array
647 */
648 public function parse_view( $out, $pairs, $atts ) {
649 // Convert "id" to "view" - sanitize to integer to prevent attribute breakout (security).
650 if ( isset( $atts['id'] ) && $atts['id'] !== '' ) {
651 $raw_id = trim( (string) $atts['id'] );
652 $view_id = absint( $raw_id );
653 // Reject non-numeric or malformed id (e.g. "1 onmouseover=alert(1)").
654 if ( $view_id < 1 || $raw_id !== (string) $view_id ) {
655 return array_merge( array( 'view_not_found' => 1 ), $atts );
656 }
657 $atts['view'] = $view_id;
658 unset( $atts['id'] );
659 } else {
660 return array_merge( array( 'view_not_found' => 1 ), $atts );
661 }
662
663 $atts['view'] = apply_filters( 'wpmtst_parse_view_id', $atts['view'] );
664
665 // Fetch the view
666 $view = wpmtst_get_view( $atts['view'] );
667
668 /**
669 * Add error attribute for shortcode handler.
670 *
671 * @since 1.21.0
672 */
673 if ( ! $view ) {
674 return array_merge( array( 'view_not_found' => 1 ), $atts );
675 }
676
677 $view_data = apply_filters( 'wpmtst_parse_view_data', unserialize( $view['value'] ), $atts['view'] );
678
679 /**
680 * Adjust for defaults.
681 *
682 * @since 2.30.0
683 */
684 if ( isset( $view_data['category'] ) && 'all' === $view_data['category'] ) {
685 $view_data['category'] = '';
686 }
687 if ( 'slideshow' === $view_data['mode'] ) {
688 unset( $view_data['id'] );
689 }
690
691 /**
692 * Saner approach.
693 *
694 * @since 2.30.0
695 */
696
697 // Post ID's override single ID, category, and count
698 if ( isset( $atts['post_ids'] ) ) {
699 $atts['id'] = $atts['post_ids'];
700 $atts['category'] = '';
701 $atts['count'] = -1;
702 }
703
704 // Override category slugs. This can handle a combination of slugs and ID's
705 if ( isset( $atts['category'] ) ) {
706 $cats = array();
707 $items = explode( ',', $atts['category'] );
708 foreach ( $items as $item ) {
709 if ( is_numeric( $item ) ) {
710 $cats[] = $item;
711 } else {
712 $term = get_term_by( 'slug', $item, 'wpm-testimonial-category' );
713 if ( $term ) {
714 $cats[] = $term->term_id;
715 }
716 }
717 }
718 if ( $cats ) {
719 $atts['category'] = implode( ',', $cats );
720 }
721 }
722
723 $out = array_merge( $this->get_view_defaults(), $view_data, $atts );
724
725 if ( 'form' === ( $out['mode'] ?? '' ) && ( empty( $out['template'] ) || 'default' === $out['template'] ) ) {
726 $out['template'] = 'default-form';
727 }
728
729 return $out;
730 }
731 }
732