PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.10.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.10.8
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 +564 -88 3.1.33.10.8 View file →
@@ -53,25 +53,109 @@
53 53 parent::__construct( $plugin );
54 54 $this->_addAction( 'load-post.php', 'enqueueMediaScripts' );
55 55 $this->_addAction( 'load-post-new.php', 'enqueueMediaScripts' );
56 56 $this->_addAction( 'admin_footer', 'renderTemplates' );
57 - $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 8 );
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 +
65 68 // revision support.
66 69 $this->_addFilter( 'wp_revisions_to_keep', 'limitRevisions', null, 10, 2 );
67 70 $this->_addAction( '_wp_put_post_revision', 'addRevision', null, 10, 1 );
68 71 $this->_addAction( 'wp_restore_post_revision', 'restoreRevision', null, 10, 2 );
69 72
73 + $this->_addAction( 'visualizer_chart_schedules_spl', 'addSplChartSchedules', null, 10, 3 );
74 +
70 75 $this->_addAction( 'admin_init', 'init' );
76 +
77 + $this->_addAction( 'visualizer_chart_languages', 'addMultilingualSupport' );
78 +
79 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
80 + $this->load_cypress_hooks();
81 + }
82 +
71 83 }
72 84
73 85 /**
86 + * Define the hooks that are needed for cypress.
87 + *
88 + * @since 3.4.0
89 + * @access private
90 + */
91 + private function load_cypress_hooks() {
92 + // all charts should load on the same page without pagination.
93 + add_filter(
94 + 'visualizer_query_args', function( $args ) {
95 + $args['posts_per_page'] = 20;
96 + return $args;
97 + }, 10, 1
98 + );
99 + }
100 +
101 + /**
102 + * Add disabled `optgroup` schedules to the drop downs.
103 + *
104 + * @since ?
105 + *
106 + * @access public
107 + *
108 + * @param string $feature The feature for which to add schedules.
109 + * @param int $chart_id The chart ID.
110 + * @param int $plan The plan number.
111 + */
112 + public function addSplChartSchedules( $feature, $chart_id, $plan ) {
113 + if ( apply_filters( 'visualizer_is_business', false ) ) {
114 + return;
115 + }
116 +
117 + $license = __( 'PRO', 'visualizer' );
118 + if ( Visualizer_Module::is_pro() ) {
119 + switch ( $plan ) {
120 + case 1:
121 + $license = __( 'Developer', 'visualizer' );
122 + break;
123 + }
124 + }
125 +
126 + $hours = array(
127 + '0' => __( 'Live', 'visualizer' ),
128 + '1' => __( 'Each hour', 'visualizer' ),
129 + '12' => __( 'Each 12 hours', 'visualizer' ),
130 + '24' => __( 'Each day', 'visualizer' ),
131 + '72' => __( 'Each 3 days', 'visualizer' ),
132 + );
133 +
134 + switch ( $feature ) {
135 + case 'json':
136 + case 'csv':
137 + // no more schedules if pro is already active.
138 + if ( Visualizer_Module::is_pro() ) {
139 + return;
140 + }
141 + break;
142 + case 'wp':
143 + // fall-through.
144 + case 'db':
145 + break;
146 + default:
147 + return;
148 + }
149 +
150 + echo '<optgroup disabled label="' . sprintf( __( 'More in the %s version', 'visualizer' ), $license ) . '">';
151 + foreach ( $hours as $hour => $desc ) {
152 + echo '<option disabled>' . $desc . '</option>';
153 + }
154 + echo '</optgroup>';
155 + }
156 +
157 + /**
74 158 * No limits on revisions.
75 159 */
76 160 public function limitRevisions( $num, $post ) {
77 161 if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
@@ -132,16 +216,31 @@
132 216 *
133 217 * @access public
134 218 */
135 219 public function init() {
220 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
136 221 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
137 222 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
138 223 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
139 224 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
225 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
140 226 }
141 227 }
142 228
143 229 /**
230 + * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
231 + *
232 + * @since ?
233 + * @access friendly
234 + */
235 + function get_strings_for_block( $settings ) {
236 + $class = new Visualizer_Module_Language();
237 + $strings = $class->get_strings();
238 + $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
239 + return array_merge( $settings, $array );
240 + }
241 +
242 + /**
144 243 * Load plugin translation for - TinyMCE API
145 244 *
146 245 * @access public
147 246 * @param array $arr The tinymce_lang array.
@@ -216,9 +315,9 @@
216 315
217 316 // Load all the assets for the different libraries we support.
218 317 $deps = array(
219 318 Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
220 - Visualizer_Render_Sidebar_Type_DataTable::enqueue_assets( array( 'media-editor' ) ),
319 + Visualizer_Render_Sidebar_Type_DataTable_Tabular::enqueue_assets( array( 'media-editor' ) ),
221 320 );
222 321
223 322 wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
224 323 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
@@ -267,9 +366,9 @@
267 366 'filters' => $chart_types,
268 367 'types' => array_keys( $chart_types ),
269 368 ),
270 369 'nonce' => wp_create_nonce(),
271 - 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
370 + 'buildurl' => esc_url( add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ) ),
272 371 );
273 372
274 373 return $strings;
275 374 }
@@ -291,64 +390,91 @@
291 390 'enabled' => true,
292 391 );
293 392 }
294 393
394 + $enabled = self::proFeaturesLocked();
395 +
295 396 $types = array_merge(
296 397 $additional,
297 398 array(
298 - 'dataTable' => array(
299 - 'name' => esc_html__( 'Table (New)', 'visualizer' ),
399 + 'tabular' => array(
400 + 'name' => esc_html__( 'Table', 'visualizer' ),
300 401 'enabled' => true,
402 + 'supports' => $enabled ? array( 'Google Charts', 'DataTable' ) : array( 'DataTable' ),
301 403 ),
302 404 'pie' => array(
303 - 'name' => esc_html__( 'Pie', 'visualizer' ),
405 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
304 406 'enabled' => true,
407 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
305 408 ),
306 409 'line' => array(
307 410 'name' => esc_html__( 'Line', 'visualizer' ),
308 411 'enabled' => true,
412 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
309 413 ),
414 + 'bar' => array(
415 + 'name' => esc_html__( 'Bar', 'visualizer' ),
416 + 'enabled' => true,
417 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
418 + ),
310 419 'area' => array(
311 420 'name' => esc_html__( 'Area', 'visualizer' ),
312 - 'enabled' => true,
421 + 'enabled' => $enabled,
422 + // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
423 + 'supports' => array( 'Google Charts' ),
313 424 ),
314 425 'geo' => array(
315 426 'name' => esc_html__( 'Geo', 'visualizer' ),
316 - 'enabled' => true,
427 + 'enabled' => $enabled,
428 + 'supports' => array( 'Google Charts' ),
317 429 ),
318 - 'bar' => array(
319 - 'name' => esc_html__( 'Bar', 'visualizer' ),
320 - 'enabled' => true,
321 - ),
322 430 'column' => array(
323 431 'name' => esc_html__( 'Column', 'visualizer' ),
324 - 'enabled' => true,
432 + 'enabled' => $enabled,
433 + 'supports' => array( 'Google Charts', 'ChartJS' ),
325 434 ),
435 + 'bubble' => array(
436 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
437 + 'enabled' => $enabled,
438 + // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
439 + 'supports' => array( 'Google Charts' ),
440 + ),
326 441 'scatter' => array(
327 442 'name' => esc_html__( 'Scatter', 'visualizer' ),
328 - 'enabled' => true,
443 + 'enabled' => $enabled,
444 + 'supports' => array( 'Google Charts' ),
329 445 ),
330 446 'gauge' => array(
331 447 'name' => esc_html__( 'Gauge', 'visualizer' ),
332 - 'enabled' => true,
448 + 'enabled' => $enabled,
449 + 'supports' => array( 'Google Charts' ),
333 450 ),
334 451 'candlestick' => array(
335 452 'name' => esc_html__( 'Candlestick', 'visualizer' ),
336 - 'enabled' => true,
453 + 'enabled' => $enabled,
454 + 'supports' => array( 'Google Charts' ),
337 455 ),
338 456 // pro types
339 - 'table' => array(
340 - 'name' => esc_html__( 'Table (Deprecated)', 'visualizer' ),
341 - 'enabled' => false,
342 - ),
343 457 'timeline' => array(
344 458 'name' => esc_html__( 'Timeline', 'visualizer' ),
345 459 'enabled' => false,
460 + 'supports' => array( 'Google Charts', 'ChartJS' ),
346 461 ),
347 462 'combo' => array(
348 463 'name' => esc_html__( 'Combo', 'visualizer' ),
349 464 'enabled' => false,
465 + 'supports' => array( 'Google Charts' ),
350 466 ),
467 + 'polarArea' => array(
468 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
469 + 'enabled' => false,
470 + 'supports' => array( 'ChartJS' ),
471 + ),
472 + 'radar' => array(
473 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
474 + 'enabled' => false,
475 + 'supports' => array( 'ChartJS' ),
476 + ),
351 477 )
352 478 );
353 479 $types = apply_filters( 'visualizer_pro_chart_types', $types );
354 480 if ( $enabledOnly ) {
@@ -357,8 +483,12 @@
357 483 if ( ! is_array( $array ) ) {
358 484 // support for old pro
359 485 $array = array( 'enabled' => true, 'name' => $array );
360 486 }
487 + // backward compatibility for PRO before v1.9.0
488 + if ( ! array_key_exists( 'supports', $array ) ) {
489 + $array['supports'] = array( 'Google Charts' );
490 + }
361 491 if ( ! $array['enabled'] ) {
362 492 continue;
363 493 }
364 494 $filtered[ $type ] = $array;
@@ -371,8 +501,12 @@
371 501 if ( ! is_array( $array ) ) {
372 502 // support for old pro
373 503 $array = array( 'enabled' => true, 'name' => $array );
374 504 }
505 + // backward compatibility for PRO before v1.9.0
506 + if ( ! array_key_exists( 'supports', $array ) ) {
507 + $array['supports'] = array( 'Google Charts' );
508 + }
375 509 $doubleD[ $type ] = $array['name'];
376 510 }
377 511 $types = $doubleD;
378 512 }
@@ -386,21 +520,13 @@
386 520 private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
387 521 $deprecated = array();
388 522
389 523 switch ( $where ) {
524 + case 'types':
525 + // fall-through
390 526 case 'library':
391 - // if the user has a Google Table chart, show it as deprecated otherwise remove the option from the library.
392 - if ( ! self::hasChartType( 'table' ) ) {
393 - $deprecated[] = 'table';
394 - if ( $get2Darray ) {
395 - $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
396 - } else {
397 - $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
398 - }
399 - }
400 -
401 527 // if a user has a Gauge/Candlestick chart, then let them keep using it.
402 - if ( ! VISUALIZER_PRO ) {
528 + if ( ! Visualizer_Module::is_pro() ) {
403 529 if ( ! self::hasChartType( 'gauge' ) ) {
404 530 if ( $get2Darray ) {
405 531 $deprecated[] = 'gauge';
406 532 } else {
@@ -416,20 +542,10 @@
416 542 }
417 543 }
418 544 break;
419 545 default:
420 - // remove the option to create a Google Table chart.
421 - $deprecated[] = 'table';
422 -
423 - // rename the new table chart type.
424 - if ( $get2Darray ) {
425 - $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
426 - } else {
427 - $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
428 - }
429 -
430 546 // if a user has a Gauge/Candlestick chart, then let them keep using it.
431 - if ( ! VISUALIZER_PRO ) {
547 + if ( ! Visualizer_Module::is_pro() ) {
432 548 if ( ! self::hasChartType( 'gauge' ) ) {
433 549 if ( $get2Darray ) {
434 550 $deprecated[] = 'gauge';
435 551 } else {
@@ -464,9 +580,9 @@
464 580 * @access public
465 581 */
466 582 public function renderTemplates() {
467 583 global $pagenow;
468 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
584 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
469 585 return;
470 586 }
471 587 $render = new Visualizer_Render_Templates();
472 588 $render->render();
@@ -484,9 +600,9 @@
484 600 *
485 601 * @param string $suffix The current page suffix.
486 602 */
487 603 public function enqueueLibraryScripts( $suffix ) {
488 - if ( $suffix == $this->_libraryPage ) {
604 + if ( $suffix === $this->_libraryPage ) {
489 605 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
490 606 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
491 607 wp_enqueue_media();
492 608 wp_enqueue_script(
@@ -494,8 +610,9 @@
494 610 VISUALIZER_ABSURL . 'js/library.js',
495 611 array(
496 612 'jquery',
497 613 'media-views',
614 + 'clipboard',
498 615 ),
499 616 Visualizer_Plugin::VERSION,
500 617 true
501 618 );
@@ -544,14 +661,177 @@
544 661 *
545 662 * @access public
546 663 */
547 664 public function registerAdminMenu() {
548 - $title = esc_html__( 'Visualizer Library', 'visualizer' );
549 - $callback = array( $this, 'renderLibraryPage' );
550 - $this->_libraryPage = add_submenu_page( 'upload.php', $title, $title, 'edit_posts', Visualizer_Plugin::NAME, $callback );
665 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
666 +
667 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
668 +
669 + add_submenu_page(
670 + Visualizer_Plugin::NAME,
671 + __( 'Chart Library', 'visualizer' ),
672 + __( 'Chart Library', 'visualizer' ),
673 + 'edit_posts',
674 + 'admin.php?page=' . Visualizer_Plugin::NAME
675 + );
676 + add_submenu_page(
677 + Visualizer_Plugin::NAME,
678 + __( 'Add New Chart', 'visualizer' ),
679 + __( 'Add New Chart', 'visualizer' ),
680 + 'edit_posts',
681 + 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew'
682 + );
683 + add_submenu_page(
684 + Visualizer_Plugin::NAME,
685 + __( 'Support', 'visualizer' ),
686 + __( '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>',
687 + 'edit_posts',
688 + 'viz-support',
689 + array( $this, 'renderSupportPage' )
690 + );
691 +
692 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
693 +
694 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
695 + add_action( 'admin_footer', array( $this, 'handleGetProSubMenu' ) );
551 696 }
552 697
553 698 /**
699 + * Handle get pro plugin submenu.
700 + */
701 + public function handleGetProSubMenu() {
702 + if ( ! Visualizer_Module::is_pro() ) {
703 + ?>
704 + <style type="text/css">
705 + #toplevel_page_visualizer ul.wp-submenu li:last-child {
706 + background: #FF7E65;
707 + font-size: 14px;
708 + font-weight: 600;
709 + color: #fff;
710 + }
711 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a {
712 + color: #fff !important;
713 + }
714 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a:hover {
715 + box-shadow: inherit;
716 + }
717 + </style>
718 + <?php
719 + if ( get_option( 'visualizer_fresh_install', false ) ) {
720 + ?>
721 + <style type="text/css">
722 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li {
723 + display: none;
724 + }
725 + </style>
726 + <?php
727 + }
728 + }
729 + }
730 +
731 + /**
732 + * Adds the screen options for pagination.
733 + */
734 + function addScreenOptions() {
735 + $screen = get_current_screen();
736 +
737 + // bail if it's some other page.
738 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
739 + return;
740 + }
741 +
742 + $args = array(
743 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
744 + 'default' => 6,
745 + 'option' => 'visualizer_library_per_page',
746 + );
747 + add_screen_option( 'per_page', $args );
748 + }
749 +
750 + /**
751 + * Returns the screen option for pagination.
752 + */
753 + function setScreenOptions( $status, $option, $value ) {
754 + if ( 'visualizer_library_per_page' === $option ) {
755 + return $value;
756 + }
757 + }
758 +
759 + /**
760 + * Adds the display filters to be used in the meta_query while displaying the charts.
761 + */
762 + private function getDisplayFilters( &$query_args ) {
763 + $query = array();
764 + global $sitepress;
765 + if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
766 + $current_lang = icl_get_current_language();
767 + if ( in_array( $current_lang, array( 'all', icl_get_default_language() ), true ) ) {
768 + $query[] = array(
769 + 'key' => 'chart_lang',
770 + 'compare' => 'NOT EXISTS',
771 + );
772 + } else {
773 + $query[] = array(
774 + 'key' => 'chart_lang',
775 + 'value' => $current_lang,
776 + 'compare' => '=',
777 + );
778 + }
779 + }
780 +
781 + // add chart type filter to the query arguments
782 + $type = filter_input( INPUT_GET, 'type' );
783 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
784 + $query[] = array(
785 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
786 + 'value' => $type,
787 + 'compare' => '=',
788 + );
789 + }
790 +
791 + // add chart library filter to the query arguments
792 + $library = filter_input( INPUT_GET, 'library' );
793 + if ( $library ) {
794 + $query[] = array(
795 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
796 + 'value' => $library,
797 + 'compare' => '=',
798 + );
799 + }
800 +
801 + // add date filter to the query arguments
802 + $date = filter_input( INPUT_GET, 'date' );
803 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
804 + if ( $date && in_array( $date, $possible, true ) ) {
805 + $query_args['date_query'] = array(
806 + 'after' => "$date -1 day",
807 + 'inclusive' => true,
808 + );
809 + }
810 +
811 + // add source filter to the query arguments
812 + $source = filter_input( INPUT_GET, 'source' );
813 + if ( $source ) {
814 + $source = ucwords( $source );
815 + $source = "Visualizer_Source_{$source}";
816 + $query[] = array(
817 + 'key' => Visualizer_Plugin::CF_SOURCE,
818 + 'value' => $source,
819 + 'compare' => '=',
820 + );
821 + }
822 +
823 + $query_args['meta_query'] = $query;
824 +
825 + $orderby = filter_input( INPUT_GET, 'orderby' );
826 + $order = filter_input( INPUT_GET, 'order' );
827 + if ( $orderby ) {
828 + $query_args['order_by'] = $orderby;
829 + }
830 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
831 + }
832 +
833 + /**
554 834 * Get the instance of WP_Query that fetches the charts as per the given criteria.
555 835 */
556 836 private function getQuery() {
557 837 static $q;
@@ -570,29 +850,34 @@
570 850 'default' => 1,
571 851 ),
572 852 )
573 853 );
854 +
855 + $per_page = 6;
856 + $screen = get_current_screen();
857 + if ( $screen ) {
858 + // retrieve the per_page option
859 + $screen_option = $screen->get_option( 'per_page', 'option' );
860 + // retrieve the value stored for the current user
861 + $user = get_current_user_id();
862 + $per_page = get_user_meta( $user, $screen_option, true );
863 + if ( empty( $per_page ) || $per_page < 1 ) {
864 + // nothing set, get the default value
865 + $per_page = $screen->get_option( 'per_page', 'default' );
866 + }
867 + }
868 +
574 869 // the initial query arguments to fetch charts
575 870 $query_args = array(
576 871 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
577 - 'posts_per_page' => 6,
872 + 'posts_per_page' => $per_page,
578 873 'paged' => $page,
579 874 );
580 - // add chart type filter to the query arguments
581 - $filter = filter_input( INPUT_GET, 'type' );
582 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
583 - $query_args['meta_query'] = array(
584 - array(
585 - 'key' => Visualizer_Plugin::CF_CHART_TYPE,
586 - 'value' => $filter,
587 - 'compare' => '=',
588 - ),
589 - );
590 - } else {
591 - $filter = 'all';
592 - }
875 +
876 + $this->getDisplayFilters( $query_args );
877 +
593 878 // Added by Ash/Upwork
594 - $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
879 + $filterByMeta = ! empty( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
595 880 if ( $filterByMeta ) {
596 881 $query = array(
597 882 'key' => Visualizer_Plugin::CF_SETTINGS,
598 883 'value' => $filterByMeta,
@@ -601,13 +886,26 @@
601 886 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
602 887 $meta[] = $query;
603 888 $query_args['meta_query'] = $meta;
604 889 }
605 - $q = new WP_Query( $query_args );
890 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
606 891 return $q;
607 892 }
608 893
609 894 /**
895 + * Renders support page.
896 + *
897 + * @since 3.3.0
898 + *
899 + * @access public
900 + */
901 + public function renderSupportPage() {
902 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
903 + $this->load_survey();
904 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
905 + }
906 +
907 + /**
610 908 * Renders visualizer library page.
611 909 *
612 910 * @since 1.0.0
613 911 *
@@ -630,9 +928,9 @@
630 928 )
631 929 );
632 930 // add chart type filter to the query arguments
633 931 $filter = filter_input( INPUT_GET, 'type' );
634 - if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) ) {
932 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
635 933 $filter = 'all';
636 934 }
637 935
638 936 $css = '';
@@ -653,12 +951,27 @@
653 951 if ( ! empty( $atts['settings'] ) ) {
654 952 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
655 953 }
656 954
657 - unset( $settings['height'], $settings['width'] );
955 + if ( $settings ) {
956 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
957 + }
958 +
658 959 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
659 - $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( html_entity_decode( $chart->post_content ) ), $chart->ID, $type );
960 + $data = self::get_chart_data( $chart, $type );
660 961
962 + // Set default setting series when add manual chart data - Only during first creation.
963 + if ( isset( $settings['series'] ) && ! empty( $series ) ) {
964 + $count_series = count( $series ) - count( $settings['series'] );
965 + if ( $count_series > 1 ) {
966 + $clone_last_series = end( $settings['series'] );
967 + $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
968 + foreach ( range( 1, $count_series ) as $item ) {
969 + $settings['series'][] = $clone_last_series;
970 + }
971 + }
972 + }
973 +
661 974 $library = $this->load_chart_type( $chart->ID );
662 975
663 976 $id = 'visualizer-' . $chart->ID;
664 977 $arguments = $this->get_inline_custom_css( $id, $settings );
@@ -666,8 +979,15 @@
666 979 $css .= $arguments[0];
667 980 $settings = $arguments[1];
668 981 }
669 982
983 + if ( isset( $settings['controls']['ui']['labelStacking'] ) ) {
984 + unset( $settings['controls']['ui']['labelStacking'] );
985 + }
986 + if ( isset( $settings['controls']['ui']['orientation'] ) ) {
987 + unset( $settings['controls']['ui']['orientation'] );
988 + }
989 +
670 990 // add chart to the array
671 991 $charts[ $id ] = array(
672 992 'id' => $chart->ID,
673 993 'type' => $type,
@@ -686,26 +1006,38 @@
686 1006 'language' => $this->get_language(),
687 1007 'map_api_key' => get_option( 'visualizer-map-api-key' ),
688 1008 'charts' => $charts,
689 1009 'urls' => array(
690 - 'base' => add_query_arg( 'vpage', false ),
691 - 'create' => add_query_arg(
692 - array(
693 - 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
694 - 'library' => 'yes',
695 - 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
696 - ),
697 - $ajaxurl
1010 + 'base' => esc_url( add_query_arg( array( 'vpage' => false, 'vaction' => false ) ) ),
1011 + 'create' => esc_url(
1012 + add_query_arg(
1013 + array(
1014 + 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
1015 + 'library' => 'yes',
1016 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
1017 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
1018 + 'vaction' => false,
1019 + ),
1020 + $ajaxurl
1021 + )
698 1022 ),
699 - 'edit' => add_query_arg(
700 - array(
701 - 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
702 - 'library' => 'yes',
703 - ),
704 - $ajaxurl
1023 + 'edit' => esc_url(
1024 + add_query_arg(
1025 + array(
1026 + 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
1027 + 'library' => 'yes',
1028 + 'vaction' => false,
1029 + ),
1030 + $ajaxurl
1031 + )
705 1032 ),
706 1033 ),
707 1034 'page_type' => 'library',
1035 + 'is_front' => false,
1036 + 'i10n' => array(
1037 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
1038 + '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' ),
1039 + ),
708 1040 )
709 1041 );
710 1042 // render library page
711 1043 $render = new Visualizer_Render_Library();
@@ -714,9 +1046,9 @@
714 1046 $render->types = self::_getChartTypesLocalized( false, false, false, true );
715 1047 $render->custom_css = $css;
716 1048 $render->pagination = paginate_links(
717 1049 array(
718 - 'base' => add_query_arg( 'vpage', '%#%' ),
1050 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
719 1051 'format' => '',
720 1052 'current' => $page,
721 1053 'total' => $query->max_num_pages,
722 1054 'type' => 'array',
@@ -721,8 +1053,11 @@
721 1053 'total' => $query->max_num_pages,
722 1054 'type' => 'array',
723 1055 )
724 1056 );
1057 +
1058 + $this->load_survey();
1059 +
725 1060 $render->render();
726 1061 }
727 1062
728 1063 /**
@@ -737,14 +1072,14 @@
737 1072 *
738 1073 * @return array Updated array of action links.
739 1074 */
740 1075 public function getPluginActionLinks( $links, $file ) {
741 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1076 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
742 1077 array_unshift(
743 1078 $links,
744 1079 sprintf(
745 1080 '<a href="%s">%s</a>',
746 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1081 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
747 1082 esc_html__( 'Library', 'visualizer' )
748 1083 )
749 1084 );
750 1085 }
@@ -764,17 +1099,17 @@
764 1099 *
765 1100 * @return array Updated array of plugin meta links.
766 1101 */
767 1102 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
768 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1103 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
769 1104 // knowledge base link
770 1105 $plugin_meta[] = sprintf(
771 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
772 - esc_html__( 'Knowledge Base', 'visualizer' )
1106 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1107 + esc_html__( 'Docs', 'visualizer' )
773 1108 );
774 1109 // flattr link
775 1110 $plugin_meta[] = sprintf(
776 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1111 + '<a style="color:red" href="' . tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'pluginrow' ) . '" target="_blank">%s</a>',
777 1112 esc_html__( 'Pro Addon', 'visualizer' )
778 1113 );
779 1114 }
780 1115
@@ -780,5 +1115,146 @@
780 1115
781 1116 return $plugin_meta;
782 1117 }
783 1118
1119 + /**
1120 + * If check is existing user.
1121 + *
1122 + * @return bool Default false
1123 + */
1124 + public static function proFeaturesLocked() {
1125 + if ( Visualizer_Module::is_pro() ) {
1126 + return true;
1127 + }
1128 + return 'yes' === get_option( 'visualizer-new-user', 'yes' ) ? false : true;
1129 + }
1130 +
1131 + /**
1132 + * Multilingual Support.
1133 + *
1134 + * @param int $chart_id Chart ID.
1135 + * @return bool Default false
1136 + */
1137 + public function addMultilingualSupport( $chart_id ) {
1138 + global $sitepress;
1139 + if ( Visualizer_Module::is_pro() ) {
1140 + return;
1141 + }
1142 + if ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) {
1143 + $language = icl_get_languages();
1144 + $current_lang = icl_get_current_language();
1145 + $default_lang = icl_get_default_language();
1146 + $post_info = wpml_get_language_information( null, $chart_id );
1147 + $translations = array();
1148 + if ( ! empty( $post_info ) && ( $default_lang === $post_info['language_code'] ) ) {
1149 + $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
1150 + $translations = $sitepress->get_element_translations( $trid );
1151 + }
1152 + if ( empty( $translations ) ) {
1153 + return;
1154 + }
1155 + ?>
1156 + <hr><div class="visualizer-languages-list only-pro">
1157 + <?php
1158 + foreach ( $language as $lang ) {
1159 + $lang_code = $lang['code'];
1160 + if ( $current_lang !== $lang_code ) {
1161 + ?>
1162 + <a href="javascript:;">
1163 + <img src="<?php echo esc_url( $lang['country_flag_url'] ); ?>" alt="<?php echo esc_attr( $lang['translated_name'] ); ?>">
1164 + </a>
1165 + <?php
1166 + }
1167 + }
1168 + ?>
1169 + <a href="<?php echo tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'wpml-support', 'visualizer_render_char' ); ?>"target="_blank"><?php esc_html_e( 'Upgrade to PRO to active this translation for charts', 'visualizer' ); ?></a>
1170 + </div>
1171 + <?php
1172 + }
1173 + }
1174 +
1175 + /**
1176 + * Check chart is enabled or not.
1177 + *
1178 + * @param string $type Chart ID.
1179 + *
1180 + * @return bool Default false
1181 + */
1182 + public static function checkChartStatus( $type ) {
1183 + $types = self::_getChartTypesLocalized( false, false, false, true );
1184 + if ( isset( $types[ $type ] ) ) {
1185 + return ! empty( $types[ $type ]['enabled'] );
1186 + }
1187 + return false;
1188 + }
1189 +
1190 + /**
1191 + * Get the survey metadata.
1192 + *
1193 + * @return array The survey metadata.
1194 + */
1195 + private function get_survey_metadata() {
1196 + $install_date = get_option( 'visualizer_install', false );
1197 + $install_category = 0;
1198 +
1199 + if ( false !== $install_date ) {
1200 + $days_since_install = round( ( time() - $install_date ) / DAY_IN_SECONDS );
1201 +
1202 + if ( 0 === $days_since_install || 1 === $days_since_install ) {
1203 + $install_category = 0;
1204 + } elseif ( 1 < $days_since_install && 8 > $days_since_install ) {
1205 + $install_category = 7;
1206 + } elseif ( 8 <= $days_since_install && 31 > $days_since_install ) {
1207 + $install_category = 30;
1208 + } elseif ( 30 < $days_since_install && 90 > $days_since_install ) {
1209 + $install_category = 90;
1210 + } elseif ( 90 <= $days_since_install ) {
1211 + $install_category = 91;
1212 + }
1213 + }
1214 +
1215 + $plugin_data = get_plugin_data( VISUALIZER_BASEFILE, false, false );
1216 + $plugin_version = '';
1217 + if ( ! empty( $plugin_data['Version'] ) ) {
1218 + $plugin_version = $plugin_data['Version'];
1219 + }
1220 +
1221 + $user_id = 'visualizer_' . preg_replace( '/[^\w\d]*/', '', get_site_url() ); // Use a normalized version of the site URL as a user ID.
1222 +
1223 + $license_data = get_option( 'visualizer_pro_license_data', false );
1224 + if ( false !== $license_data ) {
1225 + $user_id = 'visualizer_' . $license_data->key;
1226 + }
1227 +
1228 + return array(
1229 + 'userId' => $user_id,
1230 + 'attributes' => array(
1231 + 'days_since_install' => $install_category,
1232 + 'free_version' => $plugin_version,
1233 + 'pro_version' => defined( 'VISUALIZER_PRO_VERSION' ) ? VISUALIZER_PRO_VERSION : '',
1234 + 'license_status' => apply_filters( 'product_visualizer_license_status', 'invalid' ),
1235 + ),
1236 + );
1237 + }
1238 +
1239 + /**
1240 + * Load the survey.
1241 + */
1242 + private function load_survey() {
1243 +
1244 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
1245 + return;
1246 + }
1247 +
1248 + $survey_handler = apply_filters( 'themeisle_sdk_dependency_script_handler', 'survey' );
1249 +
1250 + if ( empty( $survey_handler ) ) {
1251 + return;
1252 + }
1253 +
1254 + $metadata = $this->get_survey_metadata();
1255 +
1256 + do_action( 'themeisle_sdk_dependency_enqueue_script', 'survey' );
1257 + wp_enqueue_script( 'visualizer_chart_survey', VISUALIZER_ABSURL . 'js/survey.js', array( $survey_handler ), $metadata['attributes']['free_version'], true );
1258 + wp_localize_script( 'visualizer_chart_survey', 'visualizerSurveyData', $metadata );
1259 + }
784 1260 }