PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.1
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Module / Admin.php

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

943 lines 30.5 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_get_chart_counts', 'getChartCountsByTypeAndMeta' );
64 $this->_addFilter( 'visualizer_feedback_review_trigger', 'feedbackReviewTrigger' );
65
66 // revision support.
67 $this->_addFilter( 'wp_revisions_to_keep', 'limitRevisions', null, 10, 2 );
68 $this->_addAction( '_wp_put_post_revision', 'addRevision', null, 10, 1 );
69 $this->_addAction( 'wp_restore_post_revision', 'restoreRevision', null, 10, 2 );
70
71 $this->_addAction( 'visualizer_chart_schedules_spl', 'addSplChartSchedules', null, 10, 3 );
72
73 $this->_addAction( 'admin_init', 'init' );
74 }
75
76
77 /**
78 * Add disabled `optgroup` schedules to the drop downs.
79 *
80 * @since ?
81 *
82 * @access public
83 *
84 * @param string $feature The feature for which to add schedules.
85 * @param int $chart_id The chart ID.
86 * @param int $plan The plan number.
87 */
88 public function addSplChartSchedules( $feature, $chart_id, $plan ) {
89 if ( apply_filters( 'visualizer_is_business', false ) ) {
90 return;
91 }
92
93 $license = __( 'PRO', 'visualizer' );
94 if ( Visualizer_Module::is_pro() ) {
95 switch ( $plan ) {
96 case 1:
97 $license = __( 'Developer', 'visualizer' );
98 break;
99 }
100 }
101
102 $hours = array(
103 '0' => __( 'Live', 'visualizer' ),
104 '1' => __( 'Each hour', 'visualizer' ),
105 '12' => __( 'Each 12 hours', 'visualizer' ),
106 '24' => __( 'Each day', 'visualizer' ),
107 '72' => __( 'Each 3 days', 'visualizer' ),
108 );
109
110 switch ( $feature ) {
111 case 'json':
112 case 'csv':
113 // no more schedules if pro is already active.
114 if ( Visualizer_Module::is_pro() ) {
115 return;
116 }
117 break;
118 case 'wp':
119 // fall-through.
120 case 'db':
121 break;
122 default:
123 return;
124 }
125
126 echo '<optgroup disabled label="' . sprintf( __( 'More in the %s version', 'visualizer' ), $license ) . '">';
127 foreach ( $hours as $hour => $desc ) {
128 echo '<option disabled>' . $desc . '</option>';
129 }
130 echo '</optgroup>';
131 }
132
133 /**
134 * No limits on revisions.
135 */
136 public function limitRevisions( $num, $post ) {
137 if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
138 return -1;
139 }
140 return $num;
141 }
142
143 /**
144 * Add a revision.
145 */
146 public function addRevision( $revision_id ) {
147 $parent_id = wp_is_post_revision( $revision_id );
148 if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $parent_id ) ) {
149 // add the meta data to this revision.
150 $meta = get_post_meta( $parent_id, '', true );
151
152 if ( $meta ) {
153 foreach ( $meta as $key => $value ) {
154 if ( 0 === strpos( $key, 'visualizer' ) ) {
155 add_metadata( 'post', $revision_id, $key, maybe_unserialize( $value[0] ) );
156 }
157 }
158 }
159 }
160 }
161
162 /**
163 * Restore a revision.
164 */
165 public function restoreRevision( $post_id, $revision_id ) {
166 if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $post_id ) ) {
167 // get the meta information from the revision.
168 $meta = get_metadata( 'post', $revision_id, '', true );
169
170 // delete all meta information from the post before adding.
171 $post_meta = get_post_meta( $post_id, '', true );
172 if ( $post_meta ) {
173 foreach ( $meta as $key => $value ) {
174 if ( 0 === strpos( $key, 'visualizer' ) ) {
175 delete_post_meta( $post_id, $key );
176 }
177 }
178 }
179
180 if ( $meta ) {
181 foreach ( $meta as $key => $value ) {
182 if ( 0 === strpos( $key, 'visualizer' ) ) {
183 add_post_meta( $post_id, $key, maybe_unserialize( $value[0] ) );
184 }
185 }
186 }
187 }
188 }
189
190 /**
191 * Admin init.
192 *
193 * @access public
194 */
195 public function init() {
196 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
197 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
198 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
199 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
200 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
201 $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
202 }
203 }
204
205 /**
206 * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
207 *
208 * @since ?
209 * @access friendly
210 */
211 function get_strings_for_block( $settings ) {
212 $class = new Visualizer_Module_Language();
213 $strings = $class->get_strings();
214 $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
215 return array_merge( $settings, $array );
216 }
217
218 /**
219 * Load plugin translation for - TinyMCE API
220 *
221 * @access public
222 * @param array $arr The tinymce_lang array.
223 * @return array
224 */
225 public function add_tinymce_lang( $arr ) {
226 $ui_lang = VISUALIZER_ABSPATH . '/classes/Visualizer/Module/Language.php';
227 $ui_lang = apply_filters( 'visualizer_ui_lang_filter', $ui_lang );
228 $arr[] = $ui_lang;
229 return $arr;
230 }
231
232 /**
233 * Load custom js options - TinyMCE API
234 *
235 * @access public
236 * @param array $plugin_array The tinymce plugin array.
237 * @return array
238 */
239 public function tinymce_plugin( $plugin_array ) {
240 $plugin_array['visualizer_mce_button'] = VISUALIZER_ABSURL . 'js/mce.js';
241 return $plugin_array;
242 }
243
244 /**
245 * Register new button in the editor
246 *
247 * @access public
248 * @param array $buttons The tinymce buttons array.
249 * @return array
250 */
251 public function register_mce_button( $buttons ) {
252 array_push( $buttons, 'visualizer_mce_button' );
253 return $buttons;
254 }
255
256 /**
257 * Whether to show the feedback review or not.
258 *
259 * @access public
260 */
261 public function feedbackReviewTrigger( $dumb ) {
262 $query = new WP_Query(
263 array(
264 'posts_per_page' => 50,
265 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
266 'fields' => 'ids',
267 'update_post_meta_cache' => false,
268 'update_post_term_cache' => false,
269 )
270 );
271
272 if ( $query->have_posts() && $query->post_count > 0 ) {
273 return true;
274 }
275 return false;
276 }
277
278 /**
279 * Enqueues media scripts and styles.
280 *
281 * @since 1.0.0
282 * @uses wp_enqueue_style To enqueue style file.
283 * @uses wp_enqueue_script To enqueue script file.
284 *
285 * @access public
286 */
287 public function enqueueMediaScripts() {
288 global $typenow;
289 if ( post_type_supports( $typenow, 'editor' ) ) {
290 wp_enqueue_style( 'visualizer-media', VISUALIZER_ABSURL . 'css/media.css', array( 'media-views' ), Visualizer_Plugin::VERSION );
291
292 // Load all the assets for the different libraries we support.
293 $deps = array(
294 Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
295 Visualizer_Render_Sidebar_Type_DataTable_DataTable::enqueue_assets( array( 'media-editor' ) ),
296 );
297
298 wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
299 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
300 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
301 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
302 wp_localize_script(
303 'visualizer-media-view',
304 'visualizer',
305 array(
306 'i10n' => array(
307 'insert' => __( 'Insert', 'visualizer' ),
308 ),
309 )
310 );
311 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
312 wp_enqueue_script( 'visualizer-media', VISUALIZER_ABSURL . 'js/media.js', array( 'visualizer-media-toolbar' ), Visualizer_Plugin::VERSION, true );
313 }
314 }
315
316 /**
317 * Extends media view strings with visualizer strings.
318 *
319 * @since 1.0.0
320 *
321 * @access public
322 *
323 * @param array $strings The array of media view strings.
324 *
325 * @return array The extended array of media view strings.
326 */
327 public function setupMediaViewStrings( $strings ) {
328 $chart_types = self::_getChartTypesLocalized( true, true, true );
329 $strings['visualizer'] = array(
330 'actions' => array(
331 'get_charts' => Visualizer_Plugin::ACTION_GET_CHARTS,
332 'delete_chart' => Visualizer_Plugin::ACTION_DELETE_CHART,
333 ),
334 'controller' => array(
335 'title' => esc_html__( 'Visualizations', 'visualizer' ),
336 ),
337 'routers' => array(
338 'library' => esc_html__( 'From Library', 'visualizer' ),
339 'create' => esc_html__( 'Create New', 'visualizer' ),
340 ),
341 'library' => array(
342 'filters' => $chart_types,
343 'types' => array_keys( $chart_types ),
344 ),
345 'nonce' => wp_create_nonce(),
346 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
347 );
348
349 return $strings;
350 }
351
352 /**
353 * Returns associated array of chart types and localized names.
354 *
355 * @since 1.0.0
356 *
357 * @static
358 * @access private
359 * @return array The associated array of chart types with localized names.
360 */
361 public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
362 $additional = array();
363 if ( $add_select ) {
364 $additional['select'] = array(
365 'name' => esc_html__( 'All', 'visualizer' ),
366 'enabled' => true,
367 );
368 }
369
370 $types = array_merge(
371 $additional,
372 array(
373 'dataTable' => array(
374 'name' => esc_html__( 'Table', 'visualizer' ),
375 'enabled' => true,
376 'supports' => array( 'DataTable' ),
377 ),
378 'pie' => array(
379 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
380 'enabled' => true,
381 'supports' => array( 'Google Charts', 'ChartJS' ),
382 ),
383 'line' => array(
384 'name' => esc_html__( 'Line', 'visualizer' ),
385 'enabled' => true,
386 'supports' => array( 'Google Charts', 'ChartJS' ),
387 ),
388 'area' => array(
389 'name' => esc_html__( 'Area', 'visualizer' ),
390 'enabled' => true,
391 // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
392 'supports' => array( 'Google Charts' ),
393 ),
394 'geo' => array(
395 'name' => esc_html__( 'Geo', 'visualizer' ),
396 'enabled' => true,
397 'supports' => array( 'Google Charts' ),
398 ),
399 'bar' => array(
400 'name' => esc_html__( 'Bar', 'visualizer' ),
401 'enabled' => true,
402 'supports' => array( 'Google Charts', 'ChartJS' ),
403 ),
404 'column' => array(
405 'name' => esc_html__( 'Column', 'visualizer' ),
406 'enabled' => true,
407 'supports' => array( 'Google Charts', 'ChartJS' ),
408 ),
409 'bubble' => array(
410 'name' => esc_html__( 'Bubble', 'visualizer' ),
411 'enabled' => true,
412 // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
413 'supports' => array( 'Google Charts' ),
414 ),
415 'scatter' => array(
416 'name' => esc_html__( 'Scatter', 'visualizer' ),
417 'enabled' => true,
418 'supports' => array( 'Google Charts' ),
419 ),
420 'gauge' => array(
421 'name' => esc_html__( 'Gauge', 'visualizer' ),
422 'enabled' => true,
423 'supports' => array( 'Google Charts' ),
424 ),
425 'candlestick' => array(
426 'name' => esc_html__( 'Candlestick', 'visualizer' ),
427 'enabled' => true,
428 'supports' => array( 'Google Charts' ),
429 ),
430 // pro types
431 'table' => array(
432 'name' => esc_html__( 'Table (Deprecated)', 'visualizer' ),
433 'enabled' => false,
434 'supports' => array( 'Google Charts' ),
435 ),
436 'timeline' => array(
437 'name' => esc_html__( 'Timeline', 'visualizer' ),
438 'enabled' => false,
439 'supports' => array( 'Google Charts', 'ChartJS' ),
440 ),
441 'combo' => array(
442 'name' => esc_html__( 'Combo', 'visualizer' ),
443 'enabled' => false,
444 'supports' => array( 'Google Charts' ),
445 ),
446 'polarArea' => array(
447 'name' => esc_html__( 'Polar Area', 'visualizer' ),
448 'enabled' => false,
449 'supports' => array( 'ChartJS' ),
450 ),
451 'radar' => array(
452 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
453 'enabled' => false,
454 'supports' => array( 'ChartJS' ),
455 ),
456 )
457 );
458 $types = apply_filters( 'visualizer_pro_chart_types', $types );
459 if ( $enabledOnly ) {
460 $filtered = array();
461 foreach ( $types as $type => $array ) {
462 if ( ! is_array( $array ) ) {
463 // support for old pro
464 $array = array( 'enabled' => true, 'name' => $array );
465 }
466 // backward compatibility for PRO before v1.9.0
467 if ( ! array_key_exists( 'supports', $array ) ) {
468 $array['supports'] = array( 'Google Charts' );
469 }
470 if ( ! $array['enabled'] ) {
471 continue;
472 }
473 $filtered[ $type ] = $array;
474 }
475 $types = $filtered;
476 }
477 if ( $get2Darray ) {
478 $doubleD = array();
479 foreach ( $types as $type => $array ) {
480 if ( ! is_array( $array ) ) {
481 // support for old pro
482 $array = array( 'enabled' => true, 'name' => $array );
483 }
484 // backward compatibility for PRO before v1.9.0
485 if ( ! array_key_exists( 'supports', $array ) ) {
486 $array['supports'] = array( 'Google Charts' );
487 }
488 $doubleD[ $type ] = $array['name'];
489 }
490 $types = $doubleD;
491 }
492
493 return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
494 }
495
496 /**
497 * Handle (soon-to-be) deprecated charts.
498 */
499 private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
500 $deprecated = array();
501
502 switch ( $where ) {
503 case 'types':
504 // fall-through
505 case 'library':
506 // if the user has a Google Table chart, show it as deprecated otherwise remove the option from the library.
507 if ( ! self::hasChartType( 'table' ) ) {
508 $deprecated[] = 'table';
509 if ( $get2Darray ) {
510 $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
511 } else {
512 $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
513 }
514 }
515
516 // if a user has a Gauge/Candlestick chart, then let them keep using it.
517 if ( ! Visualizer_Module::is_pro() ) {
518 if ( ! self::hasChartType( 'gauge' ) ) {
519 if ( $get2Darray ) {
520 $deprecated[] = 'gauge';
521 } else {
522 $types['gauge']['enabled'] = false;
523 }
524 }
525 if ( ! self::hasChartType( 'candlestick' ) ) {
526 if ( $get2Darray ) {
527 $deprecated[] = 'candlestick';
528 } else {
529 $types['candlestick']['enabled'] = false;
530 }
531 }
532 }
533 break;
534 default:
535 // remove the option to create a Google Table chart.
536 $deprecated[] = 'table';
537
538 // rename the new table chart type.
539 if ( $get2Darray ) {
540 $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
541 } else {
542 $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
543 }
544
545 // if a user has a Gauge/Candlestick chart, then let them keep using it.
546 if ( ! Visualizer_Module::is_pro() ) {
547 if ( ! self::hasChartType( 'gauge' ) ) {
548 if ( $get2Darray ) {
549 $deprecated[] = 'gauge';
550 } else {
551 $types['gauge']['enabled'] = false;
552 }
553 }
554 if ( ! self::hasChartType( 'candlestick' ) ) {
555 if ( $get2Darray ) {
556 $deprecated[] = 'candlestick';
557 } else {
558 $types['candlestick']['enabled'] = false;
559 }
560 }
561 }
562 }
563
564 if ( $deprecated ) {
565 foreach ( $deprecated as $type ) {
566 unset( $types[ $type ] );
567 }
568 }
569
570 return $types;
571 }
572
573 /**
574 * Renders templates to use in media popup.
575 *
576 * @since 1.0.0
577 * @global string $pagenow The name of the current page.
578 *
579 * @access public
580 */
581 public function renderTemplates() {
582 global $pagenow;
583 if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
584 return;
585 }
586 $render = new Visualizer_Render_Templates();
587 $render->render();
588 }
589
590 /**
591 * Enqueues library scripts and styles.
592 *
593 * @since 1.0.0
594 * @uses wp_enqueue_style() To enqueue library stylesheet.
595 * @uses wp_enqueue_script() To enqueue javascript file.
596 * @uses wp_enqueue_media() To enqueue media stuff.
597 *
598 * @access public
599 *
600 * @param string $suffix The current page suffix.
601 */
602 public function enqueueLibraryScripts( $suffix ) {
603 if ( $suffix === $this->_libraryPage ) {
604 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
605 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
606 wp_enqueue_media();
607 wp_enqueue_script(
608 'visualizer-library',
609 VISUALIZER_ABSURL . 'js/library.js',
610 array(
611 'jquery',
612 'media-views',
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 remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
690 }
691
692 /**
693 * Get the instance of WP_Query that fetches the charts as per the given criteria.
694 */
695 private function getQuery() {
696 static $q;
697 if ( ! is_null( $q ) ) {
698 return $q;
699 }
700
701 // get current page
702 $page = filter_input(
703 INPUT_GET,
704 'vpage',
705 FILTER_VALIDATE_INT,
706 array(
707 'options' => array(
708 'min_range' => 1,
709 'default' => 1,
710 ),
711 )
712 );
713 // the initial query arguments to fetch charts
714 $query_args = array(
715 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
716 'posts_per_page' => 6,
717 'paged' => $page,
718 );
719 // add chart type filter to the query arguments
720 $filter = filter_input( INPUT_GET, 'type' );
721 if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
722 $query_args['meta_query'] = array(
723 array(
724 'key' => Visualizer_Plugin::CF_CHART_TYPE,
725 'value' => $filter,
726 'compare' => '=',
727 ),
728 );
729 } else {
730 $filter = 'all';
731 }
732 // Added by Ash/Upwork
733 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
734 if ( $filterByMeta ) {
735 $query = array(
736 'key' => Visualizer_Plugin::CF_SETTINGS,
737 'value' => $filterByMeta,
738 'compare' => 'LIKE',
739 );
740 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
741 $meta[] = $query;
742 $query_args['meta_query'] = $meta;
743 }
744 $q = new WP_Query( $query_args );
745 return $q;
746 }
747
748 /**
749 * Renders support page.
750 *
751 * @since 3.3.0
752 *
753 * @access public
754 */
755 public function renderSupportPage() {
756 wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
757 include_once VISUALIZER_ABSPATH . '/templates/support.php';
758 }
759
760 /**
761 * Renders visualizer library page.
762 *
763 * @since 1.0.0
764 *
765 * @access public
766 */
767 public function renderLibraryPage() {
768 $charts = array();
769 $query = $this->getQuery();
770
771 // get current page
772 $page = filter_input(
773 INPUT_GET,
774 'vpage',
775 FILTER_VALIDATE_INT,
776 array(
777 'options' => array(
778 'min_range' => 1,
779 'default' => 1,
780 ),
781 )
782 );
783 // add chart type filter to the query arguments
784 $filter = filter_input( INPUT_GET, 'type' );
785 if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
786 $filter = 'all';
787 }
788
789 $css = '';
790 while ( $query->have_posts() ) {
791 $chart = $query->next_post();
792
793 // 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.
794 $chart = $this->handleExistingRevisions( $chart->ID, $chart );
795 // refresh a "live" db query chart.
796 $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
797
798 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
799
800 // fetch and update settings
801 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
802
803 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
804 if ( ! empty( $atts['settings'] ) ) {
805 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
806 }
807
808 if ( $settings ) {
809 unset( $settings['height'], $settings['width'], $settings['chartArea'] );
810 }
811
812 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
813 $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( html_entity_decode( $chart->post_content ) ), $chart->ID, $type );
814
815 $library = $this->load_chart_type( $chart->ID );
816
817 $id = 'visualizer-' . $chart->ID;
818 $arguments = $this->get_inline_custom_css( $id, $settings );
819 if ( ! empty( $arguments ) ) {
820 $css .= $arguments[0];
821 $settings = $arguments[1];
822 }
823
824 // add chart to the array
825 $charts[ $id ] = array(
826 'id' => $chart->ID,
827 'type' => $type,
828 'series' => $series,
829 'settings' => $settings,
830 'data' => $data,
831 'library' => $library,
832 );
833 }
834 // enqueue charts array
835 $ajaxurl = admin_url( 'admin-ajax.php' );
836 wp_localize_script(
837 'visualizer-library',
838 'visualizer',
839 array(
840 'language' => $this->get_language(),
841 'map_api_key' => get_option( 'visualizer-map-api-key' ),
842 'charts' => $charts,
843 'urls' => array(
844 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
845 'create' => add_query_arg(
846 array(
847 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
848 'library' => 'yes',
849 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
850 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
851 'vaction' => false,
852 ),
853 $ajaxurl
854 ),
855 'edit' => add_query_arg(
856 array(
857 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
858 'library' => 'yes',
859 'vaction' => false,
860 ),
861 $ajaxurl
862 ),
863 ),
864 'page_type' => 'library',
865 'is_front' => false,
866 )
867 );
868 // render library page
869 $render = new Visualizer_Render_Library();
870 $render->charts = $charts;
871 $render->type = $filter;
872 $render->types = self::_getChartTypesLocalized( false, false, false, true );
873 $render->custom_css = $css;
874 $render->pagination = paginate_links(
875 array(
876 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
877 'format' => '',
878 'current' => $page,
879 'total' => $query->max_num_pages,
880 'type' => 'array',
881 )
882 );
883 $render->render();
884 }
885
886 /**
887 * Updates the plugin's action links, which will be rendered at the plugins table.
888 *
889 * @since 1.0.0
890 *
891 * @access public
892 *
893 * @param array $links The array of original action links.
894 * @param string $file The plugin basename.
895 *
896 * @return array Updated array of action links.
897 */
898 public function getPluginActionLinks( $links, $file ) {
899 if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
900 array_unshift(
901 $links,
902 sprintf(
903 '<a href="%s">%s</a>',
904 admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
905 esc_html__( 'Library', 'visualizer' )
906 )
907 );
908 }
909
910 return $links;
911 }
912
913 /**
914 * Updates the plugin's meta links, which will be rendered at the plugins table.
915 *
916 * @since 1.0.0
917 *
918 * @access public
919 *
920 * @param array $plugin_meta The array of a plugin meta links.
921 * @param string $plugin_file The plugin's basename.
922 *
923 * @return array Updated array of plugin meta links.
924 */
925 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
926 if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
927 // knowledge base link
928 $plugin_meta[] = sprintf(
929 '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
930 esc_html__( 'Docs', 'visualizer' )
931 );
932 // flattr link
933 $plugin_meta[] = sprintf(
934 '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
935 esc_html__( 'Pro Addon', 'visualizer' )
936 );
937 }
938
939 return $plugin_meta;
940 }
941
942 }
943