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

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