PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.15
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.15
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Module / Frontend.php

Frontend.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.11.15, at classes/Visualizer/Module/Frontend.php

749 lines 24.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
5 // +----------------------------------------------------------------------+
6 // | This program is free software; you can redistribute it and/or modify |
7 // | it under the terms of the GNU General Public License, version 2, as |
8 // | published by the Free Software Foundation. |
9 // | |
10 // | This program is distributed in the hope that it will be useful, |
11 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 // | GNU General Public License for more details. |
14 // | |
15 // | You should have received a copy of the GNU General Public License |
16 // | along with this program; if not, write to the Free Software |
17 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
18 // | MA 02110-1301 USA |
19 // +----------------------------------------------------------------------+
20 // | Author: Eugene Manuilov <eugene@manuilov.org> |
21 // +----------------------------------------------------------------------+
22 /**
23 * Frontend module class.
24 *
25 * @category Visualizer
26 * @package Module
27 *
28 * @since 1.0.0
29 */
30 class Visualizer_Module_Frontend extends Visualizer_Module {
31
32 const NAME = __CLASS__;
33
34 /**
35 * The array of charts to render.
36 *
37 * @since 1.0.0
38 *
39 * @access private
40 * @var array
41 */
42 private $_charts = array();
43
44 /**
45 * Lazy render script.
46 *
47 * @access private
48 * @var bool
49 */
50 private $lazy_render_script = true;
51
52 /**
53 * Constructor.
54 *
55 * @since 1.0.0
56 * @uses add_filter() To add "do_shortcode" hook for "widget_text" and "term_description" filters.
57 *
58 * @access public
59 * @param Visualizer_Plugin $plugin The instance of the plugin.
60 */
61 public function __construct( Visualizer_Plugin $plugin ) {
62 parent::__construct( $plugin );
63
64 $this->_addAction( 'wp_print_footer_scripts', 'printFooterScripts' );
65 $this->_addAction( 'wp_enqueue_scripts', 'enqueueScripts' );
66 $this->_addAction( 'load-index.php', 'enqueueScripts' );
67 $this->_addAction( 'load-visualizer_page_visualizer-setup-wizard', 'enqueueScripts' );
68 $this->_addAction( 'visualizer_enqueue_scripts', 'enqueueScripts' );
69 $this->_addFilter( 'visualizer_get_language', 'getLanguage' );
70 $this->_addShortcode( 'visualizer', 'renderChart' );
71
72 // add do_shortocde hook for widget_text filter
73 if ( ! has_filter( 'widget_text', 'do_shortcode' ) ) {
74 add_filter( 'widget_text', 'do_shortcode' );
75 }
76
77 // add do_shortcode hook for term_description filter
78 if ( ! has_filter( 'term_description', 'do_shortcode' ) ) {
79 add_filter( 'term_description', 'do_shortcode' );
80 }
81
82 add_action( 'rest_api_init', array( $this, 'endpoint_register' ) );
83
84 $this->_addFilter( 'script_loader_tag', 'script_loader_tag', null, 10, 3 );
85 }
86
87 /**
88 * Adds the async attribute to certain scripts.
89 */
90 function script_loader_tag( $tag, $handle, $src ) {
91 if ( is_admin() ) {
92 return $tag;
93 }
94 // Async scripts.
95 $async_scripts = array( 'google-jsapi', 'chartjs', 'visualizer-datatables' );
96 foreach ( $async_scripts as $async ) {
97 if ( $async === $handle ) {
98 $tag = str_replace( ' src', ' async src', $tag );
99 break;
100 }
101 };
102
103 // Async scripts.
104 $scripts = array( 'dom-to-image' );
105 foreach ( array( 'async', 'defer' ) as $attr ) {
106 if ( wp_scripts()->get_data( $handle, $attr ) ) {
107 break;
108 }
109 if ( in_array( $handle, $async_scripts, true ) || false === strpos( $handle, 'visualizer-' ) ) {
110 break;
111 }
112 if ( ! preg_match( ":\s$attr(=|>|\s):", $tag ) ) {
113 $tag = preg_replace( ':(?=></script>):', " $attr", $tag, 1 );
114 if ( $this->lazy_render_script ) {
115 $tag = str_replace( ' src', ' data-visualizer-script', $tag );
116 }
117 }
118 // Only allow async or defer, not both.
119 break;
120 }
121 return $tag;
122 }
123
124 /**
125 * Returns the language/locale.
126 */
127 function getLanguage( $dummy, $only_language ) {
128 return $this->get_language();
129 }
130
131
132 /**
133 * Registers the endpoints
134 */
135 function endpoint_register() {
136 register_rest_route(
137 'visualizer/v' . VISUALIZER_REST_VERSION,
138 '/action/(?P<chart>\d+)/(?P<type>.+)/',
139 array(
140 // POST is required for save/cancel, GET for all others
141 'methods' => array( 'POST', 'GET' ),
142 'args' => array(
143 'chart' => array(
144 'required' => true,
145 'sanitize_callback' => function( $param ) {
146 return is_numeric( $param ) ? $param : null;
147 },
148 ),
149 'type' => array(
150 'required' => true,
151 'type' => 'string',
152 'enum' => array_merge( array( 'save', 'cancel' ), array_keys( $this->get_actions() ) ),
153 ),
154 ),
155 'permission_callback' => function ( WP_REST_Request $request ) {
156 $chart_id = filter_var( sanitize_text_field( $request->get_param( 'chart' ), FILTER_VALIDATE_INT ) );
157 if ( ! empty( $chart_id ) && in_array( $request->get_param( 'type' ), array( 'save', 'cancel' ), true ) ) {
158 // let save and cancel go without any check as past version of pro
159 // did not send the X-WP-Nonce
160 // we can change this at a later date.
161 return true;
162 }
163 return ! empty( $chart_id ) && apply_filters( 'visualizer_pro_show_chart', true, $chart_id );
164 },
165 'callback' => array( $this, 'perform_action' ),
166 )
167 );
168 }
169
170 /**
171 * All possible actions and their labels
172 *
173 * @access private
174 */
175 private function get_actions() {
176 $actions = apply_filters(
177 'visualizer_action_buttons',
178 array(
179 'print' => array(
180 'label' => esc_html__( 'Print', 'visualizer' ),
181 'title' => esc_html__( 'Print Chart', 'visualizer' ),
182 ),
183 'csv' => array(
184 'label' => esc_html__( 'CSV', 'visualizer' ),
185 'title' => esc_html__( 'Download as a CSV', 'visualizer' ),
186 ),
187 'xls' => array(
188 'label' => esc_html__( 'Excel', 'visualizer' ),
189 'title' => esc_html__( 'Download as a spreadsheet', 'visualizer' ),
190 ),
191 'copy' => array(
192 'label' => esc_html__( 'Copy', 'visualizer' ),
193 'title' => esc_html__( 'Copy data', 'visualizer' ),
194 ),
195 'image' => array(
196 'label' => esc_html__( 'Download', 'visualizer' ),
197 'title' => esc_html__( 'Download as an image', 'visualizer' ),
198 ),
199 )
200 );
201
202 // backward compatibility before label and title attributes were introduced.
203 if ( isset( $actions['edit'] ) && is_string( $actions['edit'] ) ) {
204 $actions['edit'] = array(
205 'label' => esc_html__( 'Edit', 'visualizer' ),
206 'title' => esc_html__( 'Edit data', 'visualizer' ),
207 );
208 }
209 return $actions;
210 }
211
212 /**
213 * The print button
214 *
215 * @since 1.0.0
216 *
217 * @access public
218 */
219 public function perform_action( WP_REST_Request $params ) {
220 $chart_id = filter_var( sanitize_text_field( $params['chart'] ), FILTER_VALIDATE_INT );
221 $type = sanitize_text_field( $params['type'] );
222 $data = null;
223
224 if ( ! $chart_id ) {
225 return new WP_REST_Response( array( 'error' => new WP_Error( __( 'Invalid chart ID', 'visualizer' ) ) ) );
226 }
227
228 if ( ! $type ) {
229 return new WP_REST_Response( array( 'error' => new WP_Error( __( 'Invalid action', 'visualizer' ) ) ) );
230 }
231
232 switch ( $type ) {
233 case 'print':
234 $data = $this->_getDataAs( $chart_id, 'print' );
235 break;
236 case 'csv':
237 $data = $this->_getDataAs( $chart_id, 'csv' );
238 break;
239 case 'xls':
240 $data = $this->_getDataAs( $chart_id, 'xls' );
241 break;
242 case 'image':
243 $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
244 $title = 'visualizer#' . $chart_id;
245 if ( ! empty( $settings['title'] ) ) {
246 $title = $settings['title'];
247 }
248 // for ChartJS, title is an array.
249 if ( is_array( $title ) && isset( $title['text'] ) ) {
250 $title = $title['text'];
251 }
252 if ( empty( $title ) ) {
253 $title = 'visualizer#' . $chart_id;
254 }
255 $data = array( 'name' => $title );
256 break;
257 default:
258 $data = apply_filters( 'visualizer_action_data', $data, $chart_id, $type, $params, $this );
259 break;
260 }
261
262 return new WP_REST_Response( array( 'data' => $data ) );
263 }
264
265 /**
266 * Registers scripts for charts rendering.
267 *
268 * @since 1.0.0
269 * @uses wp_register_script To register javascript file.
270 *
271 * @access public
272 */
273 public function enqueueScripts() {
274 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
275 do_action( 'visualizer_pro_frontend_load_resources' );
276 }
277
278 /**
279 * Returns placeholder for chart according to visualizer shortcode attributes.
280 *
281 * @since 1.0.0
282 * @uses shortcode_atts() To parse income shortocdes.
283 * @uses apply_filters() To filter chart's data and series arrays.
284 * @uses get_post_meta() To fetch chart's meta information.
285 * @uses wp_enqueue_script() To enqueue charts render script.
286 * @uses wp_localize_script() To add chart data to the page inline script.
287 *
288 * @access public
289 * @param array $atts The array of shortcode attributes.
290 */
291 public function renderChart( $atts ) {
292 global $wp_version;
293 $atts = shortcode_atts(
294 array(
295 // chart id
296 'id' => false,
297 // chart class
298 'class' => false,
299 // for lazy load
300 // set 'yes' to use the default intersection limit (300px)
301 // OR set a number (e.g. 700) to use 700px as the intersection limit
302 'lazy' => apply_filters( 'visualizer_lazy_by_default', false, $atts['id'] ),
303 // Use image chart
304 'use_image' => 'no',
305 ),
306 $atts
307 );
308
309 $atts['id'] = (int) $atts['id'];
310 $atts['class'] = esc_attr( $atts['class'] );
311 $atts['lazy'] = esc_attr( $atts['lazy'] );
312 $atts['use_image'] = esc_attr( $atts['use_image'] );
313
314 global $sitepress;
315 if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
316 global $sitepress;
317 $locale = icl_get_current_language();
318 $locale = strtolower( str_replace( '_', '-', $locale ) );
319 $trid = $sitepress->get_element_trid( $atts['id'], 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
320 $translations = $sitepress->get_element_translations( $trid );
321 if ( isset( $translations[ $locale ] ) && is_object( $translations[ $locale ] ) ) {
322 $atts['id'] = $translations[ $locale ]->element_id;
323 }
324 }
325
326 $chart_data = $this->getChartData( Visualizer_Plugin::CF_CHART_CACHE, $atts['id'] );
327 // if empty chart does not exists, then return empty string.
328 if ( ! $chart_data ) {
329 return '';
330 }
331
332 $chart = $chart_data['chart'];
333 $type = $chart_data['type'];
334 $series = $chart_data['series'];
335 // do not show the chart?
336 if ( ! apply_filters( 'visualizer_pro_show_chart', true, $atts['id'] ) ) {
337 return '';
338 }
339
340 if ( ! is_admin() && ! empty( $chart_data['is_woocommerce_report'] ) ) {
341 return '';
342 }
343
344 // in case revisions exist.
345 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found
346 if ( true === ( $revisions = $this->undoRevisions( $chart->ID, true ) ) ) {
347 $chart = get_post( $chart->ID );
348 }
349
350 $id = 'visualizer-' . $atts['id'];
351 $defaultClass = 'visualizer-front';
352 $class = apply_filters( Visualizer_Plugin::FILTER_CHART_WRAPPER_CLASS, $atts['class'], $atts['id'] );
353
354 $lazyClass = $atts['lazy'] === 'yes' || ctype_digit( $atts['lazy'] ) ? 'visualizer-lazy' : '';
355
356 $class = sprintf( '%s %s %s %s', $defaultClass, $class, 'visualizer-front-' . $atts['id'], $lazyClass );
357 $attributes = array();
358 if ( ! empty( $class ) ) {
359 $attributes['class'] = trim( $class );
360 }
361
362 if ( ctype_digit( $atts['lazy'] ) ) {
363 $attributes['data-lazy-limit'] = $atts['lazy'];
364 }
365
366 $attributes = apply_filters( 'visualizer_container_attributes', $attributes, $chart->ID );
367
368 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
369
370 // Get and update settings.
371 $settings = $chart_data['settings'];
372 $settings = ! empty( $settings ) ? $settings : array();
373 if ( empty( $settings['height'] ) ) {
374 $settings['height'] = '400';
375 }
376
377 // handle series filter hooks
378 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, $series, $chart->ID, $type );
379
380 // handle settings filter hooks
381 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
382
383 $lazy_load = isset( $settings['lazy_load_chart'] ) ? $settings['lazy_load_chart'] : false;
384 $lazy_load = apply_filters( 'visualizer_lazy_load_chart', $lazy_load, $chart->ID );
385 $container_class = 'visualizer-front-container';
386 if ( ! $lazy_load ) {
387 $this->lazy_render_script = false;
388 } else {
389 $container_class .= ' visualizer-lazy-render';
390 }
391
392 // handle data filter hooks
393 $data = self::get_chart_data( $chart, $type );
394
395 $css = '';
396 $arguments = $this->get_inline_custom_css( $id, $settings );
397 if ( ! empty( $arguments ) ) {
398 $css = $arguments[0];
399 $settings = $arguments[1];
400 }
401
402 $library = $this->load_chart_type( $chart->ID );
403
404 $id = $id . '-' . rand();
405
406 $amp = Visualizer_Plugin::instance()->getModule( Visualizer_Module_AMP::NAME );
407 if ( $amp && $amp->is_amp() ) {
408 return '<div data-amp-auto-lightbox-disable id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '>' . $amp->get_chart( $chart, $data, $series, $settings ) . '</div>';
409 }
410
411 if ( 'yes' === $atts['use_image'] ) {
412 $chart_image = $chart_data['chart_image'];
413 if ( $chart_image ) {
414 return '<div id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '>' . wp_get_attachment_image( $chart_image, 'full' ) . '</div>';
415 }
416 }
417 // Unset chart image base64 string.
418 if ( isset( $settings['chart-img'] ) ) {
419 unset( $settings['chart-img'] );
420 }
421
422 $enable_controls = false;
423 if ( isset( $settings['controls'] ) && ! empty( $settings['controls']['controlType'] ) ) {
424 $column_index = $settings['controls']['filterColumnIndex'];
425 $column_label = $settings['controls']['filterColumnLabel'];
426 if ( 'false' !== $column_index || 'false' !== $column_label ) {
427 $enable_controls = true;
428 }
429 }
430
431 if ( ! $enable_controls ) {
432 unset( $settings['controls'] );
433 }
434
435 // add chart to the array
436 $this->_charts[ $id ] = array(
437 'type' => $type,
438 'series' => $series,
439 'settings' => $settings,
440 'data' => $data,
441 'library' => $library,
442 );
443
444 $actions_div = '';
445 $actions_visible = apply_filters( 'visualizer_pro_add_actions', isset( $settings['actions'] ) ? $settings['actions'] : array(), $atts['id'] );
446 if ( ! empty( $actions_visible ) ) {
447 $actions = $this->get_actions();
448 $actions_div = '<div class="visualizer-actions">';
449 foreach ( $actions_visible as $action_type ) {
450 $key = $action_type;
451 $mime = '';
452 if ( strpos( $action_type, ';' ) !== false ) {
453 $array = explode( ';', $action_type );
454 $key = $array[0];
455 $mime = end( $array );
456 }
457 $label = $actions[ $key ]['label'];
458 $title = $actions[ $key ]['title'];
459 $actions_div .= sprintf( '<a href="#" class="visualizer-action visualizer-action-%s" data-visualizer-type="%s" data-visualizer-chart-id="%s" data-visualizer-container-id="%s" data-visualizer-mime="%s" title="%s"', $key, $key, $atts['id'], $id, $mime, $title );
460
461 if ( 'copy' === $key ) {
462 $copy = $this->_getDataAs( $atts['id'], 'csv' );
463 $actions_div .= ' data-clipboard-text="' . esc_attr( $copy['csv'] ) . '"';
464 wp_enqueue_script( 'clipboard' );
465 }
466
467 $actions_div .= apply_filters( 'visualizer_action_attributes', '', $key, $atts['id'] );
468 $actions_div .= '>' . $label . '</a> &nbsp;';
469 }
470
471 $actions_div .= '</div>';
472 }
473
474 $actions_div .= $css;
475
476 $_charts = array();
477 $_charts_type = '';
478 $count = 0;
479 foreach ( $this->_charts as $id => $array ) {
480 $_charts = $this->_charts;
481 $library = $array['library'];
482 $_charts_type = $library;
483 if ( ! wp_script_is( "visualizer-render-$library", 'registered' ) ) {
484 wp_register_script(
485 "visualizer-render-$library",
486 VISUALIZER_ABSURL . 'js/render-facade.js',
487 apply_filters( 'visualizer_assets_render', array( 'jquery', 'visualizer-customization' ), true ),
488 Visualizer_Plugin::VERSION,
489 true
490 );
491 wp_enqueue_script( "visualizer-render-$library" );
492 }
493
494 if ( wp_script_is( "visualizer-render-$_charts_type" ) && 0 === $count ) {
495 wp_localize_script(
496 "visualizer-render-$_charts_type",
497 'visualizer',
498 array(
499 'charts' => $this->_charts,
500 'language' => $this->get_language(),
501 'map_api_key' => get_option( 'visualizer-map-api-key' ),
502 'rest_url' => version_compare( $wp_version, '4.7.0', '>=' ) ? rest_url( 'visualizer/v' . VISUALIZER_REST_VERSION . '/action/#id#/#type#/' ) : '',
503 'wp_nonce' => wp_create_nonce( 'wp_rest' ),
504 'i10n' => array(
505 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
506 ),
507 'page_type' => 'frontend',
508 'is_front' => true,
509 )
510 );
511 }
512 $count++;
513 }
514 $prefix = 'C' . 'h' . 'a' . 'rt';
515 if ( $type === 'tabular' ) {
516 $prefix = 'T' . 'a' . 'bl' . 'e';
517 }
518 if ( Visualizer_Module::is_pro() && $enable_controls ) {
519 $actions_div .= '<div id="control_wrapper_' . $id . '"></div>';
520 }
521 // return placeholder div
522 return '<div class="' . $container_class . '" id="chart_wrapper_' . $id . '">' . $actions_div . '<div id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '></div>' . $this->addSchema( $chart->ID ) . '</div>';
523 }
524
525 /**
526 * Converts the array of attributes to a string of HTML attributes.
527 *
528 * @since ?
529 *
530 * @access private
531 */
532 private function getHtmlAttributes( $attributes ) {
533 $string = '';
534 if ( ! $attributes ) {
535 return $string;
536 }
537
538 foreach ( $attributes as $name => $value ) {
539 $string .= sprintf( ' %s="%s"', esc_attr( $name ), esc_attr( $value ) );
540 }
541 return $string;
542 }
543
544 /**
545 * Adds the schema corresponding to the dataset.
546 *
547 * @since 3.3.2
548 *
549 * @access private
550 */
551 private function addSchema( $id ) {
552 // should we show informative errors as HTML comments?
553 $show_errors = apply_filters( 'visualizer_schema_show_errors', true, $id );
554
555 $settings = get_post_meta( $id, Visualizer_Plugin::CF_SETTINGS, true );
556 $title = '';
557 if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
558 $title = $settings['title'];
559 if ( is_array( $title ) ) {
560 $title = $settings['title']['text'];
561 }
562 }
563 $title = apply_filters( 'visualizer_schema_name', $title, $id );
564 if ( empty( $title ) ) {
565 if ( $show_errors ) {
566 return "<!-- Not showing structured data for chart $id because title is empty -->";
567 }
568 return '';
569 }
570
571 $desc = '';
572 if ( isset( $settings['description'] ) && ! empty( $settings['description'] ) ) {
573 $desc = $settings['description'];
574 }
575 $desc = apply_filters( 'visualizer_schema_description', $desc, $id );
576 if ( empty( $desc ) ) {
577 if ( $show_errors ) {
578 return "<!-- Not showing structured data for chart $id because description is empty -->";
579 }
580 return '';
581 }
582
583 // descriptions below 50 chars are not allowed.
584 if ( strlen( $desc ) < 50 ) {
585 if ( $show_errors ) {
586 return "<!-- Not showing structured data for chart $id because description is shorter than 50 characters -->";
587 }
588 return '';
589 }
590
591 $license = '';
592 if ( isset( $settings['license'] ) && ! empty( $settings['license'] ) ) {
593 $license = $settings['license'];
594 if ( is_array( $license ) ) {
595 $license = $settings['license']['text'];
596 }
597 }
598 $license = apply_filters( 'visualizer_schema_license', $license, $id );
599 if ( empty( $license ) ) {
600 if ( $show_errors ) {
601 return "<!-- Not showing structured data for chart $id because license is empty -->";
602 }
603 return '';
604 }
605
606 $creator = '';
607 if ( isset( $settings['creator'] ) && ! empty( $settings['creator'] ) ) {
608 $creator = $settings['creator'];
609 if ( is_array( $creator ) ) {
610 $creator = $settings['creator']['text'];
611 }
612 }
613 $creator = apply_filters( 'visualizer_schema_creator', $creator, $id );
614 if ( empty( $creator ) ) {
615 if ( $show_errors ) {
616 return "<!-- Not showing structured data for chart $id because creator is empty -->";
617 }
618 return '';
619 }
620
621 $schema = apply_filters(
622 'visualizer_schema',
623 '{
624 "@context":"https://schema.org/",
625 "@type":"Dataset",
626 "name":"' . esc_html( $title ) . '",
627 "description":"' . esc_html( $desc ) . '",
628 "license": "' . esc_html( $license ) . '",
629 "creator": {
630 "@type": "Person",
631 "name": "' . esc_html( $creator ) . '"
632 }
633 }',
634 $id
635 );
636
637 if ( empty( $schema ) ) {
638 return '';
639 }
640
641 return '<script type="application/ld+json">' . $schema . '</script>';
642 }
643
644 /**
645 * Get chart by ID.
646 *
647 * @param string $cache_key Cache key.
648 * @param int $chart_id Chart ID.
649 * @return mixed
650 */
651 private function getChartData( $cache_key = '', $chart_id = 0 ) {
652 if ( ! $chart_id ) {
653 return false;
654 }
655 // Create unique cache key of each chart.
656 $cache_key .= '_' . $chart_id;
657 // Get chart from cache.
658 $chart = get_transient( $cache_key );
659 if ( $chart ) {
660 return $chart;
661 }
662
663 // Get chart by ID.
664 $chart = get_post( $chart_id );
665 if ( $chart && Visualizer_Plugin::CPT_VISUALIZER === $chart->post_type ) {
666 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
667 $series = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true );
668 $is_woocommerce_report = get_post_meta( $chart->ID, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE, true );
669
670 if ( isset( $settings['series'] ) && ! ( count( $settings['series'] ) - count( $series ) > 1 ) ) {
671 $diff_total_series = abs( count( $settings['series'] ) - count( $series ) );
672 if ( $diff_total_series ) {
673 foreach ( range( 1, $diff_total_series ) as $k => $diff_series ) {
674 $settings['series'][] = end( $settings['series'] );
675 }
676 }
677 }
678 $chart_data = array(
679 'chart' => $chart,
680 'type' => get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true ),
681 'settings' => $settings,
682 'series' => $series,
683 'chart_image' => get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_IMAGE, true ),
684 'is_woocommerce_report' => $is_woocommerce_report,
685 );
686
687 // Put the results in a transient. Expire after 12 hours.
688 set_transient( $cache_key, $chart_data, apply_filters( Visualizer_Plugin::FILTER_HANDLE_CACHE_EXPIRATION_TIME, 12 * HOUR_IN_SECONDS ) );
689 return $chart_data;
690 }
691
692 return false;
693 }
694
695 /**
696 * Print footer script.
697 */
698 public function printFooterScripts() {
699 if ( $this->lazy_render_script ) {
700 ?>
701 <script type="text/javascript">
702 var visualizerUserInteractionEvents = [
703 "scroll",
704 "mouseover",
705 "keydown",
706 "touchmove",
707 "touchstart"
708 ];
709
710 visualizerUserInteractionEvents.forEach(function(event) {
711 window.addEventListener(event, visualizerTriggerScriptLoader, { passive: true });
712 });
713
714 function visualizerTriggerScriptLoader() {
715 visualizerLoadScripts();
716 visualizerUserInteractionEvents.forEach(function(event) {
717 window.removeEventListener(event, visualizerTriggerScriptLoader, { passive: true });
718 });
719 }
720
721 function visualizerLoadScripts() {
722 document.querySelectorAll("script[data-visualizer-script]").forEach(function(elem) {
723 jQuery.getScript( elem.getAttribute("data-visualizer-script") )
724 .done( function( script, textStatus ) {
725 elem.setAttribute("src", elem.getAttribute("data-visualizer-script"));
726 elem.removeAttribute("data-visualizer-script");
727 setTimeout( function() {
728 visualizerRefreshChart();
729 } );
730 } );
731 });
732 }
733
734 function visualizerRefreshChart() {
735 jQuery( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
736 if ( jQuery( 'div.viz-facade-loaded:not(.visualizer-lazy):empty' ).length > 0 ) {
737 visualizerUserInteractionEvents.forEach( function( event ) {
738 window.addEventListener( event, function() {
739 jQuery( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
740 }, { passive: true } );
741 } );
742 }
743 }
744 </script>
745 <?php
746 }
747 }
748 }
749