PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.1
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 / Admin.php

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

1,196 lines 38.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
4 // +----------------------------------------------------------------------+
5 // | This program is free software; you can redistribute it and/or modify |
6 // | it under the terms of the GNU General Public License, version 2, as |
7 // | published by the Free Software Foundation. |
8 // | |
9 // | This program is distributed in the hope that it will be useful, |
10 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 // | GNU General Public License for more details. |
13 // | |
14 // | You should have received a copy of the GNU General Public License |
15 // | along with this program; if not, write to the Free Software |
16 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
17 // | MA 02110-1301 USA |
18 // +----------------------------------------------------------------------+
19 // | Author: Eugene Manuilov <eugene@manuilov.org> |
20 // +----------------------------------------------------------------------+
21 /**
22 * The module for all admin stuff.
23 *
24 * @category Visualizer
25 * @package Module
26 *
27 * @since 1.0.0
28 */
29 class Visualizer_Module_Admin extends Visualizer_Module {
30
31 const NAME = __CLASS__;
32
33 /**
34 * Library page suffix.
35 *
36 * @since 1.0.0
37 *
38 * @access private
39 * @var string
40 */
41 private $_libraryPage;
42
43 /**
44 * Constructor.
45 *
46 * @since 1.0.0
47 *
48 * @access public
49 *
50 * @param Visualizer_Plugin $plugin The instance of the plugin.
51 */
52 public function __construct( Visualizer_Plugin $plugin ) {
53 parent::__construct( $plugin );
54 $this->_addAction( 'load-post.php', 'enqueueMediaScripts' );
55 $this->_addAction( 'load-post-new.php', 'enqueueMediaScripts' );
56 $this->_addAction( 'admin_footer', 'renderTemplates' );
57 $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 0 );
58 $this->_addAction( 'admin_menu', 'registerAdminMenu' );
59 $this->_addFilter( 'media_view_strings', 'setupMediaViewStrings' );
60 $this->_addFilter( 'plugin_action_links', 'getPluginActionLinks', 10, 2 );
61 $this->_addFilter( 'plugin_row_meta', 'getPluginMetaLinks', 10, 2 );
62 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
63 $this->_addFilter( 'visualizer_feedback_review_trigger', 'feedbackReviewTrigger' );
64
65 // screen pagination
66 $this->_addFilter( 'set-screen-option', 'setScreenOptions', 10, 3 );
67
68 // revision support.
69 $this->_addFilter( 'wp_revisions_to_keep', 'limitRevisions', null, 10, 2 );
70 $this->_addAction( '_wp_put_post_revision', 'addRevision', null, 10, 1 );
71 $this->_addAction( 'wp_restore_post_revision', 'restoreRevision', null, 10, 2 );
72
73 $this->_addAction( 'visualizer_chart_schedules_spl', 'addSplChartSchedules', null, 10, 3 );
74
75 $this->_addAction( 'admin_init', 'init' );
76
77 $this->_addAction( 'visualizer_chart_languages', 'addMultilingualSupport' );
78
79 if ( defined( 'TI_CYPRESS_TESTING' ) ) {
80 $this->load_cypress_hooks();
81 }
82
83 }
84
85 /**
86 * Define the hooks that are needed for cypress.
87 *
88 * @since 3.4.0
89 * @access private
90 */
91 private function load_cypress_hooks() {
92 // all charts should load on the same page without pagination.
93 add_filter(
94 'visualizer_query_args', function( $args ) {
95 $args['posts_per_page'] = 20;
96 return $args;
97 }, 10, 1
98 );
99 }
100
101 /**
102 * Add disabled `optgroup` schedules to the drop downs.
103 *
104 * @since ?
105 *
106 * @access public
107 *
108 * @param string $feature The feature for which to add schedules.
109 * @param int $chart_id The chart ID.
110 * @param int $plan The plan number.
111 */
112 public function addSplChartSchedules( $feature, $chart_id, $plan ) {
113 if ( apply_filters( 'visualizer_is_business', false ) ) {
114 return;
115 }
116
117 $license = __( 'PRO', 'visualizer' );
118 if ( Visualizer_Module::is_pro() ) {
119 switch ( $plan ) {
120 case 1:
121 $license = __( 'Developer', 'visualizer' );
122 break;
123 }
124 }
125
126 $hours = array(
127 '0' => __( 'Live', 'visualizer' ),
128 '1' => __( 'Each hour', 'visualizer' ),
129 '12' => __( 'Each 12 hours', 'visualizer' ),
130 '24' => __( 'Each day', 'visualizer' ),
131 '72' => __( 'Each 3 days', 'visualizer' ),
132 );
133
134 switch ( $feature ) {
135 case 'json':
136 case 'csv':
137 // no more schedules if pro is already active.
138 if ( Visualizer_Module::is_pro() ) {
139 return;
140 }
141 break;
142 case 'wp':
143 // fall-through.
144 case 'db':
145 break;
146 default:
147 return;
148 }
149
150 echo '<optgroup disabled label="' . sprintf( __( 'More in the %s version', 'visualizer' ), $license ) . '">';
151 foreach ( $hours as $hour => $desc ) {
152 echo '<option disabled>' . $desc . '</option>';
153 }
154 echo '</optgroup>';
155 }
156
157 /**
158 * No limits on revisions.
159 */
160 public function limitRevisions( $num, $post ) {
161 if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
162 return -1;
163 }
164 return $num;
165 }
166
167 /**
168 * Add a revision.
169 */
170 public function addRevision( $revision_id ) {
171 $parent_id = wp_is_post_revision( $revision_id );
172 if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $parent_id ) ) {
173 // add the meta data to this revision.
174 $meta = get_post_meta( $parent_id, '', true );
175
176 if ( $meta ) {
177 foreach ( $meta as $key => $value ) {
178 if ( 0 === strpos( $key, 'visualizer' ) ) {
179 add_metadata( 'post', $revision_id, $key, maybe_unserialize( $value[0] ) );
180 }
181 }
182 }
183 }
184 }
185
186 /**
187 * Restore a revision.
188 */
189 public function restoreRevision( $post_id, $revision_id ) {
190 if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $post_id ) ) {
191 // get the meta information from the revision.
192 $meta = get_metadata( 'post', $revision_id, '', true );
193
194 // delete all meta information from the post before adding.
195 $post_meta = get_post_meta( $post_id, '', true );
196 if ( $post_meta ) {
197 foreach ( $meta as $key => $value ) {
198 if ( 0 === strpos( $key, 'visualizer' ) ) {
199 delete_post_meta( $post_id, $key );
200 }
201 }
202 }
203
204 if ( $meta ) {
205 foreach ( $meta as $key => $value ) {
206 if ( 0 === strpos( $key, 'visualizer' ) ) {
207 add_post_meta( $post_id, $key, maybe_unserialize( $value[0] ) );
208 }
209 }
210 }
211 }
212 }
213
214 /**
215 * Admin init.
216 *
217 * @access public
218 */
219 public function init() {
220 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
221 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
222 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
223 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
224 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
225 $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
226 }
227 }
228
229 /**
230 * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
231 *
232 * @since ?
233 * @access friendly
234 */
235 function get_strings_for_block( $settings ) {
236 $class = new Visualizer_Module_Language();
237 $strings = $class->get_strings();
238 $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
239 return array_merge( $settings, $array );
240 }
241
242 /**
243 * Load plugin translation for - TinyMCE API
244 *
245 * @access public
246 * @param array $arr The tinymce_lang array.
247 * @return array
248 */
249 public function add_tinymce_lang( $arr ) {
250 $ui_lang = VISUALIZER_ABSPATH . '/classes/Visualizer/Module/Language.php';
251 $ui_lang = apply_filters( 'visualizer_ui_lang_filter', $ui_lang );
252 $arr[] = $ui_lang;
253 return $arr;
254 }
255
256 /**
257 * Load custom js options - TinyMCE API
258 *
259 * @access public
260 * @param array $plugin_array The tinymce plugin array.
261 * @return array
262 */
263 public function tinymce_plugin( $plugin_array ) {
264 $plugin_array['visualizer_mce_button'] = VISUALIZER_ABSURL . 'js/mce.js';
265 return $plugin_array;
266 }
267
268 /**
269 * Register new button in the editor
270 *
271 * @access public
272 * @param array $buttons The tinymce buttons array.
273 * @return array
274 */
275 public function register_mce_button( $buttons ) {
276 array_push( $buttons, 'visualizer_mce_button' );
277 return $buttons;
278 }
279
280 /**
281 * Whether to show the feedback review or not.
282 *
283 * @access public
284 */
285 public function feedbackReviewTrigger( $dumb ) {
286 $query = new WP_Query(
287 array(
288 'posts_per_page' => 50,
289 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
290 'fields' => 'ids',
291 'update_post_meta_cache' => false,
292 'update_post_term_cache' => false,
293 )
294 );
295
296 if ( $query->have_posts() && $query->post_count > 0 ) {
297 return true;
298 }
299 return false;
300 }
301
302 /**
303 * Enqueues media scripts and styles.
304 *
305 * @since 1.0.0
306 * @uses wp_enqueue_style To enqueue style file.
307 * @uses wp_enqueue_script To enqueue script file.
308 *
309 * @access public
310 */
311 public function enqueueMediaScripts() {
312 global $typenow;
313 if ( post_type_supports( $typenow, 'editor' ) ) {
314 wp_enqueue_style( 'visualizer-media', VISUALIZER_ABSURL . 'css/media.css', array( 'media-views' ), Visualizer_Plugin::VERSION );
315
316 // Load all the assets for the different libraries we support.
317 $deps = array(
318 Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
319 Visualizer_Render_Sidebar_Type_DataTable_Tabular::enqueue_assets( array( 'media-editor' ) ),
320 );
321
322 wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
323 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
324 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
325 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
326 wp_localize_script(
327 'visualizer-media-view',
328 'visualizer',
329 array(
330 'i10n' => array(
331 'insert' => __( 'Insert', 'visualizer' ),
332 ),
333 )
334 );
335 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
336 wp_enqueue_script( 'visualizer-media', VISUALIZER_ABSURL . 'js/media.js', array( 'visualizer-media-toolbar' ), Visualizer_Plugin::VERSION, true );
337 }
338 }
339
340 /**
341 * Extends media view strings with visualizer strings.
342 *
343 * @since 1.0.0
344 *
345 * @access public
346 *
347 * @param array $strings The array of media view strings.
348 *
349 * @return array The extended array of media view strings.
350 */
351 public function setupMediaViewStrings( $strings ) {
352 $chart_types = self::_getChartTypesLocalized( true, true, true );
353 $strings['visualizer'] = array(
354 'actions' => array(
355 'get_charts' => Visualizer_Plugin::ACTION_GET_CHARTS,
356 'delete_chart' => Visualizer_Plugin::ACTION_DELETE_CHART,
357 ),
358 'controller' => array(
359 'title' => esc_html__( 'Visualizations', 'visualizer' ),
360 ),
361 'routers' => array(
362 'library' => esc_html__( 'From Library', 'visualizer' ),
363 'create' => esc_html__( 'Create New', 'visualizer' ),
364 ),
365 'library' => array(
366 'filters' => $chart_types,
367 'types' => array_keys( $chart_types ),
368 ),
369 'nonce' => wp_create_nonce(),
370 'buildurl' => esc_url( add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ) ),
371 );
372
373 return $strings;
374 }
375
376 /**
377 * Returns associated array of chart types and localized names.
378 *
379 * @since 1.0.0
380 *
381 * @static
382 * @access private
383 * @return array The associated array of chart types with localized names.
384 */
385 public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
386 $additional = array();
387 if ( $add_select ) {
388 $additional['select'] = array(
389 'name' => esc_html__( 'All', 'visualizer' ),
390 'enabled' => true,
391 );
392 }
393
394 $enabled = self::proFeaturesLocked();
395
396 $types = array_merge(
397 $additional,
398 array(
399 'tabular' => array(
400 'name' => esc_html__( 'Table', 'visualizer' ),
401 'enabled' => true,
402 'supports' => $enabled ? array( 'Google Charts', 'DataTable' ) : array( 'DataTable' ),
403 ),
404 'pie' => array(
405 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
406 'enabled' => true,
407 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
408 ),
409 'line' => array(
410 'name' => esc_html__( 'Line', 'visualizer' ),
411 'enabled' => true,
412 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
413 ),
414 'bar' => array(
415 'name' => esc_html__( 'Bar', 'visualizer' ),
416 'enabled' => true,
417 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
418 ),
419 'area' => array(
420 'name' => esc_html__( 'Area', 'visualizer' ),
421 'enabled' => $enabled,
422 // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
423 'supports' => array( 'Google Charts' ),
424 ),
425 'geo' => array(
426 'name' => esc_html__( 'Geo', 'visualizer' ),
427 'enabled' => $enabled,
428 'supports' => array( 'Google Charts' ),
429 ),
430 'column' => array(
431 'name' => esc_html__( 'Column', 'visualizer' ),
432 'enabled' => $enabled,
433 'supports' => array( 'Google Charts', 'ChartJS' ),
434 ),
435 'bubble' => array(
436 'name' => esc_html__( 'Bubble', 'visualizer' ),
437 'enabled' => $enabled,
438 // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
439 'supports' => array( 'Google Charts' ),
440 ),
441 'scatter' => array(
442 'name' => esc_html__( 'Scatter', 'visualizer' ),
443 'enabled' => $enabled,
444 'supports' => array( 'Google Charts' ),
445 ),
446 'gauge' => array(
447 'name' => esc_html__( 'Gauge', 'visualizer' ),
448 'enabled' => $enabled,
449 'supports' => array( 'Google Charts' ),
450 ),
451 'candlestick' => array(
452 'name' => esc_html__( 'Candlestick', 'visualizer' ),
453 'enabled' => $enabled,
454 'supports' => array( 'Google Charts' ),
455 ),
456 // pro types
457 'timeline' => array(
458 'name' => esc_html__( 'Timeline', 'visualizer' ),
459 'enabled' => false,
460 'supports' => array( 'Google Charts', 'ChartJS' ),
461 ),
462 'combo' => array(
463 'name' => esc_html__( 'Combo', 'visualizer' ),
464 'enabled' => false,
465 'supports' => array( 'Google Charts' ),
466 ),
467 'polarArea' => array(
468 'name' => esc_html__( 'Polar Area', 'visualizer' ),
469 'enabled' => false,
470 'supports' => array( 'ChartJS' ),
471 ),
472 'radar' => array(
473 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
474 'enabled' => false,
475 'supports' => array( 'ChartJS' ),
476 ),
477 )
478 );
479 $types = apply_filters( 'visualizer_pro_chart_types', $types );
480 if ( $enabledOnly ) {
481 $filtered = array();
482 foreach ( $types as $type => $array ) {
483 if ( ! is_array( $array ) ) {
484 // support for old pro
485 $array = array( 'enabled' => true, 'name' => $array );
486 }
487 // backward compatibility for PRO before v1.9.0
488 if ( ! array_key_exists( 'supports', $array ) ) {
489 $array['supports'] = array( 'Google Charts' );
490 }
491 if ( ! $array['enabled'] ) {
492 continue;
493 }
494 $filtered[ $type ] = $array;
495 }
496 $types = $filtered;
497 }
498 if ( $get2Darray ) {
499 $doubleD = array();
500 foreach ( $types as $type => $array ) {
501 if ( ! is_array( $array ) ) {
502 // support for old pro
503 $array = array( 'enabled' => true, 'name' => $array );
504 }
505 // backward compatibility for PRO before v1.9.0
506 if ( ! array_key_exists( 'supports', $array ) ) {
507 $array['supports'] = array( 'Google Charts' );
508 }
509 $doubleD[ $type ] = $array['name'];
510 }
511 $types = $doubleD;
512 }
513
514 return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
515 }
516
517 /**
518 * Handle (soon-to-be) deprecated charts.
519 */
520 private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
521 $deprecated = array();
522
523 switch ( $where ) {
524 case 'types':
525 // fall-through
526 case 'library':
527 // if a user has a Gauge/Candlestick chart, then let them keep using it.
528 if ( ! Visualizer_Module::is_pro() ) {
529 if ( ! self::hasChartType( 'gauge' ) ) {
530 if ( $get2Darray ) {
531 $deprecated[] = 'gauge';
532 } else {
533 $types['gauge']['enabled'] = false;
534 }
535 }
536 if ( ! self::hasChartType( 'candlestick' ) ) {
537 if ( $get2Darray ) {
538 $deprecated[] = 'candlestick';
539 } else {
540 $types['candlestick']['enabled'] = false;
541 }
542 }
543 }
544 break;
545 default:
546 // if a user has a Gauge/Candlestick chart, then let them keep using it.
547 if ( ! Visualizer_Module::is_pro() ) {
548 if ( ! self::hasChartType( 'gauge' ) ) {
549 if ( $get2Darray ) {
550 $deprecated[] = 'gauge';
551 } else {
552 $types['gauge']['enabled'] = false;
553 }
554 }
555 if ( ! self::hasChartType( 'candlestick' ) ) {
556 if ( $get2Darray ) {
557 $deprecated[] = 'candlestick';
558 } else {
559 $types['candlestick']['enabled'] = false;
560 }
561 }
562 }
563 }
564
565 if ( $deprecated ) {
566 foreach ( $deprecated as $type ) {
567 unset( $types[ $type ] );
568 }
569 }
570
571 return $types;
572 }
573
574 /**
575 * Renders templates to use in media popup.
576 *
577 * @since 1.0.0
578 * @global string $pagenow The name of the current page.
579 *
580 * @access public
581 */
582 public function renderTemplates() {
583 global $pagenow;
584 if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
585 return;
586 }
587 $render = new Visualizer_Render_Templates();
588 $render->render();
589 }
590
591 /**
592 * Enqueues library scripts and styles.
593 *
594 * @since 1.0.0
595 * @uses wp_enqueue_style() To enqueue library stylesheet.
596 * @uses wp_enqueue_script() To enqueue javascript file.
597 * @uses wp_enqueue_media() To enqueue media stuff.
598 *
599 * @access public
600 *
601 * @param string $suffix The current page suffix.
602 */
603 public function enqueueLibraryScripts( $suffix ) {
604 if ( $suffix === $this->_libraryPage ) {
605 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
606 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
607 wp_enqueue_media();
608 wp_enqueue_script(
609 'visualizer-library',
610 VISUALIZER_ABSURL . 'js/library.js',
611 array(
612 'jquery',
613 'media-views',
614 'clipboard',
615 ),
616 Visualizer_Plugin::VERSION,
617 true
618 );
619
620 wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
621
622 $query = $this->getQuery();
623 while ( $query->have_posts() ) {
624 $chart = $query->next_post();
625 $library = $this->load_chart_type( $chart->ID );
626 if ( is_null( $library ) ) {
627 continue;
628 }
629 wp_enqueue_script(
630 "visualizer-render-$library",
631 VISUALIZER_ABSURL . 'js/render-facade.js',
632 apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
633 Visualizer_Plugin::VERSION,
634 true
635 );
636 }
637 }
638 }
639
640 /**
641 * Adds visualizer tab for media upload tabs array.
642 *
643 * @since 1.0.0
644 *
645 * @access public
646 *
647 * @param array $tabs The array of media upload tabs.
648 *
649 * @return array Extended array of media upload tabs.
650 */
651 public function setupVisualizerTab( $tabs ) {
652 $tabs['visualizer'] = 'Visualizer';
653
654 return $tabs;
655 }
656
657 /**
658 * Registers admin menu for visualizer library.
659 *
660 * @since 1.0.0
661 *
662 * @access public
663 */
664 public function registerAdminMenu() {
665 $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
666
667 $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
668
669 add_submenu_page(
670 Visualizer_Plugin::NAME,
671 __( 'Chart Library', 'visualizer' ),
672 __( 'Chart Library', 'visualizer' ),
673 'edit_posts',
674 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
675 );
676 add_submenu_page(
677 Visualizer_Plugin::NAME,
678 __( 'Add New Chart', 'visualizer' ),
679 __( 'Add New Chart', 'visualizer' ),
680 'edit_posts',
681 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
682 );
683 add_submenu_page(
684 Visualizer_Plugin::NAME,
685 __( 'Support', 'visualizer' ),
686 __( 'Support', 'visualizer' ) . '<span class="dashicons dashicons-editor-help more-features-icon" style="width: 17px; height: 17px; margin-left: 4px; color: #ffca54; font-size: 17px; vertical-align: -3px;"></span>',
687 'edit_posts',
688 'viz-support',
689 array( $this, 'renderSupportPage' )
690 );
691
692 if ( ! Visualizer_Module::is_pro() ) {
693 add_submenu_page(
694 Visualizer_Plugin::NAME,
695 __( 'Get Visualizer Pro', 'visualizer' ),
696 __( 'Get Visualizer Pro', 'visualizer' ),
697 'edit_posts',
698 'viz-get-pro',
699 '__return_null'
700 );
701 add_action( 'admin_footer', array( $this, 'handleGetProSubMenu' ) );
702 }
703 remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
704
705 add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
706 }
707
708 /**
709 * Handle get pro plugin submenu.
710 */
711 public function handleGetProSubMenu() {
712 ?>
713 <style type="text/css">
714 #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li {
715 background: #FF7E65;
716 font-size: 14px;
717 font-weight: 600;
718 color: #fff;
719 }
720 #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li > a {
721 color: #fff !important;
722 }
723 #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li > a:hover {
724 box-shadow: inherit;
725 }
726 #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li + li {
727 display: none;
728 }
729 </style>
730 <script type="text/javascript">
731 jQuery( document ).ready( function() {
732 jQuery( '#toplevel_page_visualizer' ).on( 'click', 'li:not(.wp-submenu-head, .wp-first-item):eq(2)', function( e ) {
733 e.preventDefault();
734 window.open( '<?php echo tsdk_utmify( 'https://themeisle.com/plugins/visualizer-charts-and-graphs/upgrade/', 'toplevel' ); ?>', '_blank' );
735 } );
736 } );
737 </script>
738 <?php
739 }
740
741 /**
742 * Adds the screen options for pagination.
743 */
744 function addScreenOptions() {
745 $screen = get_current_screen();
746
747 // bail if it's some other page.
748 if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
749 return;
750 }
751
752 $args = array(
753 'label' => __( 'Number of charts per page:', 'visualizer' ),
754 'default' => 6,
755 'option' => 'visualizer_library_per_page',
756 );
757 add_screen_option( 'per_page', $args );
758 }
759
760 /**
761 * Returns the screen option for pagination.
762 */
763 function setScreenOptions( $status, $option, $value ) {
764 if ( 'visualizer_library_per_page' === $option ) {
765 return $value;
766 }
767 }
768
769 /**
770 * Adds the display filters to be used in the meta_query while displaying the charts.
771 */
772 private function getDisplayFilters( &$query_args ) {
773 $query = array();
774 global $sitepress;
775 if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
776 $current_lang = icl_get_current_language();
777 if ( in_array( $current_lang, array( 'all', icl_get_default_language() ), true ) ) {
778 $query[] = array(
779 'key' => 'chart_lang',
780 'compare' => 'NOT EXISTS',
781 );
782 } else {
783 $query[] = array(
784 'key' => 'chart_lang',
785 'value' => $current_lang,
786 'compare' => '=',
787 );
788 }
789 }
790
791 // add chart type filter to the query arguments
792 $type = filter_input( INPUT_GET, 'type' );
793 if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
794 $query[] = array(
795 'key' => Visualizer_Plugin::CF_CHART_TYPE,
796 'value' => $type,
797 'compare' => '=',
798 );
799 }
800
801 // add chart library filter to the query arguments
802 $library = filter_input( INPUT_GET, 'library' );
803 if ( $library ) {
804 $query[] = array(
805 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
806 'value' => $library,
807 'compare' => '=',
808 );
809 }
810
811 // add date filter to the query arguments
812 $date = filter_input( INPUT_GET, 'date' );
813 $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
814 if ( $date && in_array( $date, $possible, true ) ) {
815 $query_args['date_query'] = array(
816 'after' => "$date -1 day",
817 'inclusive' => true,
818 );
819 }
820
821 // add source filter to the query arguments
822 $source = filter_input( INPUT_GET, 'source' );
823 if ( $source ) {
824 $source = ucwords( $source );
825 $source = "Visualizer_Source_{$source}";
826 $query[] = array(
827 'key' => Visualizer_Plugin::CF_SOURCE,
828 'value' => $source,
829 'compare' => '=',
830 );
831 }
832
833 $query_args['meta_query'] = $query;
834
835 $orderby = filter_input( INPUT_GET, 'orderby' );
836 $order = filter_input( INPUT_GET, 'order' );
837 if ( $orderby ) {
838 $query_args['order_by'] = $orderby;
839 }
840 $query_args['order'] = empty( $order ) ? 'desc' : $order;
841 }
842
843 /**
844 * Get the instance of WP_Query that fetches the charts as per the given criteria.
845 */
846 private function getQuery() {
847 static $q;
848 if ( ! is_null( $q ) ) {
849 return $q;
850 }
851
852 // get current page
853 $page = filter_input(
854 INPUT_GET,
855 'vpage',
856 FILTER_VALIDATE_INT,
857 array(
858 'options' => array(
859 'min_range' => 1,
860 'default' => 1,
861 ),
862 )
863 );
864
865 $per_page = 6;
866 $screen = get_current_screen();
867 if ( $screen ) {
868 // retrieve the per_page option
869 $screen_option = $screen->get_option( 'per_page', 'option' );
870 // retrieve the value stored for the current user
871 $user = get_current_user_id();
872 $per_page = get_user_meta( $user, $screen_option, true );
873 if ( empty( $per_page ) || $per_page < 1 ) {
874 // nothing set, get the default value
875 $per_page = $screen->get_option( 'per_page', 'default' );
876 }
877 }
878
879 // the initial query arguments to fetch charts
880 $query_args = array(
881 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
882 'posts_per_page' => $per_page,
883 'paged' => $page,
884 );
885
886 $this->getDisplayFilters( $query_args );
887
888 // Added by Ash/Upwork
889 $filterByMeta = ! empty( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
890 if ( $filterByMeta ) {
891 $query = array(
892 'key' => Visualizer_Plugin::CF_SETTINGS,
893 'value' => $filterByMeta,
894 'compare' => 'LIKE',
895 );
896 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
897 $meta[] = $query;
898 $query_args['meta_query'] = $meta;
899 }
900 $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
901 return $q;
902 }
903
904 /**
905 * Renders support page.
906 *
907 * @since 3.3.0
908 *
909 * @access public
910 */
911 public function renderSupportPage() {
912 wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
913 include_once VISUALIZER_ABSPATH . '/templates/support.php';
914 }
915
916 /**
917 * Renders visualizer library page.
918 *
919 * @since 1.0.0
920 *
921 * @access public
922 */
923 public function renderLibraryPage() {
924 $charts = array();
925 $query = $this->getQuery();
926
927 // get current page
928 $page = filter_input(
929 INPUT_GET,
930 'vpage',
931 FILTER_VALIDATE_INT,
932 array(
933 'options' => array(
934 'min_range' => 1,
935 'default' => 1,
936 ),
937 )
938 );
939 // add chart type filter to the query arguments
940 $filter = filter_input( INPUT_GET, 'type' );
941 if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
942 $filter = 'all';
943 }
944
945 $css = '';
946 while ( $query->have_posts() ) {
947 $chart = $query->next_post();
948
949 // if the user has updated a chart and instead of saving it, has closed the modal. If the user refreshes, they should get the original chart.
950 $chart = $this->handleExistingRevisions( $chart->ID, $chart );
951 // refresh a "live" db query chart.
952 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
953
954 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
955
956 // fetch and update settings
957 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
958
959 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
960 if ( ! empty( $atts['settings'] ) ) {
961 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
962 }
963
964 if ( $settings ) {
965 unset( $settings['height'], $settings['width'], $settings['chartArea'] );
966 }
967
968 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
969 $data = self::get_chart_data( $chart, $type );
970
971 // Set default setting series when add manual chart data - Only during first creation.
972 if ( isset( $settings['series'] ) && ! empty( $series ) ) {
973 $count_series = count( $series ) - count( $settings['series'] );
974 if ( $count_series > 1 ) {
975 $clone_last_series = end( $settings['series'] );
976 $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
977 foreach ( range( 1, $count_series ) as $item ) {
978 $settings['series'][] = $clone_last_series;
979 }
980 }
981 }
982
983 $library = $this->load_chart_type( $chart->ID );
984
985 $id = 'visualizer-' . $chart->ID;
986 $arguments = $this->get_inline_custom_css( $id, $settings );
987 if ( ! empty( $arguments ) ) {
988 $css .= $arguments[0];
989 $settings = $arguments[1];
990 }
991
992 if ( isset( $settings['controls']['ui']['labelStacking'] ) ) {
993 unset( $settings['controls']['ui']['labelStacking'] );
994 }
995 if ( isset( $settings['controls']['ui']['orientation'] ) ) {
996 unset( $settings['controls']['ui']['orientation'] );
997 }
998
999 // add chart to the array
1000 $charts[ $id ] = array(
1001 'id' => $chart->ID,
1002 'type' => $type,
1003 'series' => $series,
1004 'settings' => $settings,
1005 'data' => $data,
1006 'library' => $library,
1007 );
1008 }
1009 // enqueue charts array
1010 $ajaxurl = admin_url( 'admin-ajax.php' );
1011 wp_localize_script(
1012 'visualizer-library',
1013 'visualizer',
1014 array(
1015 'language' => $this->get_language(),
1016 'map_api_key' => get_option( 'visualizer-map-api-key' ),
1017 'charts' => $charts,
1018 'urls' => array(
1019 'base' => esc_url( add_query_arg( array( 'vpage' => false, 'vaction' => false ) ) ),
1020 'create' => esc_url(
1021 add_query_arg(
1022 array(
1023 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
1024 'library' => 'yes',
1025 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
1026 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
1027 'vaction' => false,
1028 ),
1029 $ajaxurl
1030 )
1031 ),
1032 'edit' => esc_url(
1033 add_query_arg(
1034 array(
1035 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
1036 'library' => 'yes',
1037 'vaction' => false,
1038 ),
1039 $ajaxurl
1040 )
1041 ),
1042 ),
1043 'page_type' => 'library',
1044 'is_front' => false,
1045 'i10n' => array(
1046 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
1047 'conflict' => __( 'We have detected a potential conflict with another component that prevents Visualizer from functioning properly. Please disable any of the following components if they are activated on your instance: Modern Events Calendar plugin, Acronix plugin. In case the aforementioned components are not activated or you continue to see this error message, please disable all other plugins and enable them one by one to find out the component that is causing the conflict.', 'visualizer' ),
1048 ),
1049 )
1050 );
1051 // render library page
1052 $render = new Visualizer_Render_Library();
1053 $render->charts = $charts;
1054 $render->type = $filter;
1055 $render->types = self::_getChartTypesLocalized( false, false, false, true );
1056 $render->custom_css = $css;
1057 $render->pagination = paginate_links(
1058 array(
1059 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
1060 'format' => '',
1061 'current' => $page,
1062 'total' => $query->max_num_pages,
1063 'type' => 'array',
1064 )
1065 );
1066 $render->render();
1067 }
1068
1069 /**
1070 * Updates the plugin's action links, which will be rendered at the plugins table.
1071 *
1072 * @since 1.0.0
1073 *
1074 * @access public
1075 *
1076 * @param array $links The array of original action links.
1077 * @param string $file The plugin basename.
1078 *
1079 * @return array Updated array of action links.
1080 */
1081 public function getPluginActionLinks( $links, $file ) {
1082 if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
1083 array_unshift(
1084 $links,
1085 sprintf(
1086 '<a href="%s">%s</a>',
1087 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
1088 esc_html__( 'Library', 'visualizer' )
1089 )
1090 );
1091 }
1092
1093 return $links;
1094 }
1095
1096 /**
1097 * Updates the plugin's meta links, which will be rendered at the plugins table.
1098 *
1099 * @since 1.0.0
1100 *
1101 * @access public
1102 *
1103 * @param array $plugin_meta The array of a plugin meta links.
1104 * @param string $plugin_file The plugin's basename.
1105 *
1106 * @return array Updated array of plugin meta links.
1107 */
1108 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
1109 if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
1110 // knowledge base link
1111 $plugin_meta[] = sprintf(
1112 '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1113 esc_html__( 'Docs', 'visualizer' )
1114 );
1115 // flattr link
1116 $plugin_meta[] = sprintf(
1117 '<a style="color:red" href="' . tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'pluginrow' ) . '" target="_blank">%s</a>',
1118 esc_html__( 'Pro Addon', 'visualizer' )
1119 );
1120 }
1121
1122 return $plugin_meta;
1123 }
1124
1125 /**
1126 * If check is existing user.
1127 *
1128 * @return bool Default false
1129 */
1130 public static function proFeaturesLocked() {
1131 if ( Visualizer_Module::is_pro() ) {
1132 return true;
1133 }
1134 return 'yes' === get_option( 'visualizer-new-user', 'yes' ) ? false : true;
1135 }
1136
1137 /**
1138 * Multilingual Support.
1139 *
1140 * @param int $chart_id Chart ID.
1141 * @return bool Default false
1142 */
1143 public function addMultilingualSupport( $chart_id ) {
1144 global $sitepress;
1145 if ( Visualizer_Module::is_pro() ) {
1146 return;
1147 }
1148 if ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) {
1149 $language = icl_get_languages();
1150 $current_lang = icl_get_current_language();
1151 $default_lang = icl_get_default_language();
1152 $post_info = wpml_get_language_information( null, $chart_id );
1153 $translations = array();
1154 if ( ! empty( $post_info ) && ( $default_lang === $post_info['language_code'] ) ) {
1155 $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
1156 $translations = $sitepress->get_element_translations( $trid );
1157 }
1158 if ( empty( $translations ) ) {
1159 return;
1160 }
1161 ?>
1162 <hr><div class="visualizer-languages-list only-pro">
1163 <?php
1164 foreach ( $language as $lang ) {
1165 $lang_code = $lang['code'];
1166 if ( $current_lang !== $lang_code ) {
1167 ?>
1168 <a href="javascript:;">
1169 <img src="<?php echo esc_url( $lang['country_flag_url'] ); ?>" alt="<?php echo esc_attr( $lang['translated_name'] ); ?>">
1170 </a>
1171 <?php
1172 }
1173 }
1174 ?>
1175 <a href="<?php echo tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'wpml-support', 'visualizer_render_char' ); ?>"target="_blank"><?php esc_html_e( 'Upgrade to PRO to active this translation for charts', 'visualizer' ); ?></a>
1176 </div>
1177 <?php
1178 }
1179 }
1180
1181 /**
1182 * Check chart is enabled or not.
1183 *
1184 * @param string $type Chart ID.
1185 *
1186 * @return bool Default false
1187 */
1188 public static function checkChartStatus( $type ) {
1189 $types = self::_getChartTypesLocalized( false, false, false, true );
1190 if ( isset( $types[ $type ] ) ) {
1191 return ! empty( $types[ $type ]['enabled'] );
1192 }
1193 return false;
1194 }
1195 }
1196