PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.7.9
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.7.9
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
← All changes | classes/Visualizer/Module/Admin.php +643 -91 3.0.73.7.9 View file →
@@ -52,34 +52,193 @@
52 52 public function __construct( Visualizer_Plugin $plugin ) {
53 53 parent::__construct( $plugin );
54 54 $this->_addAction( 'load-post.php', 'enqueueMediaScripts' );
55 55 $this->_addAction( 'load-post-new.php', 'enqueueMediaScripts' );
56 - $this->_addAction( 'admin_footer', 'renderTempaltes' );
57 - $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 8 );
56 + $this->_addAction( 'admin_footer', 'renderTemplates' );
57 + $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 0 );
58 58 $this->_addAction( 'admin_menu', 'registerAdminMenu' );
59 59 $this->_addFilter( 'media_view_strings', 'setupMediaViewStrings' );
60 60 $this->_addFilter( 'plugin_action_links', 'getPluginActionLinks', 10, 2 );
61 + $this->_addFilter( 'plugin_row_meta', 'getPluginMetaLinks', 10, 2 );
61 62 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
62 - $this->_addFilter( 'visualizer_get_chart_counts', 'getChartCountsByTypeAndMeta' );
63 63 $this->_addFilter( 'visualizer_feedback_review_trigger', 'feedbackReviewTrigger' );
64 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 +
65 75 $this->_addAction( 'admin_init', 'init' );
76 +
77 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
78 + $this->load_cypress_hooks();
79 + }
80 +
66 81 }
67 82
68 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 + /**
69 213 * Admin init.
70 214 *
71 215 * @access public
72 216 */
73 217 public function init() {
218 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
74 219 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
75 220 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
76 221 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
77 222 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
223 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
78 224 }
79 225 }
80 226
81 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 + /**
82 241 * Load plugin translation for - TinyMCE API
83 242 *
84 243 * @access public
85 244 * @param array $arr The tinymce_lang array.
@@ -150,16 +309,23 @@
150 309 public function enqueueMediaScripts() {
151 310 global $typenow;
152 311 if ( post_type_supports( $typenow, 'editor' ) ) {
153 312 wp_enqueue_style( 'visualizer-media', VISUALIZER_ABSURL . 'css/media.css', array( 'media-views' ), Visualizer_Plugin::VERSION );
154 - wp_enqueue_script( 'visualizer-google-jsapi-new', '//www.gstatic.com/charts/loader.js', array( 'media-editor' ), null, true );
155 - wp_enqueue_script( 'visualizer-google-jsapi-old', '//www.google.com/jsapi', array( 'visualizer-google-jsapi-new' ), null, true );
156 - wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', array( 'visualizer-google-jsapi-old' ), Visualizer_Plugin::VERSION, true );
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 );
157 321 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
158 322 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
159 323 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
160 324 wp_localize_script(
161 - 'visualizer-media-view', 'visualizer', array(
325 + 'visualizer-media-view',
326 + 'visualizer',
327 + array(
162 328 'i10n' => array(
163 329 'insert' => __( 'Insert', 'visualizer' ),
164 330 ),
165 331 )
@@ -198,9 +364,9 @@
198 364 'filters' => $chart_types,
199 365 'types' => array_keys( $chart_types ),
200 366 ),
201 367 'nonce' => wp_create_nonce(),
202 - 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
368 + 'buildurl' => esc_url( add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ) ),
203 369 );
204 370
205 371 return $strings;
206 372 }
@@ -213,9 +379,9 @@
213 379 * @static
214 380 * @access private
215 381 * @return array The associated array of chart types with localized names.
216 382 */
217 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false ) {
383 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
218 384 $additional = array();
219 385 if ( $add_select ) {
220 386 $additional['select'] = array(
221 387 'name' => esc_html__( 'All', 'visualizer' ),
@@ -222,59 +388,91 @@
222 388 'enabled' => true,
223 389 );
224 390 }
225 391
392 + $enabled = self::proFeaturesLocked();
393 +
226 394 $types = array_merge(
227 - $additional, array(
395 + $additional,
396 + array(
397 + 'tabular' => array(
398 + 'name' => esc_html__( 'Table', 'visualizer' ),
399 + 'enabled' => true,
400 + 'supports' => $enabled ? array( 'Google Charts', 'DataTable' ) : array( 'DataTable' ),
401 + ),
228 402 'pie' => array(
229 - 'name' => esc_html__( 'Pie', 'visualizer' ),
403 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
230 404 'enabled' => true,
405 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
231 406 ),
232 407 'line' => array(
233 408 'name' => esc_html__( 'Line', 'visualizer' ),
234 409 'enabled' => true,
410 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
235 411 ),
412 + 'bar' => array(
413 + 'name' => esc_html__( 'Bar', 'visualizer' ),
414 + 'enabled' => true,
415 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
416 + ),
236 417 'area' => array(
237 418 'name' => esc_html__( 'Area', 'visualizer' ),
238 - 'enabled' => true,
419 + 'enabled' => $enabled,
420 + // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
421 + 'supports' => array( 'Google Charts' ),
239 422 ),
240 423 'geo' => array(
241 424 'name' => esc_html__( 'Geo', 'visualizer' ),
242 - 'enabled' => true,
425 + 'enabled' => $enabled,
426 + 'supports' => array( 'Google Charts' ),
243 427 ),
244 - 'bar' => array(
245 - 'name' => esc_html__( 'Bar', 'visualizer' ),
246 - 'enabled' => true,
247 - ),
248 428 'column' => array(
249 429 'name' => esc_html__( 'Column', 'visualizer' ),
250 - 'enabled' => true,
430 + 'enabled' => $enabled,
431 + 'supports' => array( 'Google Charts', 'ChartJS' ),
251 432 ),
252 - 'gauge' => array(
253 - 'name' => esc_html__( 'Gauge', 'visualizer' ),
254 - 'enabled' => true,
433 + 'bubble' => array(
434 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
435 + 'enabled' => $enabled,
436 + // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
437 + 'supports' => array( 'Google Charts' ),
255 438 ),
256 439 'scatter' => array(
257 440 'name' => esc_html__( 'Scatter', 'visualizer' ),
258 - 'enabled' => true,
441 + 'enabled' => $enabled,
442 + 'supports' => array( 'Google Charts' ),
259 443 ),
444 + 'gauge' => array(
445 + 'name' => esc_html__( 'Gauge', 'visualizer' ),
446 + 'enabled' => $enabled,
447 + 'supports' => array( 'Google Charts' ),
448 + ),
260 449 'candlestick' => array(
261 450 'name' => esc_html__( 'Candlestick', 'visualizer' ),
262 - 'enabled' => true,
451 + 'enabled' => $enabled,
452 + 'supports' => array( 'Google Charts' ),
263 453 ),
264 454 // pro types
265 - 'table' => array(
266 - 'name' => esc_html__( 'Table', 'visualizer' ),
267 - 'enabled' => false,
268 - ),
269 455 'timeline' => array(
270 456 'name' => esc_html__( 'Timeline', 'visualizer' ),
271 457 'enabled' => false,
458 + 'supports' => array( 'Google Charts', 'ChartJS' ),
272 459 ),
273 460 'combo' => array(
274 461 'name' => esc_html__( 'Combo', 'visualizer' ),
275 462 'enabled' => false,
463 + 'supports' => array( 'Google Charts' ),
276 464 ),
465 + 'polarArea' => array(
466 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
467 + 'enabled' => false,
468 + 'supports' => array( 'ChartJS' ),
469 + ),
470 + 'radar' => array(
471 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
472 + 'enabled' => false,
473 + 'supports' => array( 'ChartJS' ),
474 + ),
277 475 )
278 476 );
279 477 $types = apply_filters( 'visualizer_pro_chart_types', $types );
280 478 if ( $enabledOnly ) {
@@ -283,8 +481,12 @@
283 481 if ( ! is_array( $array ) ) {
284 482 // support for old pro
285 483 $array = array( 'enabled' => true, 'name' => $array );
286 484 }
485 + // backward compatibility for PRO before v1.9.0
486 + if ( ! array_key_exists( 'supports', $array ) ) {
487 + $array['supports'] = array( 'Google Charts' );
488 + }
287 489 if ( ! $array['enabled'] ) {
288 490 continue;
289 491 }
290 492 $filtered[ $type ] = $array;
@@ -297,13 +499,74 @@
297 499 if ( ! is_array( $array ) ) {
298 500 // support for old pro
299 501 $array = array( 'enabled' => true, 'name' => $array );
300 502 }
503 + // backward compatibility for PRO before v1.9.0
504 + if ( ! array_key_exists( 'supports', $array ) ) {
505 + $array['supports'] = array( 'Google Charts' );
506 + }
301 507 $doubleD[ $type ] = $array['name'];
302 508 }
303 509 $types = $doubleD;
304 510 }
305 511
512 + return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
513 + }
514 +
515 + /**
516 + * Handle (soon-to-be) deprecated charts.
517 + */
518 + private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
519 + $deprecated = array();
520 +
521 + switch ( $where ) {
522 + case 'types':
523 + // fall-through
524 + case 'library':
525 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
526 + if ( ! Visualizer_Module::is_pro() ) {
527 + if ( ! self::hasChartType( 'gauge' ) ) {
528 + if ( $get2Darray ) {
529 + $deprecated[] = 'gauge';
530 + } else {
531 + $types['gauge']['enabled'] = false;
532 + }
533 + }
534 + if ( ! self::hasChartType( 'candlestick' ) ) {
535 + if ( $get2Darray ) {
536 + $deprecated[] = 'candlestick';
537 + } else {
538 + $types['candlestick']['enabled'] = false;
539 + }
540 + }
541 + }
542 + break;
543 + default:
544 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
545 + if ( ! Visualizer_Module::is_pro() ) {
546 + if ( ! self::hasChartType( 'gauge' ) ) {
547 + if ( $get2Darray ) {
548 + $deprecated[] = 'gauge';
549 + } else {
550 + $types['gauge']['enabled'] = false;
551 + }
552 + }
553 + if ( ! self::hasChartType( 'candlestick' ) ) {
554 + if ( $get2Darray ) {
555 + $deprecated[] = 'candlestick';
556 + } else {
557 + $types['candlestick']['enabled'] = false;
558 + }
559 + }
560 + }
561 + }
562 +
563 + if ( $deprecated ) {
564 + foreach ( $deprecated as $type ) {
565 + unset( $types[ $type ] );
566 + }
567 + }
568 +
306 569 return $types;
307 570 }
308 571
309 572 /**
@@ -313,11 +576,11 @@
313 576 * @global string $pagenow The name of the current page.
314 577 *
315 578 * @access public
316 579 */
317 - public function renderTempaltes() {
580 + public function renderTemplates() {
318 581 global $pagenow;
319 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
582 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
320 583 return;
321 584 }
322 585 $render = new Visualizer_Render_Templates();
323 586 $render->render();
@@ -335,26 +598,41 @@
335 598 *
336 599 * @param string $suffix The current page suffix.
337 600 */
338 601 public function enqueueLibraryScripts( $suffix ) {
339 - if ( $suffix == $this->_libraryPage ) {
602 + if ( $suffix === $this->_libraryPage ) {
340 603 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
341 604 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
342 605 wp_enqueue_media();
343 606 wp_enqueue_script(
344 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
607 + 'visualizer-library',
608 + VISUALIZER_ABSURL . 'js/library.js',
609 + array(
345 610 'jquery',
346 611 'media-views',
347 - ), Visualizer_Plugin::VERSION, true
612 + 'clipboard',
613 + ),
614 + Visualizer_Plugin::VERSION,
615 + true
348 616 );
349 - wp_enqueue_script( 'google-jsapi-new', '//www.gstatic.com/charts/loader.js', array(), null, true );
350 - wp_enqueue_script( 'google-jsapi-old', '//www.google.com/jsapi', array( 'google-jsapi-new' ), null, true );
351 - wp_enqueue_script(
352 - 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array(
353 - 'google-jsapi-old',
354 - 'visualizer-library',
355 - ), Visualizer_Plugin::VERSION, true
356 - );
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 + }
357 635 }
358 636 }
359 637
360 638 /**
@@ -381,24 +659,182 @@
381 659 *
382 660 * @access public
383 661 */
384 662 public function registerAdminMenu() {
385 - $title = esc_html__( 'Visualizer Library', 'visualizer' );
386 - $callback = array( $this, 'renderLibraryPage' );
387 - $this->_libraryPage = add_submenu_page( 'upload.php', $title, $title, 'edit_posts', Visualizer_Plugin::NAME, $callback );
663 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
664 +
665 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
666 +
667 + add_submenu_page(
668 + Visualizer_Plugin::NAME,
669 + __( 'Chart Library', 'visualizer' ),
670 + __( 'Chart Library', 'visualizer' ),
671 + 'edit_posts',
672 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
673 + );
674 + add_submenu_page(
675 + Visualizer_Plugin::NAME,
676 + __( 'Add New Chart', 'visualizer' ),
677 + __( 'Add New Chart', 'visualizer' ),
678 + 'edit_posts',
679 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
680 + );
681 + add_submenu_page(
682 + Visualizer_Plugin::NAME,
683 + __( 'Support', 'visualizer' ),
684 + __( 'Support', 'visualizer' ) . '<span class="dashicons dashicons-editor-help more-features-icon" style="width: 17px; height: 17px; margin-left: 4px; color: #ffca54; font-size: 17px; vertical-align: -3px;"></span>',
685 + 'edit_posts',
686 + 'viz-support',
687 + array( $this, 'renderSupportPage' )
688 + );
689 +
690 + if ( ! Visualizer_Module::is_pro() ) {
691 + add_submenu_page(
692 + Visualizer_Plugin::NAME,
693 + __( 'Get Visualizer Pro', 'visualizer' ),
694 + __( 'Get Visualizer Pro', 'visualizer' ),
695 + 'edit_posts',
696 + 'viz-get-pro',
697 + '__return_null'
698 + );
699 + add_action( 'admin_footer', array( $this, 'handleGetProSubMenu' ) );
700 + }
701 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
702 +
703 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
388 704 }
389 705
390 706 /**
391 - * Renders visualizer library page.
392 - *
393 - * @since 1.0.0
394 - *
395 - * @access public
707 + * Handle get pro plugin submenu.
396 708 */
397 - public function renderLibraryPage() {
709 + public function handleGetProSubMenu() {
710 + ?>
711 + <style type="text/css">
712 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li {
713 + background: #FF7E65;
714 + font-size: 14px;
715 + font-weight: 600;
716 + color: #fff;
717 + }
718 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li > a {
719 + color: #fff !important;
720 + }
721 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li > a:hover {
722 + box-shadow: inherit;
723 + }
724 + </style>
725 + <script type="text/javascript">
726 + jQuery( document ).ready( function() {
727 + jQuery( '#toplevel_page_visualizer' ).on( 'click', 'li:not(.wp-submenu-head, .wp-first-item):eq(2)', function( e ) {
728 + e.preventDefault();
729 + window.open( 'https://themeisle.com/plugins/visualizer-charts-and-graphs/upgrade/#pricing', '_blank' );
730 + } );
731 + } );
732 + </script>
733 + <?php
734 + }
735 +
736 + /**
737 + * Adds the screen options for pagination.
738 + */
739 + function addScreenOptions() {
740 + $screen = get_current_screen();
741 +
742 + // bail if it's some other page.
743 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
744 + return;
745 + }
746 +
747 + $args = array(
748 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
749 + 'default' => 6,
750 + 'option' => 'visualizer_library_per_page',
751 + );
752 + add_screen_option( 'per_page', $args );
753 + }
754 +
755 + /**
756 + * Returns the screen option for pagination.
757 + */
758 + function setScreenOptions( $status, $option, $value ) {
759 + if ( 'visualizer_library_per_page' === $option ) {
760 + return $value;
761 + }
762 + }
763 +
764 + /**
765 + * Adds the display filters to be used in the meta_query while displaying the charts.
766 + */
767 + private function getDisplayFilters( &$query_args ) {
768 + $query = array();
769 +
770 + // add chart type filter to the query arguments
771 + $type = filter_input( INPUT_GET, 'type' );
772 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
773 + $query[] = array(
774 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
775 + 'value' => $type,
776 + 'compare' => '=',
777 + );
778 + }
779 +
780 + // add chart library filter to the query arguments
781 + $library = filter_input( INPUT_GET, 'library' );
782 + if ( $library ) {
783 + $query[] = array(
784 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
785 + 'value' => $library,
786 + 'compare' => '=',
787 + );
788 + }
789 +
790 + // add date filter to the query arguments
791 + $date = filter_input( INPUT_GET, 'date' );
792 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
793 + if ( $date && in_array( $date, $possible, true ) ) {
794 + $query_args['date_query'] = array(
795 + 'after' => "$date -1 day",
796 + 'inclusive' => true,
797 + );
798 + }
799 +
800 + // add source filter to the query arguments
801 + $source = filter_input( INPUT_GET, 'source' );
802 + if ( $source ) {
803 + $source = ucwords( $source );
804 + $source = "Visualizer_Source_{$source}";
805 + $query[] = array(
806 + 'key' => Visualizer_Plugin::CF_SOURCE,
807 + 'value' => $source,
808 + 'compare' => '=',
809 + );
810 + }
811 +
812 + $query_args['meta_query'] = $query;
813 +
814 + $orderby = filter_input( INPUT_GET, 'orderby' );
815 + $order = filter_input( INPUT_GET, 'order' );
816 + if ( $orderby ) {
817 + $query_args['order_by'] = $orderby;
818 + }
819 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
820 + }
821 +
822 + /**
823 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
824 + */
825 + private function getQuery() {
826 + static $q;
827 + if ( ! is_null( $q ) ) {
828 + return $q;
829 + }
830 +
398 831 // get current page
399 832 $page = filter_input(
400 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
833 + INPUT_GET,
834 + 'vpage',
835 + FILTER_VALIDATE_INT,
836 + array(
401 837 'options' => array(
402 838 'min_range' => 1,
403 839 'default' => 1,
404 840 ),
@@ -403,27 +839,32 @@
403 839 'default' => 1,
404 840 ),
405 841 )
406 842 );
843 +
844 + $per_page = 6;
845 + $screen = get_current_screen();
846 + if ( $screen ) {
847 + // retrieve the per_page option
848 + $screen_option = $screen->get_option( 'per_page', 'option' );
849 + // retrieve the value stored for the current user
850 + $user = get_current_user_id();
851 + $per_page = get_user_meta( $user, $screen_option, true );
852 + if ( empty( $per_page ) || $per_page < 1 ) {
853 + // nothing set, get the default value
854 + $per_page = $screen->get_option( 'per_page', 'default' );
855 + }
856 + }
857 +
407 858 // the initial query arguments to fetch charts
408 859 $query_args = array(
409 860 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
410 - 'posts_per_page' => 6,
861 + 'posts_per_page' => $per_page,
411 862 'paged' => $page,
412 863 );
413 - // add chart type filter to the query arguments
414 - $filter = filter_input( INPUT_GET, 'type' );
415 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
416 - $query_args['meta_query'] = array(
417 - array(
418 - 'key' => Visualizer_Plugin::CF_CHART_TYPE,
419 - 'value' => $filter,
420 - 'compare' => '=',
421 - ),
422 - );
423 - } else {
424 - $filter = 'all';
425 - }
864 +
865 + $this->getDisplayFilters( $query_args );
866 +
426 867 // Added by Ash/Upwork
427 868 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
428 869 if ( $filterByMeta ) {
429 870 $query = array(
@@ -434,51 +875,150 @@
434 875 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
435 876 $meta[] = $query;
436 877 $query_args['meta_query'] = $meta;
437 878 }
438 - // Added by Ash/Upwork
439 - // fetch charts
879 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
880 + return $q;
881 + }
882 +
883 + /**
884 + * Renders support page.
885 + *
886 + * @since 3.3.0
887 + *
888 + * @access public
889 + */
890 + public function renderSupportPage() {
891 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
892 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
893 + }
894 +
895 + /**
896 + * Renders visualizer library page.
897 + *
898 + * @since 1.0.0
899 + *
900 + * @access public
901 + */
902 + public function renderLibraryPage() {
440 903 $charts = array();
441 - $query = new WP_Query( $query_args );
904 + $query = $this->getQuery();
905 +
906 + // get current page
907 + $page = filter_input(
908 + INPUT_GET,
909 + 'vpage',
910 + FILTER_VALIDATE_INT,
911 + array(
912 + 'options' => array(
913 + 'min_range' => 1,
914 + 'default' => 1,
915 + ),
916 + )
917 + );
918 + // add chart type filter to the query arguments
919 + $filter = filter_input( INPUT_GET, 'type' );
920 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
921 + $filter = 'all';
922 + }
923 +
924 + $css = '';
442 925 while ( $query->have_posts() ) {
443 926 $chart = $query->next_post();
927 +
928 + // if the user has updated a chart and instead of saving it, has closed the modal. If the user refreshes, they should get the original chart.
929 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
930 + // refresh a "live" db query chart.
931 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
932 +
933 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
934 +
444 935 // fetch and update settings
445 936 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
446 - unset( $settings['height'], $settings['width'] );
447 - $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
937 +
938 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
939 + if ( ! empty( $atts['settings'] ) ) {
940 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
941 + }
942 +
943 + if ( $settings ) {
944 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
945 + }
946 +
448 947 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
449 - $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( html_entity_decode( $chart->post_content ) ), $chart->ID, $type );
948 + $data = self::get_chart_data( $chart, $type );
949 +
950 + // Set default setting series when add manual chart data - Only during first creation.
951 + if ( isset( $settings['series'] ) && ! empty( $series ) ) {
952 + $count_series = count( $series ) - count( $settings['series'] );
953 + if ( $count_series > 1 ) {
954 + $clone_last_series = end( $settings['series'] );
955 + $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
956 + foreach ( range( 1, $count_series ) as $item ) {
957 + $settings['series'][] = $clone_last_series;
958 + }
959 + }
960 + }
961 +
962 + $library = $this->load_chart_type( $chart->ID );
963 +
964 + $id = 'visualizer-' . $chart->ID;
965 + $arguments = $this->get_inline_custom_css( $id, $settings );
966 + if ( ! empty( $arguments ) ) {
967 + $css .= $arguments[0];
968 + $settings = $arguments[1];
969 + }
970 +
450 971 // add chart to the array
451 - $charts[ 'visualizer-' . $chart->ID ] = array(
972 + $charts[ $id ] = array(
452 973 'id' => $chart->ID,
453 974 'type' => $type,
454 975 'series' => $series,
455 976 'settings' => $settings,
456 977 'data' => $data,
978 + 'library' => $library,
457 979 );
458 980 }
459 981 // enqueue charts array
460 982 $ajaxurl = admin_url( 'admin-ajax.php' );
461 983 wp_localize_script(
462 - 'visualizer-library', 'visualizer', array(
984 + 'visualizer-library',
985 + 'visualizer',
986 + array(
463 987 'language' => $this->get_language(),
464 988 'map_api_key' => get_option( 'visualizer-map-api-key' ),
465 989 'charts' => $charts,
466 990 'urls' => array(
467 - 'base' => add_query_arg( 'vpage', false ),
468 - 'create' => add_query_arg(
469 - array(
470 - 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
471 - 'library' => 'yes',
472 - ), $ajaxurl
991 + 'base' => esc_url( add_query_arg( array( 'vpage' => false, 'vaction' => false ) ) ),
992 + 'create' => esc_url(
993 + add_query_arg(
994 + array(
995 + 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
996 + 'library' => 'yes',
997 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
998 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
999 + 'vaction' => false,
1000 + ),
1001 + $ajaxurl
1002 + )
473 1003 ),
474 - 'edit' => add_query_arg(
475 - array(
476 - 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
477 - 'library' => 'yes',
478 - ), $ajaxurl
1004 + 'edit' => esc_url(
1005 + add_query_arg(
1006 + array(
1007 + 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
1008 + 'library' => 'yes',
1009 + 'vaction' => false,
1010 + ),
1011 + $ajaxurl
1012 + )
479 1013 ),
480 1014 ),
1015 + 'page_type' => 'library',
1016 + 'is_front' => false,
1017 + 'i10n' => array(
1018 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
1019 + 'conflict' => __( 'We have detected a potential conflict with another component that prevents Visualizer from functioning properly. Please disable any of the following components if they are activated on your instance: Modern Events Calendar plugin, Acronix plugin. In case the aforementioned components are not activated or you continue to see this error message, please disable all other plugins and enable them one by one to find out the component that is causing the conflict.', 'visualizer' ),
1020 + ),
481 1021 )
482 1022 );
483 1023 // render library page
484 1024 $render = new Visualizer_Render_Library();
@@ -483,12 +1023,13 @@
483 1023 // render library page
484 1024 $render = new Visualizer_Render_Library();
485 1025 $render->charts = $charts;
486 1026 $render->type = $filter;
487 - $render->types = self::_getChartTypesLocalized();
1027 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
1028 + $render->custom_css = $css;
488 1029 $render->pagination = paginate_links(
489 1030 array(
490 - 'base' => add_query_arg( 'vpage', '%#%' ),
1031 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
491 1032 'format' => '',
492 1033 'current' => $page,
493 1034 'total' => $query->max_num_pages,
494 1035 'type' => 'array',
@@ -509,14 +1050,14 @@
509 1050 *
510 1051 * @return array Updated array of action links.
511 1052 */
512 1053 public function getPluginActionLinks( $links, $file ) {
513 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1054 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
514 1055 array_unshift(
515 1056 $links,
516 1057 sprintf(
517 1058 '<a href="%s">%s</a>',
518 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1059 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
519 1060 esc_html__( 'Library', 'visualizer' )
520 1061 )
521 1062 );
522 1063 }
@@ -536,17 +1077,17 @@
536 1077 *
537 1078 * @return array Updated array of plugin meta links.
538 1079 */
539 1080 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
540 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1081 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
541 1082 // knowledge base link
542 1083 $plugin_meta[] = sprintf(
543 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
544 - esc_html__( 'Knowledge Base', 'visualizer' )
1084 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1085 + esc_html__( 'Docs', 'visualizer' )
545 1086 );
546 1087 // flattr link
547 1088 $plugin_meta[] = sprintf(
548 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1089 + '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
549 1090 esc_html__( 'Pro Addon', 'visualizer' )
550 1091 );
551 1092 }
552 1093
@@ -552,5 +1093,16 @@
552 1093
553 1094 return $plugin_meta;
554 1095 }
555 1096
1097 + /**
1098 + * If check is existing user.
1099 + *
1100 + * @return bool Default false
1101 + */
1102 + public static function proFeaturesLocked() {
1103 + if ( Visualizer_Module::is_pro() ) {
1104 + return true;
1105 + }
1106 + return 'yes' === get_option( 'visualizer-new-user', 'yes' ) ? false : true;
1107 + }
556 1108 }