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

456 lines 14.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 * Constructor.
46 *
47 * @since 1.0.0
48 * @uses add_filter() To add "do_shortcode" hook for "widget_text" and "term_description" filters.
49 *
50 * @access public
51 * @param Visualizer_Plugin $plugin The instance of the plugin.
52 */
53 public function __construct( Visualizer_Plugin $plugin ) {
54 parent::__construct( $plugin );
55
56 $this->_addAction( 'wp_enqueue_scripts', 'enqueueScripts' );
57 $this->_addAction( 'visualizer_enqueue_scripts', 'enqueueScripts' );
58 $this->_addFilter( 'visualizer_get_language', 'getLanguage' );
59 $this->_addShortcode( 'visualizer', 'renderChart' );
60
61 // add do_shortocde hook for widget_text filter
62 if ( ! has_filter( 'widget_text', 'do_shortcode' ) ) {
63 add_filter( 'widget_text', 'do_shortcode' );
64 }
65
66 // add do_shortcode hook for term_description filter
67 if ( ! has_filter( 'term_description', 'do_shortcode' ) ) {
68 add_filter( 'term_description', 'do_shortcode' );
69 }
70
71 add_action( 'rest_api_init', array( $this, 'endpoint_register' ) );
72
73 $this->_addFilter( 'script_loader_tag', 'script_loader_tag', null, 10, 3 );
74 }
75
76 /**
77 * Adds the async attribute to certain scripts.
78 */
79 function script_loader_tag( $tag, $handle, $src ) {
80 if ( is_admin() ) {
81 return $tag;
82 }
83
84 $scripts = array( 'google-jsapi-new', 'google-jsapi-old', 'visualizer-render-google-lib', 'visualizer-render-google' );
85
86 foreach ( $scripts as $async ) {
87 if ( $async === $handle ) {
88 $tag = str_replace( ' src', ' defer="defer" src', $tag );
89 break;
90 }
91 }
92 return $tag;
93 }
94
95 /**
96 * Returns the language/locale.
97 */
98 function getLanguage( $dummy, $only_language ) {
99 return $this->get_language();
100 }
101
102
103 /**
104 * Registers the endpoints
105 */
106 function endpoint_register() {
107 register_rest_route(
108 'visualizer/v' . VISUALIZER_REST_VERSION,
109 '/action/(?P<chart>\d+)/(?P<type>.+)/',
110 array(
111 'methods' => array( 'GET', 'POST' ),
112 'callback' => array( $this, 'perform_action' ),
113 )
114 );
115 }
116
117 /**
118 * All possible actions and their labels
119 *
120 * @access private
121 */
122 private function get_actions() {
123 $actions = apply_filters(
124 'visualizer_action_buttons',
125 array(
126 'print' => array(
127 'label' => esc_html__( 'Print', 'visualizer' ),
128 'title' => esc_html__( 'Print Chart', 'visualizer' ),
129 ),
130 'csv' => array(
131 'label' => esc_html__( 'CSV', 'visualizer' ),
132 'title' => esc_html__( 'Download as a CSV', 'visualizer' ),
133 ),
134 'xls' => array(
135 'label' => esc_html__( 'Excel', 'visualizer' ),
136 'title' => esc_html__( 'Download as a spreadsheet', 'visualizer' ),
137 ),
138 'copy' => array(
139 'label' => esc_html__( 'Copy', 'visualizer' ),
140 'title' => esc_html__( 'Copy data', 'visualizer' ),
141 ),
142 'image' => array(
143 'label' => esc_html__( 'Download', 'visualizer' ),
144 'title' => esc_html__( 'Download as an image', 'visualizer' ),
145 ),
146 )
147 );
148
149 // backward compatibility before label and title attributes were introduced.
150 if ( isset( $actions['edit'] ) && is_string( $actions['edit'] ) ) {
151 $actions['edit'] = array(
152 'label' => esc_html__( 'Edit', 'visualizer' ),
153 'title' => esc_html__( 'Edit data', 'visualizer' ),
154 );
155 }
156 return $actions;
157 }
158
159 /**
160 * The print button
161 *
162 * @since 1.0.0
163 *
164 * @access public
165 */
166 public function perform_action( WP_REST_Request $params ) {
167 $chart_id = filter_var( sanitize_text_field( $params['chart'] ), FILTER_VALIDATE_INT );
168 $type = sanitize_text_field( $params['type'] );
169 $data = null;
170
171 if ( ! $chart_id ) {
172 return new WP_REST_Response( array( 'error' => new WP_Error( __( 'Invalid chart ID', 'visualizer' ) ) ) );
173 }
174
175 if ( ! $type ) {
176 return new WP_REST_Response( array( 'error' => new WP_Error( __( 'Invalid action', 'visualizer' ) ) ) );
177 }
178
179 switch ( $type ) {
180 case 'print':
181 $data = $this->_getDataAs( $chart_id, 'print' );
182 break;
183 case 'csv':
184 $data = $this->_getDataAs( $chart_id, 'csv' );
185 break;
186 case 'xls':
187 $data = $this->_getDataAs( $chart_id, 'xls' );
188 break;
189 case 'image':
190 $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
191 $title = 'visualizer#' . $chart_id;
192 if ( ! empty( $settings['title'] ) ) {
193 $title = $settings['title'];
194 }
195 // for ChartJS, title is an array.
196 if ( is_array( $title ) && isset( $title['text'] ) ) {
197 $title = $title['text'];
198 }
199 if ( empty( $title ) ) {
200 $title = 'visualizer#' . $chart_id;
201 }
202 $data = array( 'name' => $title );
203 break;
204 default:
205 $data = apply_filters( 'visualizer_action_data', $data, $chart_id, $type, $params, $this );
206 break;
207 }
208
209 return new WP_REST_Response( array( 'data' => $data ) );
210 }
211
212 /**
213 * Registers scripts for charts rendering.
214 *
215 * @since 1.0.0
216 * @uses wp_register_script To register javascript file.
217 *
218 * @access public
219 */
220 public function enqueueScripts() {
221 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
222 wp_register_script( 'visualizer-clipboardjs', VISUALIZER_ABSURL . 'js/lib/clipboardjs/clipboard.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
223 wp_register_style( 'visualizer-front', VISUALIZER_ABSURL . 'css/front.css', array(), Visualizer_Plugin::VERSION );
224 do_action( 'visualizer_pro_frontend_load_resources' );
225 }
226
227 /**
228 * Returns placeholder for chart according to visualizer shortcode attributes.
229 *
230 * @since 1.0.0
231 * @uses shortcode_atts() To parse income shortocdes.
232 * @uses apply_filters() To filter chart's data and series arrays.
233 * @uses get_post_meta() To fetch chart's meta information.
234 * @uses wp_enqueue_script() To enqueue charts render script.
235 * @uses wp_localize_script() To add chart data to the page inline script.
236 *
237 * @access public
238 * @param array $atts The array of shortcode attributes.
239 */
240 public function renderChart( $atts ) {
241 global $wp_version;
242 $atts = shortcode_atts(
243 array(
244 'id' => false, // chart id
245 'class' => false, // chart class
246 'series' => false, // series filter hook
247 'data' => false, // data filter hook
248 'settings' => false, // data filter hook
249 ),
250 $atts
251 );
252
253 // if empty id or chart does not exists, then return empty string
254 if ( ! $atts['id'] || ! ( $chart = get_post( $atts['id'] ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
255 return '';
256 }
257
258 if ( ! apply_filters( 'visualizer_pro_show_chart', true, $atts['id'] ) ) {
259 return '';
260 }
261
262 // in case revisions exist.
263 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found
264 if ( true === ( $revisions = $this->undoRevisions( $chart->ID, true ) ) ) {
265 $chart = get_post( $chart->ID );
266 }
267
268 $id = 'visualizer-' . $atts['id'];
269 $defaultClass = 'visualizer-front';
270 $class = apply_filters( Visualizer_Plugin::FILTER_CHART_WRAPPER_CLASS, $atts['class'], $atts['id'] );
271 $class = $defaultClass . ' ' . $class . ' ' . 'visualizer-front-' . $atts['id'];
272 $class = ! empty( $class ) ? ' class="' . trim( $class ) . '"' : '';
273
274 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
275
276 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
277
278 // fetch and update settings
279 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
280 if ( empty( $settings['height'] ) ) {
281 $settings['height'] = '400';
282 }
283
284 // handle series filter hooks
285 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
286 if ( ! empty( $atts['series'] ) ) {
287 $series = apply_filters( $atts['series'], $series, $chart->ID, $type );
288 }
289 // handle settings filter hooks
290 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
291 if ( ! empty( $atts['settings'] ) ) {
292 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
293 }
294
295 // handle data filter hooks
296 $data = self::get_chart_data( $chart, $type );
297 if ( ! empty( $atts['data'] ) ) {
298 $data = apply_filters( $atts['data'], $data, $chart->ID, $type );
299 }
300
301 $css = '';
302 $arguments = $this->get_inline_custom_css( $id, $settings );
303 if ( ! empty( $arguments ) ) {
304 $css = $arguments[0];
305 $settings = $arguments[1];
306 }
307
308 $library = $this->load_chart_type( $chart->ID );
309
310 $id = $id . '-' . rand();
311
312 $amp = Visualizer_Plugin::instance()->getModule( Visualizer_Module_AMP::NAME );
313 if ( $amp && $amp->is_amp() ) {
314 return '<div id="' . $id . '"' . $class . '>' . $amp->get_chart( $chart, $data, $series, $settings ) . '</div>';
315 }
316
317 // add chart to the array
318 $this->_charts[ $id ] = array(
319 'type' => $type,
320 'series' => $series,
321 'settings' => $settings,
322 'data' => $data,
323 'library' => $library,
324 );
325
326 $actions_div = '';
327 $actions_visible = apply_filters( 'visualizer_pro_add_actions', isset( $settings['actions'] ) ? $settings['actions'] : array(), $atts['id'] );
328 if ( ! empty( $actions_visible ) ) {
329 $actions = $this->get_actions();
330 $actions_div = '<div class="visualizer-actions">';
331 foreach ( $actions_visible as $action_type ) {
332 $key = $action_type;
333 $mime = '';
334 if ( strpos( $action_type, ';' ) !== false ) {
335 $array = explode( ';', $action_type );
336 $key = $array[0];
337 $mime = end( $array );
338 }
339 $label = $actions[ $key ]['label'];
340 $title = $actions[ $key ]['title'];
341 $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 );
342
343 if ( 'copy' === $key ) {
344 $copy = $this->_getDataAs( $atts['id'], 'csv' );
345 $actions_div .= ' data-clipboard-text="' . esc_attr( $copy['csv'] ) . '"';
346 wp_enqueue_script( 'visualizer-clipboardjs' );
347 }
348
349 $actions_div .= apply_filters( 'visualizer_action_attributes', '', $key, $atts['id'] );
350 $actions_div .= '>' . $label . '</a> &nbsp;';
351 }
352
353 $actions_div .= '</div>';
354 }
355
356 $actions_div .= $css;
357
358 foreach ( $this->_charts as $id => $attributes ) {
359 $library = $attributes['library'];
360 wp_register_script(
361 "visualizer-render-$library",
362 VISUALIZER_ABSURL . 'js/render-facade.js',
363 apply_filters( 'visualizer_assets_render', array( 'jquery', 'visualizer-customization' ), true ),
364 Visualizer_Plugin::VERSION,
365 true
366 );
367
368 wp_enqueue_script( "visualizer-render-$library" );
369 wp_localize_script(
370 "visualizer-render-$library",
371 'visualizer',
372 array(
373 'charts' => $this->_charts,
374 'language' => $this->get_language(),
375 'map_api_key' => get_option( 'visualizer-map-api-key' ),
376 'rest_url' => version_compare( $wp_version, '4.7.0', '>=' ) ? rest_url( 'visualizer/v' . VISUALIZER_REST_VERSION . '/action/#id#/#type#/' ) : '',
377 'i10n' => array(
378 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
379 ),
380 'page_type' => 'frontend',
381 'is_front' => true,
382 )
383 );
384 wp_enqueue_style( 'visualizer-front' );
385 }
386
387 // return placeholder div
388 return $actions_div . '<div id="' . $id . '"' . $class . '></div>' . $this->addSchema( $chart->ID );
389 }
390
391 /**
392 * Adds the schema corresponding to the dataset.
393 *
394 * @since 3.3.2
395 *
396 * @access private
397 */
398 private function addSchema( $id ) {
399 // should we show informative errors as HTML comments?
400 $show_errors = apply_filters( 'visualizer_schema_show_errors', true, $id );
401
402 $settings = get_post_meta( $id, Visualizer_Plugin::CF_SETTINGS, true );
403 $title = '';
404 if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
405 $title = $settings['title'];
406 if ( is_array( $title ) ) {
407 $title = $settings['title']['text'];
408 }
409 }
410 $title = apply_filters( 'visualizer_schema_name', $title, $id );
411 if ( empty( $title ) ) {
412 if ( $show_errors ) {
413 return "<!-- Not showing structured data for chart $id because title is empty -->";
414 }
415 return '';
416 }
417
418 $desc = '';
419 if ( isset( $settings['description'] ) && ! empty( $settings['description'] ) ) {
420 $desc = $settings['description'];
421 }
422 $desc = apply_filters( 'visualizer_schema_description', $desc, $id );
423 if ( empty( $desc ) ) {
424 if ( $show_errors ) {
425 return "<!-- Not showing structured data for chart $id because description is empty -->";
426 }
427 return '';
428 }
429
430 // descriptions below 50 chars are not allowed.
431 if ( strlen( $desc ) < 50 ) {
432 if ( $show_errors ) {
433 return "<!-- Not showing structured data for chart $id because description is shorter than 50 characters -->";
434 }
435 return '';
436 }
437
438 $schema = apply_filters(
439 'visualizer_schema',
440 '{
441 "@context":"https://schema.org/",
442 "@type":"Dataset",
443 "name":"' . esc_html( $title ) . '",
444 "description":"' . esc_html( $desc ) . '"
445 }',
446 $id
447 );
448
449 if ( empty( $schema ) ) {
450 return '';
451 }
452
453 return '<script type="application/ld+json">' . $schema . '</script>';
454 }
455 }
456