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

1,038 lines 33.2 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_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
602 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
603 wp_enqueue_media();
604 wp_enqueue_script(
605 'visualizer-library',
606 VISUALIZER_ABSURL . 'js/library.js',
607 array(
608 'jquery',
609 'media-views',
610 'clipboard',
611 ),
612 Visualizer_Plugin::VERSION,
613 true
614 );
615
616 wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
617
618 $query = $this->getQuery();
619 while ( $query->have_posts() ) {
620 $chart = $query->next_post();
621 $library = $this->load_chart_type( $chart->ID );
622 if ( is_null( $library ) ) {
623 continue;
624 }
625 wp_enqueue_script(
626 "visualizer-render-$library",
627 VISUALIZER_ABSURL . 'js/render-facade.js',
628 apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
629 Visualizer_Plugin::VERSION,
630 true
631 );
632 }
633 }
634 }
635
636 /**
637 * Adds visualizer tab for media upload tabs array.
638 *
639 * @since 1.0.0
640 *
641 * @access public
642 *
643 * @param array $tabs The array of media upload tabs.
644 *
645 * @return array Extended array of media upload tabs.
646 */
647 public function setupVisualizerTab( $tabs ) {
648 $tabs['visualizer'] = 'Visualizer';
649
650 return $tabs;
651 }
652
653 /**
654 * Registers admin menu for visualizer library.
655 *
656 * @since 1.0.0
657 *
658 * @access public
659 */
660 public function registerAdminMenu() {
661 $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
662
663 $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
664
665 add_submenu_page(
666 Visualizer_Plugin::NAME,
667 __( 'Chart Library', 'visualizer' ),
668 __( 'Chart Library', 'visualizer' ),
669 'edit_posts',
670 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
671 );
672 add_submenu_page(
673 Visualizer_Plugin::NAME,
674 __( 'Add New Chart', 'visualizer' ),
675 __( 'Add New Chart', 'visualizer' ),
676 'edit_posts',
677 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
678 );
679 add_submenu_page(
680 Visualizer_Plugin::NAME,
681 __( 'Support', 'visualizer' ),
682 __( '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>',
683 'edit_posts',
684 'viz-support',
685 array( $this, 'renderSupportPage' )
686 );
687 remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
688
689 add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
690 }
691
692 /**
693 * Adds the screen options for pagination.
694 */
695 function addScreenOptions() {
696 $screen = get_current_screen();
697
698 // bail if it's some other page.
699 if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
700 return;
701 }
702
703 $args = array(
704 'label' => __( 'Number of charts per page:', 'visualizer' ),
705 'default' => 6,
706 'option' => 'visualizer_per_page_library',
707 );
708 add_screen_option( 'per_page', $args );
709 }
710
711 /**
712 * Returns the screen option for pagination.
713 */
714 function setScreenOptions( $status, $option, $value ) {
715 if ( 'visualizer_per_page_library' === $option ) {
716 return $value;
717 }
718 }
719
720 /**
721 * Adds the display filters to be used in the meta_query while displaying the charts.
722 */
723 private function getDisplayFilters( &$query_args ) {
724 $query = array();
725
726 // add chart type filter to the query arguments
727 $type = filter_input( INPUT_GET, 'type' );
728 if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
729 $query[] = array(
730 'key' => Visualizer_Plugin::CF_CHART_TYPE,
731 'value' => $type,
732 'compare' => '=',
733 );
734 }
735
736 // add chart library filter to the query arguments
737 $library = filter_input( INPUT_GET, 'library' );
738 if ( $library ) {
739 $query[] = array(
740 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
741 'value' => $library,
742 'compare' => '=',
743 );
744 }
745
746 // add date filter to the query arguments
747 $date = filter_input( INPUT_GET, 'date' );
748 $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
749 if ( $date && in_array( $date, $possible, true ) ) {
750 $query_args['date_query'] = array(
751 'after' => "$date -1 day",
752 'inclusive' => true,
753 );
754 }
755
756 // add source filter to the query arguments
757 $source = filter_input( INPUT_GET, 'source' );
758 if ( $source ) {
759 $source = ucwords( $source );
760 $source = "Visualizer_Source_{$source}";
761 $query[] = array(
762 'key' => Visualizer_Plugin::CF_SOURCE,
763 'value' => $source,
764 'compare' => '=',
765 );
766 }
767
768 $query_args['meta_query'] = $query;
769
770 $orderby = filter_input( INPUT_GET, 'orderby' );
771 $order = filter_input( INPUT_GET, 'order' );
772 if ( $orderby ) {
773 $query_args['order_by'] = $orderby;
774 }
775 $query_args['order'] = empty( $order ) ? 'desc' : $order;
776 }
777
778 /**
779 * Get the instance of WP_Query that fetches the charts as per the given criteria.
780 */
781 private function getQuery() {
782 static $q;
783 if ( ! is_null( $q ) ) {
784 return $q;
785 }
786
787 // get current page
788 $page = filter_input(
789 INPUT_GET,
790 'vpage',
791 FILTER_VALIDATE_INT,
792 array(
793 'options' => array(
794 'min_range' => 1,
795 'default' => 1,
796 ),
797 )
798 );
799
800 $per_page = 6;
801 $screen = get_current_screen();
802 if ( $screen ) {
803 // retrieve the per_page option
804 $screen_option = $screen->get_option( 'per_page', 'option' );
805 // retrieve the value stored for the current user
806 $user = get_current_user_id();
807 $per_page = get_user_meta( $user, $screen_option, true );
808 if ( empty( $per_page ) || $per_page < 1 ) {
809 // nothing set, get the default value
810 $per_page = $screen->get_option( 'per_page', 'default' );
811 }
812 }
813
814 // the initial query arguments to fetch charts
815 $query_args = array(
816 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
817 'posts_per_page' => $per_page,
818 'paged' => $page,
819 );
820
821 $this->getDisplayFilters( $query_args );
822
823 // Added by Ash/Upwork
824 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
825 if ( $filterByMeta ) {
826 $query = array(
827 'key' => Visualizer_Plugin::CF_SETTINGS,
828 'value' => $filterByMeta,
829 'compare' => 'LIKE',
830 );
831 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
832 $meta[] = $query;
833 $query_args['meta_query'] = $meta;
834 }
835 $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
836 return $q;
837 }
838
839 /**
840 * Renders support page.
841 *
842 * @since 3.3.0
843 *
844 * @access public
845 */
846 public function renderSupportPage() {
847 wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
848 include_once VISUALIZER_ABSPATH . '/templates/support.php';
849 }
850
851 /**
852 * Renders visualizer library page.
853 *
854 * @since 1.0.0
855 *
856 * @access public
857 */
858 public function renderLibraryPage() {
859 $charts = array();
860 $query = $this->getQuery();
861
862 // get current page
863 $page = filter_input(
864 INPUT_GET,
865 'vpage',
866 FILTER_VALIDATE_INT,
867 array(
868 'options' => array(
869 'min_range' => 1,
870 'default' => 1,
871 ),
872 )
873 );
874 // add chart type filter to the query arguments
875 $filter = filter_input( INPUT_GET, 'type' );
876 if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
877 $filter = 'all';
878 }
879
880 $css = '';
881 while ( $query->have_posts() ) {
882 $chart = $query->next_post();
883
884 // 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.
885 $chart = $this->handleExistingRevisions( $chart->ID, $chart );
886 // refresh a "live" db query chart.
887 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
888
889 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
890
891 // fetch and update settings
892 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
893
894 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
895 if ( ! empty( $atts['settings'] ) ) {
896 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
897 }
898
899 if ( $settings ) {
900 unset( $settings['height'], $settings['width'], $settings['chartArea'] );
901 }
902
903 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
904 $data = self::get_chart_data( $chart, $type );
905
906 $library = $this->load_chart_type( $chart->ID );
907
908 $id = 'visualizer-' . $chart->ID;
909 $arguments = $this->get_inline_custom_css( $id, $settings );
910 if ( ! empty( $arguments ) ) {
911 $css .= $arguments[0];
912 $settings = $arguments[1];
913 }
914
915 // add chart to the array
916 $charts[ $id ] = array(
917 'id' => $chart->ID,
918 'type' => $type,
919 'series' => $series,
920 'settings' => $settings,
921 'data' => $data,
922 'library' => $library,
923 );
924 }
925 // enqueue charts array
926 $ajaxurl = admin_url( 'admin-ajax.php' );
927 wp_localize_script(
928 'visualizer-library',
929 'visualizer',
930 array(
931 'language' => $this->get_language(),
932 'map_api_key' => get_option( 'visualizer-map-api-key' ),
933 'charts' => $charts,
934 'urls' => array(
935 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
936 'create' => add_query_arg(
937 array(
938 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
939 'library' => 'yes',
940 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
941 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
942 'vaction' => false,
943 ),
944 $ajaxurl
945 ),
946 'edit' => add_query_arg(
947 array(
948 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
949 'library' => 'yes',
950 'vaction' => false,
951 ),
952 $ajaxurl
953 ),
954 ),
955 'page_type' => 'library',
956 'is_front' => false,
957 'i10n' => array(
958 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
959 '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' ),
960 ),
961 )
962 );
963 // render library page
964 $render = new Visualizer_Render_Library();
965 $render->charts = $charts;
966 $render->type = $filter;
967 $render->types = self::_getChartTypesLocalized( false, false, false, true );
968 $render->custom_css = $css;
969 $render->pagination = paginate_links(
970 array(
971 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
972 'format' => '',
973 'current' => $page,
974 'total' => $query->max_num_pages,
975 'type' => 'array',
976 )
977 );
978 $render->render();
979 }
980
981 /**
982 * Updates the plugin's action links, which will be rendered at the plugins table.
983 *
984 * @since 1.0.0
985 *
986 * @access public
987 *
988 * @param array $links The array of original action links.
989 * @param string $file The plugin basename.
990 *
991 * @return array Updated array of action links.
992 */
993 public function getPluginActionLinks( $links, $file ) {
994 if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
995 array_unshift(
996 $links,
997 sprintf(
998 '<a href="%s">%s</a>',
999 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
1000 esc_html__( 'Library', 'visualizer' )
1001 )
1002 );
1003 }
1004
1005 return $links;
1006 }
1007
1008 /**
1009 * Updates the plugin's meta links, which will be rendered at the plugins table.
1010 *
1011 * @since 1.0.0
1012 *
1013 * @access public
1014 *
1015 * @param array $plugin_meta The array of a plugin meta links.
1016 * @param string $plugin_file The plugin's basename.
1017 *
1018 * @return array Updated array of plugin meta links.
1019 */
1020 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
1021 if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
1022 // knowledge base link
1023 $plugin_meta[] = sprintf(
1024 '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1025 esc_html__( 'Docs', 'visualizer' )
1026 );
1027 // flattr link
1028 $plugin_meta[] = sprintf(
1029 '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
1030 esc_html__( 'Pro Addon', 'visualizer' )
1031 );
1032 }
1033
1034 return $plugin_meta;
1035 }
1036
1037 }
1038