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

1,039 lines 33.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, 8 );
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' => 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 $types = array_merge(
393 $additional,
394 array(
395 'tabular' => array(
396 'name' => esc_html__( 'Table', 'visualizer' ),
397 'enabled' => true,
398 'supports' => array( 'Google Charts', 'DataTable' ),
399 ),
400 'pie' => array(
401 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
402 'enabled' => true,
403 'supports' => array( 'Google Charts', 'ChartJS' ),
404 ),
405 'line' => array(
406 'name' => esc_html__( 'Line', 'visualizer' ),
407 'enabled' => true,
408 'supports' => array( 'Google Charts', 'ChartJS' ),
409 ),
410 'area' => array(
411 'name' => esc_html__( 'Area', 'visualizer' ),
412 'enabled' => true,
413 // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
414 'supports' => array( 'Google Charts' ),
415 ),
416 'geo' => array(
417 'name' => esc_html__( 'Geo', 'visualizer' ),
418 'enabled' => true,
419 'supports' => array( 'Google Charts' ),
420 ),
421 'bar' => array(
422 'name' => esc_html__( 'Bar', 'visualizer' ),
423 'enabled' => true,
424 'supports' => array( 'Google Charts', 'ChartJS' ),
425 ),
426 'column' => array(
427 'name' => esc_html__( 'Column', 'visualizer' ),
428 'enabled' => true,
429 'supports' => array( 'Google Charts', 'ChartJS' ),
430 ),
431 'bubble' => array(
432 'name' => esc_html__( 'Bubble', 'visualizer' ),
433 'enabled' => true,
434 // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
435 'supports' => array( 'Google Charts' ),
436 ),
437 'scatter' => array(
438 'name' => esc_html__( 'Scatter', 'visualizer' ),
439 'enabled' => true,
440 'supports' => array( 'Google Charts' ),
441 ),
442 'gauge' => array(
443 'name' => esc_html__( 'Gauge', 'visualizer' ),
444 'enabled' => true,
445 'supports' => array( 'Google Charts' ),
446 ),
447 'candlestick' => array(
448 'name' => esc_html__( 'Candlestick', 'visualizer' ),
449 'enabled' => true,
450 'supports' => array( 'Google Charts' ),
451 ),
452 // pro types
453 'timeline' => array(
454 'name' => esc_html__( 'Timeline', 'visualizer' ),
455 'enabled' => false,
456 'supports' => array( 'Google Charts', 'ChartJS' ),
457 ),
458 'combo' => array(
459 'name' => esc_html__( 'Combo', 'visualizer' ),
460 'enabled' => false,
461 'supports' => array( 'Google Charts' ),
462 ),
463 'polarArea' => array(
464 'name' => esc_html__( 'Polar Area', 'visualizer' ),
465 'enabled' => false,
466 'supports' => array( 'ChartJS' ),
467 ),
468 'radar' => array(
469 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
470 'enabled' => false,
471 'supports' => array( 'ChartJS' ),
472 ),
473 )
474 );
475 $types = apply_filters( 'visualizer_pro_chart_types', $types );
476 if ( $enabledOnly ) {
477 $filtered = array();
478 foreach ( $types as $type => $array ) {
479 if ( ! is_array( $array ) ) {
480 // support for old pro
481 $array = array( 'enabled' => true, 'name' => $array );
482 }
483 // backward compatibility for PRO before v1.9.0
484 if ( ! array_key_exists( 'supports', $array ) ) {
485 $array['supports'] = array( 'Google Charts' );
486 }
487 if ( ! $array['enabled'] ) {
488 continue;
489 }
490 $filtered[ $type ] = $array;
491 }
492 $types = $filtered;
493 }
494 if ( $get2Darray ) {
495 $doubleD = array();
496 foreach ( $types as $type => $array ) {
497 if ( ! is_array( $array ) ) {
498 // support for old pro
499 $array = array( 'enabled' => true, 'name' => $array );
500 }
501 // backward compatibility for PRO before v1.9.0
502 if ( ! array_key_exists( 'supports', $array ) ) {
503 $array['supports'] = array( 'Google Charts' );
504 }
505 $doubleD[ $type ] = $array['name'];
506 }
507 $types = $doubleD;
508 }
509
510 return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
511 }
512
513 /**
514 * Handle (soon-to-be) deprecated charts.
515 */
516 private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
517 $deprecated = array();
518
519 switch ( $where ) {
520 case 'types':
521 // fall-through
522 case 'library':
523 // if a user has a Gauge/Candlestick chart, then let them keep using it.
524 if ( ! Visualizer_Module::is_pro() ) {
525 if ( ! self::hasChartType( 'gauge' ) ) {
526 if ( $get2Darray ) {
527 $deprecated[] = 'gauge';
528 } else {
529 $types['gauge']['enabled'] = false;
530 }
531 }
532 if ( ! self::hasChartType( 'candlestick' ) ) {
533 if ( $get2Darray ) {
534 $deprecated[] = 'candlestick';
535 } else {
536 $types['candlestick']['enabled'] = false;
537 }
538 }
539 }
540 break;
541 default:
542 // if a user has a Gauge/Candlestick chart, then let them keep using it.
543 if ( ! Visualizer_Module::is_pro() ) {
544 if ( ! self::hasChartType( 'gauge' ) ) {
545 if ( $get2Darray ) {
546 $deprecated[] = 'gauge';
547 } else {
548 $types['gauge']['enabled'] = false;
549 }
550 }
551 if ( ! self::hasChartType( 'candlestick' ) ) {
552 if ( $get2Darray ) {
553 $deprecated[] = 'candlestick';
554 } else {
555 $types['candlestick']['enabled'] = false;
556 }
557 }
558 }
559 }
560
561 if ( $deprecated ) {
562 foreach ( $deprecated as $type ) {
563 unset( $types[ $type ] );
564 }
565 }
566
567 return $types;
568 }
569
570 /**
571 * Renders templates to use in media popup.
572 *
573 * @since 1.0.0
574 * @global string $pagenow The name of the current page.
575 *
576 * @access public
577 */
578 public function renderTemplates() {
579 global $pagenow;
580 if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
581 return;
582 }
583 $render = new Visualizer_Render_Templates();
584 $render->render();
585 }
586
587 /**
588 * Enqueues library scripts and styles.
589 *
590 * @since 1.0.0
591 * @uses wp_enqueue_style() To enqueue library stylesheet.
592 * @uses wp_enqueue_script() To enqueue javascript file.
593 * @uses wp_enqueue_media() To enqueue media stuff.
594 *
595 * @access public
596 *
597 * @param string $suffix The current page suffix.
598 */
599 public function enqueueLibraryScripts( $suffix ) {
600 if ( $suffix === $this->_libraryPage ) {
601 wp_register_script( 'visualizer-clipboardjs', VISUALIZER_ABSURL . 'js/lib/clipboardjs/clipboard.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
602 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
603 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
604 wp_enqueue_media();
605 wp_enqueue_script(
606 'visualizer-library',
607 VISUALIZER_ABSURL . 'js/library.js',
608 array(
609 'jquery',
610 'media-views',
611 'visualizer-clipboardjs',
612 ),
613 Visualizer_Plugin::VERSION,
614 true
615 );
616
617 wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
618
619 $query = $this->getQuery();
620 while ( $query->have_posts() ) {
621 $chart = $query->next_post();
622 $library = $this->load_chart_type( $chart->ID );
623 if ( is_null( $library ) ) {
624 continue;
625 }
626 wp_enqueue_script(
627 "visualizer-render-$library",
628 VISUALIZER_ABSURL . 'js/render-facade.js',
629 apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
630 Visualizer_Plugin::VERSION,
631 true
632 );
633 }
634 }
635 }
636
637 /**
638 * Adds visualizer tab for media upload tabs array.
639 *
640 * @since 1.0.0
641 *
642 * @access public
643 *
644 * @param array $tabs The array of media upload tabs.
645 *
646 * @return array Extended array of media upload tabs.
647 */
648 public function setupVisualizerTab( $tabs ) {
649 $tabs['visualizer'] = 'Visualizer';
650
651 return $tabs;
652 }
653
654 /**
655 * Registers admin menu for visualizer library.
656 *
657 * @since 1.0.0
658 *
659 * @access public
660 */
661 public function registerAdminMenu() {
662 $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
663
664 $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
665
666 add_submenu_page(
667 Visualizer_Plugin::NAME,
668 __( 'Chart Library', 'visualizer' ),
669 __( 'Chart Library', 'visualizer' ),
670 'edit_posts',
671 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
672 );
673 add_submenu_page(
674 Visualizer_Plugin::NAME,
675 __( 'Add New Chart', 'visualizer' ),
676 __( 'Add New Chart', 'visualizer' ),
677 'edit_posts',
678 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
679 );
680 add_submenu_page(
681 Visualizer_Plugin::NAME,
682 __( 'Support', 'visualizer' ),
683 __( '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>',
684 'edit_posts',
685 'viz-support',
686 array( $this, 'renderSupportPage' )
687 );
688 remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
689
690 add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
691 }
692
693 /**
694 * Adds the screen options for pagination.
695 */
696 function addScreenOptions() {
697 $screen = get_current_screen();
698
699 // bail if it's some other page.
700 if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
701 return;
702 }
703
704 $args = array(
705 'label' => __( 'Number of charts per page:', 'visualizer' ),
706 'default' => 6,
707 'option' => 'visualizer_per_page_library',
708 );
709 add_screen_option( 'per_page', $args );
710 }
711
712 /**
713 * Returns the screen option for pagination.
714 */
715 function setScreenOptions( $status, $option, $value ) {
716 if ( 'visualizer_per_page_library' === $option ) {
717 return $value;
718 }
719 }
720
721 /**
722 * Adds the display filters to be used in the meta_query while displaying the charts.
723 */
724 private function getDisplayFilters( &$query_args ) {
725 $query = array();
726
727 // add chart type filter to the query arguments
728 $type = filter_input( INPUT_GET, 'type' );
729 if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
730 $query[] = array(
731 'key' => Visualizer_Plugin::CF_CHART_TYPE,
732 'value' => $type,
733 'compare' => '=',
734 );
735 }
736
737 // add chart library filter to the query arguments
738 $library = filter_input( INPUT_GET, 'library' );
739 if ( $library ) {
740 $query[] = array(
741 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
742 'value' => $library,
743 'compare' => '=',
744 );
745 }
746
747 // add date filter to the query arguments
748 $date = filter_input( INPUT_GET, 'date' );
749 $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
750 if ( $date && in_array( $date, $possible, true ) ) {
751 $query_args['date_query'] = array(
752 'after' => "$date -1 day",
753 'inclusive' => true,
754 );
755 }
756
757 // add source filter to the query arguments
758 $source = filter_input( INPUT_GET, 'source' );
759 if ( $source ) {
760 $source = ucwords( $source );
761 $source = "Visualizer_Source_{$source}";
762 $query[] = array(
763 'key' => Visualizer_Plugin::CF_SOURCE,
764 'value' => $source,
765 'compare' => '=',
766 );
767 }
768
769 $query_args['meta_query'] = $query;
770
771 $orderby = filter_input( INPUT_GET, 'orderby' );
772 $order = filter_input( INPUT_GET, 'order' );
773 if ( $orderby ) {
774 $query_args['order_by'] = $orderby;
775 }
776 $query_args['order'] = empty( $order ) ? 'desc' : $order;
777 }
778
779 /**
780 * Get the instance of WP_Query that fetches the charts as per the given criteria.
781 */
782 private function getQuery() {
783 static $q;
784 if ( ! is_null( $q ) ) {
785 return $q;
786 }
787
788 // get current page
789 $page = filter_input(
790 INPUT_GET,
791 'vpage',
792 FILTER_VALIDATE_INT,
793 array(
794 'options' => array(
795 'min_range' => 1,
796 'default' => 1,
797 ),
798 )
799 );
800
801 $per_page = 6;
802 $screen = get_current_screen();
803 if ( $screen ) {
804 // retrieve the per_page option
805 $screen_option = $screen->get_option( 'per_page', 'option' );
806 // retrieve the value stored for the current user
807 $user = get_current_user_id();
808 $per_page = get_user_meta( $user, $screen_option, true );
809 if ( empty( $per_page ) || $per_page < 1 ) {
810 // nothing set, get the default value
811 $per_page = $screen->get_option( 'per_page', 'default' );
812 }
813 }
814
815 // the initial query arguments to fetch charts
816 $query_args = array(
817 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
818 'posts_per_page' => $per_page,
819 'paged' => $page,
820 );
821
822 $this->getDisplayFilters( $query_args );
823
824 // Added by Ash/Upwork
825 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
826 if ( $filterByMeta ) {
827 $query = array(
828 'key' => Visualizer_Plugin::CF_SETTINGS,
829 'value' => $filterByMeta,
830 'compare' => 'LIKE',
831 );
832 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
833 $meta[] = $query;
834 $query_args['meta_query'] = $meta;
835 }
836 $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
837 return $q;
838 }
839
840 /**
841 * Renders support page.
842 *
843 * @since 3.3.0
844 *
845 * @access public
846 */
847 public function renderSupportPage() {
848 wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
849 include_once VISUALIZER_ABSPATH . '/templates/support.php';
850 }
851
852 /**
853 * Renders visualizer library page.
854 *
855 * @since 1.0.0
856 *
857 * @access public
858 */
859 public function renderLibraryPage() {
860 $charts = array();
861 $query = $this->getQuery();
862
863 // get current page
864 $page = filter_input(
865 INPUT_GET,
866 'vpage',
867 FILTER_VALIDATE_INT,
868 array(
869 'options' => array(
870 'min_range' => 1,
871 'default' => 1,
872 ),
873 )
874 );
875 // add chart type filter to the query arguments
876 $filter = filter_input( INPUT_GET, 'type' );
877 if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
878 $filter = 'all';
879 }
880
881 $css = '';
882 while ( $query->have_posts() ) {
883 $chart = $query->next_post();
884
885 // 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.
886 $chart = $this->handleExistingRevisions( $chart->ID, $chart );
887 // refresh a "live" db query chart.
888 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
889
890 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
891
892 // fetch and update settings
893 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
894
895 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
896 if ( ! empty( $atts['settings'] ) ) {
897 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
898 }
899
900 if ( $settings ) {
901 unset( $settings['height'], $settings['width'], $settings['chartArea'] );
902 }
903
904 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
905 $data = self::get_chart_data( $chart, $type );
906
907 $library = $this->load_chart_type( $chart->ID );
908
909 $id = 'visualizer-' . $chart->ID;
910 $arguments = $this->get_inline_custom_css( $id, $settings );
911 if ( ! empty( $arguments ) ) {
912 $css .= $arguments[0];
913 $settings = $arguments[1];
914 }
915
916 // add chart to the array
917 $charts[ $id ] = array(
918 'id' => $chart->ID,
919 'type' => $type,
920 'series' => $series,
921 'settings' => $settings,
922 'data' => $data,
923 'library' => $library,
924 );
925 }
926 // enqueue charts array
927 $ajaxurl = admin_url( 'admin-ajax.php' );
928 wp_localize_script(
929 'visualizer-library',
930 'visualizer',
931 array(
932 'language' => $this->get_language(),
933 'map_api_key' => get_option( 'visualizer-map-api-key' ),
934 'charts' => $charts,
935 'urls' => array(
936 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
937 'create' => add_query_arg(
938 array(
939 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
940 'library' => 'yes',
941 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
942 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
943 'vaction' => false,
944 ),
945 $ajaxurl
946 ),
947 'edit' => add_query_arg(
948 array(
949 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
950 'library' => 'yes',
951 'vaction' => false,
952 ),
953 $ajaxurl
954 ),
955 ),
956 'page_type' => 'library',
957 'is_front' => false,
958 'i10n' => array(
959 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
960 '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' ),
961 ),
962 )
963 );
964 // render library page
965 $render = new Visualizer_Render_Library();
966 $render->charts = $charts;
967 $render->type = $filter;
968 $render->types = self::_getChartTypesLocalized( false, false, false, true );
969 $render->custom_css = $css;
970 $render->pagination = paginate_links(
971 array(
972 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
973 'format' => '',
974 'current' => $page,
975 'total' => $query->max_num_pages,
976 'type' => 'array',
977 )
978 );
979 $render->render();
980 }
981
982 /**
983 * Updates the plugin's action links, which will be rendered at the plugins table.
984 *
985 * @since 1.0.0
986 *
987 * @access public
988 *
989 * @param array $links The array of original action links.
990 * @param string $file The plugin basename.
991 *
992 * @return array Updated array of action links.
993 */
994 public function getPluginActionLinks( $links, $file ) {
995 if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
996 array_unshift(
997 $links,
998 sprintf(
999 '<a href="%s">%s</a>',
1000 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
1001 esc_html__( 'Library', 'visualizer' )
1002 )
1003 );
1004 }
1005
1006 return $links;
1007 }
1008
1009 /**
1010 * Updates the plugin's meta links, which will be rendered at the plugins table.
1011 *
1012 * @since 1.0.0
1013 *
1014 * @access public
1015 *
1016 * @param array $plugin_meta The array of a plugin meta links.
1017 * @param string $plugin_file The plugin's basename.
1018 *
1019 * @return array Updated array of plugin meta links.
1020 */
1021 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
1022 if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
1023 // knowledge base link
1024 $plugin_meta[] = sprintf(
1025 '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1026 esc_html__( 'Docs', 'visualizer' )
1027 );
1028 // flattr link
1029 $plugin_meta[] = sprintf(
1030 '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
1031 esc_html__( 'Pro Addon', 'visualizer' )
1032 );
1033 }
1034
1035 return $plugin_meta;
1036 }
1037
1038 }
1039