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

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