PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.2
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.10.2, at classes/Visualizer/Module/Frontend.php

747 lines 24.8 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 = false;
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 = true;
388 $container_class .= ' visualizer-lazy-render';
389 }
390
391 // handle data filter hooks
392 $data = self::get_chart_data( $chart, $type );
393
394 $css = '';
395 $arguments = $this->get_inline_custom_css( $id, $settings );
396 if ( ! empty( $arguments ) ) {
397 $css = $arguments[0];
398 $settings = $arguments[1];
399 }
400
401 $library = $this->load_chart_type( $chart->ID );
402
403 $id = $id . '-' . rand();
404
405 $amp = Visualizer_Plugin::instance()->getModule( Visualizer_Module_AMP::NAME );
406 if ( $amp && $amp->is_amp() ) {
407 return '<div data-amp-auto-lightbox-disable id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '>' . $amp->get_chart( $chart, $data, $series, $settings ) . '</div>';
408 }
409
410 if ( 'yes' === $atts['use_image'] ) {
411 $chart_image = $chart_data['chart_image'];
412 if ( $chart_image ) {
413 return '<div id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '>' . wp_get_attachment_image( $chart_image, 'full' ) . '</div>';
414 }
415 }
416 // Unset chart image base64 string.
417 if ( isset( $settings['chart-img'] ) ) {
418 unset( $settings['chart-img'] );
419 }
420
421 $enable_controls = false;
422 if ( isset( $settings['controls'] ) && ! empty( $settings['controls']['controlType'] ) ) {
423 $column_index = $settings['controls']['filterColumnIndex'];
424 $column_label = $settings['controls']['filterColumnLabel'];
425 if ( 'false' !== $column_index || 'false' !== $column_label ) {
426 $enable_controls = true;
427 }
428 }
429
430 if ( ! $enable_controls ) {
431 unset( $settings['controls'] );
432 }
433
434 // add chart to the array
435 $this->_charts[ $id ] = array(
436 'type' => $type,
437 'series' => $series,
438 'settings' => $settings,
439 'data' => $data,
440 'library' => $library,
441 );
442
443 $actions_div = '';
444 $actions_visible = apply_filters( 'visualizer_pro_add_actions', isset( $settings['actions'] ) ? $settings['actions'] : array(), $atts['id'] );
445 if ( ! empty( $actions_visible ) ) {
446 $actions = $this->get_actions();
447 $actions_div = '<div class="visualizer-actions">';
448 foreach ( $actions_visible as $action_type ) {
449 $key = $action_type;
450 $mime = '';
451 if ( strpos( $action_type, ';' ) !== false ) {
452 $array = explode( ';', $action_type );
453 $key = $array[0];
454 $mime = end( $array );
455 }
456 $label = $actions[ $key ]['label'];
457 $title = $actions[ $key ]['title'];
458 $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 );
459
460 if ( 'copy' === $key ) {
461 $copy = $this->_getDataAs( $atts['id'], 'csv' );
462 $actions_div .= ' data-clipboard-text="' . esc_attr( $copy['csv'] ) . '"';
463 wp_enqueue_script( 'clipboard' );
464 }
465
466 $actions_div .= apply_filters( 'visualizer_action_attributes', '', $key, $atts['id'] );
467 $actions_div .= '>' . $label . '</a> &nbsp;';
468 }
469
470 $actions_div .= '</div>';
471 }
472
473 $actions_div .= $css;
474
475 $_charts = array();
476 $_charts_type = '';
477 $count = 0;
478 foreach ( $this->_charts as $id => $array ) {
479 $_charts = $this->_charts;
480 $library = $array['library'];
481 $_charts_type = $library;
482 if ( ! wp_script_is( "visualizer-render-$library", 'registered' ) ) {
483 wp_register_script(
484 "visualizer-render-$library",
485 VISUALIZER_ABSURL . 'js/render-facade.js',
486 apply_filters( 'visualizer_assets_render', array( 'jquery', 'visualizer-customization' ), true ),
487 Visualizer_Plugin::VERSION,
488 true
489 );
490 wp_enqueue_script( "visualizer-render-$library" );
491 }
492
493 if ( wp_script_is( "visualizer-render-$_charts_type" ) && 0 === $count ) {
494 wp_localize_script(
495 "visualizer-render-$_charts_type",
496 'visualizer',
497 array(
498 'charts' => $this->_charts,
499 'language' => $this->get_language(),
500 'map_api_key' => get_option( 'visualizer-map-api-key' ),
501 'rest_url' => version_compare( $wp_version, '4.7.0', '>=' ) ? rest_url( 'visualizer/v' . VISUALIZER_REST_VERSION . '/action/#id#/#type#/' ) : '',
502 'wp_nonce' => wp_create_nonce( 'wp_rest' ),
503 'i10n' => array(
504 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
505 ),
506 'page_type' => 'frontend',
507 'is_front' => true,
508 )
509 );
510 }
511 $count++;
512 }
513 $prefix = 'C' . 'h' . 'a' . 'rt';
514 if ( $type === 'tabular' ) {
515 $prefix = 'T' . 'a' . 'bl' . 'e';
516 }
517 if ( Visualizer_Module::is_pro() && $enable_controls ) {
518 $actions_div .= '<div id="control_wrapper_' . $id . '"></div>';
519 }
520 // return placeholder div
521 return '<div class="' . $container_class . '" id="chart_wrapper_' . $id . '">' . $actions_div . '<div id="' . $id . '"' . $this->getHtmlAttributes( $attributes ) . '></div>' . $this->addSchema( $chart->ID ) . ( ! Visualizer_Module::is_pro() ? ( '<' . 'di' . 'v st' . 'yl' . 'e="' . 'op' . 'a' . 'ci' . 't' . 'y:' . '0' . '.7' . ';t' . 'ex' . 't-a' . 'li' . 'gn:' . 'ri' . 'gh' . 't;b' . 'o' . 'tto' . 'm: 1' . '0px; z-i' . 'nd' . 'ex:1' . '00' . '0; ' . 'le' . 'ft' . ':2' . '0px' . '; fo' . 'nt-si' . 'ze: 1' . '4px">' . $prefix . ' b' . 'y' . ' <a ' . 'h' . 're' . 'f="ht' . 'tp' . 's:/' . '/t' . 'he' . 'me' . 'i' . 'sl' . 'e' . '.c' . 'om' . '/p' . 'lu' . 'gi' . 'ns' . '/v' . 'i' . 'su' . 'al' . 'iz' . 'er' . '-c' . 'ha' . 'rts' . '-a' . 'nd' . '-gr' . 'ap' . 'hs' . '/" t' . 'arg' . 'et="' . '_bl' . 'an' . 'k" re' . 'l=' . '"no' . 'fol' . 'l' . 'ow"' . '>V' . 'is' . 'u' . 'a' . 'l' . 'i' . 'z' . 'e' . 'r' . '</' . 'a' . '>' . '<' . '/' . 'd' . 'i' . 'v' . '>' ) : '' ) . '</div>';
522 }
523
524 /**
525 * Converts the array of attributes to a string of HTML attributes.
526 *
527 * @since ?
528 *
529 * @access private
530 */
531 private function getHtmlAttributes( $attributes ) {
532 $string = '';
533 if ( ! $attributes ) {
534 return $string;
535 }
536
537 foreach ( $attributes as $name => $value ) {
538 $string .= sprintf( ' %s="%s"', esc_attr( $name ), esc_attr( $value ) );
539 }
540 return $string;
541 }
542
543 /**
544 * Adds the schema corresponding to the dataset.
545 *
546 * @since 3.3.2
547 *
548 * @access private
549 */
550 private function addSchema( $id ) {
551 // should we show informative errors as HTML comments?
552 $show_errors = apply_filters( 'visualizer_schema_show_errors', true, $id );
553
554 $settings = get_post_meta( $id, Visualizer_Plugin::CF_SETTINGS, true );
555 $title = '';
556 if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
557 $title = $settings['title'];
558 if ( is_array( $title ) ) {
559 $title = $settings['title']['text'];
560 }
561 }
562 $title = apply_filters( 'visualizer_schema_name', $title, $id );
563 if ( empty( $title ) ) {
564 if ( $show_errors ) {
565 return "<!-- Not showing structured data for chart $id because title is empty -->";
566 }
567 return '';
568 }
569
570 $desc = '';
571 if ( isset( $settings['description'] ) && ! empty( $settings['description'] ) ) {
572 $desc = $settings['description'];
573 }
574 $desc = apply_filters( 'visualizer_schema_description', $desc, $id );
575 if ( empty( $desc ) ) {
576 if ( $show_errors ) {
577 return "<!-- Not showing structured data for chart $id because description is empty -->";
578 }
579 return '';
580 }
581
582 // descriptions below 50 chars are not allowed.
583 if ( strlen( $desc ) < 50 ) {
584 if ( $show_errors ) {
585 return "<!-- Not showing structured data for chart $id because description is shorter than 50 characters -->";
586 }
587 return '';
588 }
589
590 $license = '';
591 if ( isset( $settings['license'] ) && ! empty( $settings['license'] ) ) {
592 $license = $settings['license'];
593 if ( is_array( $license ) ) {
594 $license = $settings['license']['text'];
595 }
596 }
597 $license = apply_filters( 'visualizer_schema_license', $license, $id );
598 if ( empty( $license ) ) {
599 if ( $show_errors ) {
600 return "<!-- Not showing structured data for chart $id because license is empty -->";
601 }
602 return '';
603 }
604
605 $creator = '';
606 if ( isset( $settings['creator'] ) && ! empty( $settings['creator'] ) ) {
607 $creator = $settings['creator'];
608 if ( is_array( $creator ) ) {
609 $creator = $settings['creator']['text'];
610 }
611 }
612 $creator = apply_filters( 'visualizer_schema_creator', $creator, $id );
613 if ( empty( $creator ) ) {
614 if ( $show_errors ) {
615 return "<!-- Not showing structured data for chart $id because creator is empty -->";
616 }
617 return '';
618 }
619
620 $schema = apply_filters(
621 'visualizer_schema',
622 '{
623 "@context":"https://schema.org/",
624 "@type":"Dataset",
625 "name":"' . esc_html( $title ) . '",
626 "description":"' . esc_html( $desc ) . '",
627 "license": "' . esc_html( $license ) . '",
628 "creator": {
629 "@type": "Person",
630 "name": "' . esc_html( $creator ) . '"
631 }
632 }',
633 $id
634 );
635
636 if ( empty( $schema ) ) {
637 return '';
638 }
639
640 return '<script type="application/ld+json">' . $schema . '</script>';
641 }
642
643 /**
644 * Get chart by ID.
645 *
646 * @param string $cache_key Cache key.
647 * @param int $chart_id Chart ID.
648 * @return mixed
649 */
650 private function getChartData( $cache_key = '', $chart_id = 0 ) {
651 if ( ! $chart_id ) {
652 return false;
653 }
654 // Create unique cache key of each chart.
655 $cache_key .= '_' . $chart_id;
656 // Get chart from cache.
657 $chart = get_transient( $cache_key );
658 if ( $chart ) {
659 return $chart;
660 }
661
662 // Get chart by ID.
663 $chart = get_post( $chart_id );
664 if ( $chart && Visualizer_Plugin::CPT_VISUALIZER === $chart->post_type ) {
665 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
666 $series = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true );
667 $is_woocommerce_report = get_post_meta( $chart->ID, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE, true );
668
669 if ( isset( $settings['series'] ) && ! ( count( $settings['series'] ) - count( $series ) > 1 ) ) {
670 $diff_total_series = abs( count( $settings['series'] ) - count( $series ) );
671 if ( $diff_total_series ) {
672 foreach ( range( 1, $diff_total_series ) as $k => $diff_series ) {
673 $settings['series'][] = end( $settings['series'] );
674 }
675 }
676 }
677 $chart_data = array(
678 'chart' => $chart,
679 'type' => get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true ),
680 'settings' => $settings,
681 'series' => $series,
682 'chart_image' => get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_IMAGE, true ),
683 'is_woocommerce_report' => $is_woocommerce_report,
684 );
685
686 // Put the results in a transient. Expire after 12 hours.
687 set_transient( $cache_key, $chart_data, apply_filters( Visualizer_Plugin::FILTER_HANDLE_CACHE_EXPIRATION_TIME, 12 * HOUR_IN_SECONDS ) );
688 return $chart_data;
689 }
690
691 return false;
692 }
693
694 /**
695 * Print footer script.
696 */
697 public function printFooterScripts() {
698 if ( $this->lazy_render_script ) {
699 ?>
700 <script type="text/javascript">
701 var visualizerUserInteractionEvents = [
702 "mouseover",
703 "keydown",
704 "touchmove",
705 "touchstart"
706 ];
707
708 visualizerUserInteractionEvents.forEach(function(event) {
709 window.addEventListener(event, visualizerTriggerScriptLoader, { passive: true });
710 });
711
712 function visualizerTriggerScriptLoader() {
713 visualizerLoadScripts();
714 visualizerUserInteractionEvents.forEach(function(event) {
715 window.removeEventListener(event, visualizerTriggerScriptLoader, { passive: true });
716 });
717 }
718
719 function visualizerLoadScripts() {
720 document.querySelectorAll("script[data-visualizer-script]").forEach(function(elem) {
721 jQuery.getScript( elem.getAttribute("data-visualizer-script") )
722 .done( function( script, textStatus ) {
723 elem.setAttribute("src", elem.getAttribute("data-visualizer-script"));
724 elem.removeAttribute("data-visualizer-script");
725 setTimeout( function() {
726 visualizerRefreshChart();
727 } );
728 } );
729 });
730 }
731
732 function visualizerRefreshChart() {
733 jQuery( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
734 if ( jQuery( 'div.viz-facade-loaded:not(.visualizer-lazy):empty' ).length > 0 ) {
735 visualizerUserInteractionEvents.forEach( function( event ) {
736 window.addEventListener( event, function() {
737 jQuery( '.visualizer-front:not(.visualizer-chart-loaded)' ).resize();
738 }, { passive: true } );
739 } );
740 }
741 }
742 </script>
743 <?php
744 }
745 }
746 }
747