PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.1
4.0.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 All 149 releases
← All changes | classes/Visualizer/Module/Admin.php +817 -92 3.0.73.11.1 View file →
@@ -52,34 +52,215 @@
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 + $this->_addAction( 'visualizer_chart_languages', 'addMultilingualSupport' );
78 +
79 + $this->_addFilter( 'admin_footer_text', 'render_review_notice' );
80 +
81 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
82 + $this->load_cypress_hooks();
83 + }
84 +
66 85 }
86 + /**
87 + * Display review notice.
88 + */
89 + public function render_review_notice( $footer_text ) {
90 + $current_screen = get_current_screen();
67 91
92 + $visualizer_page_ids = ['toplevel_page_visualizer', 'visualizer_page_viz-support', 'visualizer_page_ti-about-visualizer' ];
93 +
94 + if ( ! empty( $current_screen ) && isset( $current_screen->id ) ) {
95 + foreach ( $visualizer_page_ids as $page_to_check ) {
96 + if ( strpos( $current_screen->id, $page_to_check ) !== false ) {
97 + $footer_text = sprintf(
98 + __( 'Enjoying %1$s? %2$s %3$s rating. Thank you for being so supportive!', 'visualizer' ),
99 + '<b>Visualizer</b>',
100 + esc_html__( 'You can help us by leaving a', 'visualizer' ),
101 + '<a href="https://wordpress.org/support/plugin/visualizer/reviews/" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
102 + );
103 + break;
104 + }
105 + }
106 + }
107 +
108 + return $footer_text;
109 + }
110 +
111 +
68 112 /**
113 + * Define the hooks that are needed for cypress.
114 + *
115 + * @since 3.4.0
116 + * @access private
117 + */
118 + private function load_cypress_hooks() {
119 + // all charts should load on the same page without pagination.
120 + add_filter(
121 + 'visualizer_query_args', function( $args ) {
122 + $args['posts_per_page'] = 20;
123 + return $args;
124 + }, 10, 1
125 + );
126 + }
127 +
128 + /**
129 + * Add disabled `optgroup` schedules to the drop downs.
130 + *
131 + * @since ?
132 + *
133 + * @access public
134 + *
135 + * @param string $feature The feature for which to add schedules.
136 + * @param int $chart_id The chart ID.
137 + * @param int $plan The plan number.
138 + */
139 + public function addSplChartSchedules( $feature, $chart_id, $plan ) {
140 + if ( apply_filters( 'visualizer_is_business', false ) ) {
141 + return;
142 + }
143 +
144 + $is_new_personal = apply_filters( 'visualizer_is_new_personal', false );
145 +
146 + $hours = array(
147 + '0.16' => __( '10 minutes', 'visualizer' ),
148 + '1' => __( 'Each hour', 'visualizer' ),
149 + '12' => __( 'Each 12 hours', 'visualizer' ),
150 + '24' => __( 'Each day', 'visualizer' ),
151 + '72' => __( 'Each 3 days', 'visualizer' ),
152 + );
153 +
154 + switch ( $feature ) {
155 + case 'json':
156 + case 'csv':
157 + // no more schedules if pro is already active.
158 + if ( Visualizer_Module::is_pro() && ! $is_new_personal ) {
159 + return;
160 + }
161 + break;
162 + case 'wp':
163 + // fall-through.
164 + case 'db':
165 + break;
166 + default:
167 + return;
168 + }
169 +
170 + echo '<optgroup disabled label="' . __( 'Upgrade required', 'visualizer' ) . '">';
171 + foreach ( $hours as $hour => $desc ) {
172 + echo '<option disabled>' . $desc . '</option>';
173 + }
174 + echo '</optgroup>';
175 + }
176 +
177 + /**
178 + * No limits on revisions.
179 + */
180 + public function limitRevisions( $num, $post ) {
181 + if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
182 + return -1;
183 + }
184 + return $num;
185 + }
186 +
187 + /**
188 + * Add a revision.
189 + */
190 + public function addRevision( $revision_id ) {
191 + $parent_id = wp_is_post_revision( $revision_id );
192 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $parent_id ) ) {
193 + // add the meta data to this revision.
194 + $meta = get_post_meta( $parent_id, '', true );
195 +
196 + if ( $meta ) {
197 + foreach ( $meta as $key => $value ) {
198 + if ( 0 === strpos( $key, 'visualizer' ) ) {
199 + add_metadata( 'post', $revision_id, $key, maybe_unserialize( $value[0] ) );
200 + }
201 + }
202 + }
203 + }
204 + }
205 +
206 + /**
207 + * Restore a revision.
208 + */
209 + public function restoreRevision( $post_id, $revision_id ) {
210 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $post_id ) ) {
211 + // get the meta information from the revision.
212 + $meta = get_metadata( 'post', $revision_id, '', true );
213 +
214 + // delete all meta information from the post before adding.
215 + $post_meta = get_post_meta( $post_id, '', true );
216 + if ( $post_meta ) {
217 + foreach ( $meta as $key => $value ) {
218 + if ( 0 === strpos( $key, 'visualizer' ) ) {
219 + delete_post_meta( $post_id, $key );
220 + }
221 + }
222 + }
223 +
224 + if ( $meta ) {
225 + foreach ( $meta as $key => $value ) {
226 + if ( 0 === strpos( $key, 'visualizer' ) ) {
227 + add_post_meta( $post_id, $key, maybe_unserialize( $value[0] ) );
228 + }
229 + }
230 + }
231 + }
232 + }
233 +
234 + /**
69 235 * Admin init.
70 236 *
71 237 * @access public
72 238 */
73 239 public function init() {
240 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
74 241 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
75 242 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
76 243 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
77 244 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
245 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
78 246 }
79 247 }
80 248
81 249 /**
250 + * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
251 + *
252 + * @since ?
253 + * @access friendly
254 + */
255 + function get_strings_for_block( $settings ) {
256 + $class = new Visualizer_Module_Language();
257 + $strings = $class->get_strings();
258 + $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
259 + return array_merge( $settings, $array );
260 + }
261 +
262 + /**
82 263 * Load plugin translation for - TinyMCE API
83 264 *
84 265 * @access public
85 266 * @param array $arr The tinymce_lang array.
@@ -150,16 +331,23 @@
150 331 public function enqueueMediaScripts() {
151 332 global $typenow;
152 333 if ( post_type_supports( $typenow, 'editor' ) ) {
153 334 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 );
335 +
336 + // Load all the assets for the different libraries we support.
337 + $deps = array(
338 + Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
339 + Visualizer_Render_Sidebar_Type_DataTable_Tabular::enqueue_assets( array( 'media-editor' ) ),
340 + );
341 +
342 + wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
157 343 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
158 344 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
159 345 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
160 346 wp_localize_script(
161 - 'visualizer-media-view', 'visualizer', array(
347 + 'visualizer-media-view',
348 + 'visualizer',
349 + array(
162 350 'i10n' => array(
163 351 'insert' => __( 'Insert', 'visualizer' ),
164 352 ),
165 353 )
@@ -198,9 +386,9 @@
198 386 'filters' => $chart_types,
199 387 'types' => array_keys( $chart_types ),
200 388 ),
201 389 'nonce' => wp_create_nonce(),
202 - 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
390 + 'buildurl' => esc_url( add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ) ),
203 391 );
204 392
205 393 return $strings;
206 394 }
@@ -213,9 +401,9 @@
213 401 * @static
214 402 * @access private
215 403 * @return array The associated array of chart types with localized names.
216 404 */
217 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false ) {
405 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
218 406 $additional = array();
219 407 if ( $add_select ) {
220 408 $additional['select'] = array(
221 409 'name' => esc_html__( 'All', 'visualizer' ),
@@ -222,59 +410,91 @@
222 410 'enabled' => true,
223 411 );
224 412 }
225 413
414 + $enabled = self::proFeaturesLocked();
415 +
226 416 $types = array_merge(
227 - $additional, array(
417 + $additional,
418 + array(
419 + 'tabular' => array(
420 + 'name' => esc_html__( 'Table', 'visualizer' ),
421 + 'enabled' => true,
422 + 'supports' => $enabled ? array( 'Google Charts', 'DataTable' ) : array( 'DataTable' ),
423 + ),
228 424 'pie' => array(
229 - 'name' => esc_html__( 'Pie', 'visualizer' ),
425 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
230 426 'enabled' => true,
427 + 'supports' => array( 'Google Charts', 'ChartJS' ),
231 428 ),
232 429 'line' => array(
233 430 'name' => esc_html__( 'Line', 'visualizer' ),
234 431 'enabled' => true,
432 + 'supports' => array( 'Google Charts', 'ChartJS' ),
235 433 ),
434 + 'bar' => array(
435 + 'name' => esc_html__( 'Bar', 'visualizer' ),
436 + 'enabled' => true,
437 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
438 + ),
236 439 'area' => array(
237 440 'name' => esc_html__( 'Area', 'visualizer' ),
238 - 'enabled' => true,
441 + 'enabled' => $enabled,
442 + // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
443 + 'supports' => array( 'Google Charts' ),
239 444 ),
240 445 'geo' => array(
241 446 'name' => esc_html__( 'Geo', 'visualizer' ),
242 - 'enabled' => true,
447 + 'enabled' => $enabled,
448 + 'supports' => array( 'Google Charts' ),
243 449 ),
244 - 'bar' => array(
245 - 'name' => esc_html__( 'Bar', 'visualizer' ),
246 - 'enabled' => true,
247 - ),
248 450 'column' => array(
249 451 'name' => esc_html__( 'Column', 'visualizer' ),
250 - 'enabled' => true,
452 + 'enabled' => $enabled,
453 + 'supports' => array( 'Google Charts', 'ChartJS' ),
251 454 ),
252 - 'gauge' => array(
253 - 'name' => esc_html__( 'Gauge', 'visualizer' ),
254 - 'enabled' => true,
455 + 'bubble' => array(
456 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
457 + 'enabled' => $enabled,
458 + // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
459 + 'supports' => array( 'Google Charts' ),
255 460 ),
256 461 'scatter' => array(
257 462 'name' => esc_html__( 'Scatter', 'visualizer' ),
258 - 'enabled' => true,
463 + 'enabled' => $enabled,
464 + 'supports' => array( 'Google Charts' ),
259 465 ),
466 + 'gauge' => array(
467 + 'name' => esc_html__( 'Gauge', 'visualizer' ),
468 + 'enabled' => $enabled,
469 + 'supports' => array( 'Google Charts' ),
470 + ),
260 471 'candlestick' => array(
261 472 'name' => esc_html__( 'Candlestick', 'visualizer' ),
262 - 'enabled' => true,
473 + 'enabled' => $enabled,
474 + 'supports' => array( 'Google Charts' ),
263 475 ),
264 476 // pro types
265 - 'table' => array(
266 - 'name' => esc_html__( 'Table', 'visualizer' ),
267 - 'enabled' => false,
268 - ),
269 477 'timeline' => array(
270 478 'name' => esc_html__( 'Timeline', 'visualizer' ),
271 479 'enabled' => false,
480 + 'supports' => array( 'Google Charts', 'ChartJS' ),
272 481 ),
273 482 'combo' => array(
274 483 'name' => esc_html__( 'Combo', 'visualizer' ),
275 484 'enabled' => false,
485 + 'supports' => array( 'Google Charts' ),
276 486 ),
487 + 'polarArea' => array(
488 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
489 + 'enabled' => false,
490 + 'supports' => array( 'ChartJS' ),
491 + ),
492 + 'radar' => array(
493 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
494 + 'enabled' => false,
495 + 'supports' => array( 'ChartJS' ),
496 + ),
277 497 )
278 498 );
279 499 $types = apply_filters( 'visualizer_pro_chart_types', $types );
280 500 if ( $enabledOnly ) {
@@ -283,8 +503,12 @@
283 503 if ( ! is_array( $array ) ) {
284 504 // support for old pro
285 505 $array = array( 'enabled' => true, 'name' => $array );
286 506 }
507 + // backward compatibility for PRO before v1.9.0
508 + if ( ! array_key_exists( 'supports', $array ) ) {
509 + $array['supports'] = array( 'Google Charts' );
510 + }
287 511 if ( ! $array['enabled'] ) {
288 512 continue;
289 513 }
290 514 $filtered[ $type ] = $array;
@@ -297,13 +521,74 @@
297 521 if ( ! is_array( $array ) ) {
298 522 // support for old pro
299 523 $array = array( 'enabled' => true, 'name' => $array );
300 524 }
525 + // backward compatibility for PRO before v1.9.0
526 + if ( ! array_key_exists( 'supports', $array ) ) {
527 + $array['supports'] = array( 'Google Charts' );
528 + }
301 529 $doubleD[ $type ] = $array['name'];
302 530 }
303 531 $types = $doubleD;
304 532 }
305 533
534 + return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
535 + }
536 +
537 + /**
538 + * Handle (soon-to-be) deprecated charts.
539 + */
540 + private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
541 + $deprecated = array();
542 +
543 + switch ( $where ) {
544 + case 'types':
545 + // fall-through
546 + case 'library':
547 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
548 + if ( ! Visualizer_Module::is_pro() ) {
549 + if ( ! self::hasChartType( 'gauge' ) ) {
550 + if ( $get2Darray ) {
551 + $deprecated[] = 'gauge';
552 + } else {
553 + $types['gauge']['enabled'] = false;
554 + }
555 + }
556 + if ( ! self::hasChartType( 'candlestick' ) ) {
557 + if ( $get2Darray ) {
558 + $deprecated[] = 'candlestick';
559 + } else {
560 + $types['candlestick']['enabled'] = false;
561 + }
562 + }
563 + }
564 + break;
565 + default:
566 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
567 + if ( ! Visualizer_Module::is_pro() ) {
568 + if ( ! self::hasChartType( 'gauge' ) ) {
569 + if ( $get2Darray ) {
570 + $deprecated[] = 'gauge';
571 + } else {
572 + $types['gauge']['enabled'] = false;
573 + }
574 + }
575 + if ( ! self::hasChartType( 'candlestick' ) ) {
576 + if ( $get2Darray ) {
577 + $deprecated[] = 'candlestick';
578 + } else {
579 + $types['candlestick']['enabled'] = false;
580 + }
581 + }
582 + }
583 + }
584 +
585 + if ( $deprecated ) {
586 + foreach ( $deprecated as $type ) {
587 + unset( $types[ $type ] );
588 + }
589 + }
590 +
306 591 return $types;
307 592 }
308 593
309 594 /**
@@ -313,11 +598,11 @@
313 598 * @global string $pagenow The name of the current page.
314 599 *
315 600 * @access public
316 601 */
317 - public function renderTempaltes() {
602 + public function renderTemplates() {
318 603 global $pagenow;
319 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
604 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
320 605 return;
321 606 }
322 607 $render = new Visualizer_Render_Templates();
323 608 $render->render();
@@ -335,26 +620,41 @@
335 620 *
336 621 * @param string $suffix The current page suffix.
337 622 */
338 623 public function enqueueLibraryScripts( $suffix ) {
339 - if ( $suffix == $this->_libraryPage ) {
624 + if ( $suffix === $this->_libraryPage ) {
340 625 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
341 626 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
342 627 wp_enqueue_media();
343 628 wp_enqueue_script(
344 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
629 + 'visualizer-library',
630 + VISUALIZER_ABSURL . 'js/library.js',
631 + array(
345 632 'jquery',
346 633 'media-views',
347 - ), Visualizer_Plugin::VERSION, true
634 + 'clipboard',
635 + ),
636 + Visualizer_Plugin::VERSION,
637 + true
348 638 );
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 - );
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 + }
357 657 }
358 658 }
359 659
360 660 /**
@@ -381,24 +681,191 @@
381 681 *
382 682 * @access public
383 683 */
384 684 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 );
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.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.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 +
712 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
713 +
714 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
715 + add_action( 'admin_footer', array( $this, 'handleGetProSubMenu' ) );
388 716 }
389 717
390 718 /**
391 - * Renders visualizer library page.
392 - *
393 - * @since 1.0.0
394 - *
395 - * @access public
719 + * Handle get pro plugin submenu.
396 720 */
397 - public function renderLibraryPage() {
721 + public function handleGetProSubMenu() {
722 + if ( ! Visualizer_Module::is_pro() ) {
723 + ?>
724 + <style type="text/css">
725 + #toplevel_page_visualizer ul.wp-submenu li:last-child {
726 + background: #FF7E65;
727 + font-size: 14px;
728 + font-weight: 600;
729 + color: #fff;
730 + }
731 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a {
732 + color: #fff !important;
733 + }
734 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a:hover {
735 + box-shadow: inherit;
736 + }
737 + </style>
738 + <?php
739 + if ( get_option( 'visualizer_fresh_install', false ) ) {
740 + ?>
741 + <style type="text/css">
742 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li {
743 + display: none;
744 + }
745 + </style>
746 + <?php
747 + }
748 + }
749 + }
750 +
751 + /**
752 + * Adds the screen options for pagination.
753 + */
754 + function addScreenOptions() {
755 + $screen = get_current_screen();
756 +
757 + // bail if it's some other page.
758 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
759 + return;
760 + }
761 +
762 + $args = array(
763 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
764 + 'default' => 6,
765 + 'option' => 'visualizer_library_per_page',
766 + );
767 + add_screen_option( 'per_page', $args );
768 + }
769 +
770 + /**
771 + * Returns the screen option for pagination.
772 + */
773 + function setScreenOptions( $status, $option, $value ) {
774 + if ( 'visualizer_library_per_page' === $option ) {
775 + return $value;
776 + }
777 + }
778 +
779 + /**
780 + * Adds the display filters to be used in the meta_query while displaying the charts.
781 + */
782 + private function getDisplayFilters( &$query_args ) {
783 + $query = array();
784 + global $sitepress;
785 + if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
786 + $current_lang = icl_get_current_language();
787 + if ( in_array( $current_lang, array( 'all', icl_get_default_language() ), true ) ) {
788 + $query[] = array(
789 + 'key' => 'chart_lang',
790 + 'compare' => 'NOT EXISTS',
791 + );
792 + } else {
793 + $query[] = array(
794 + 'key' => 'chart_lang',
795 + 'value' => $current_lang,
796 + 'compare' => '=',
797 + );
798 + }
799 + }
800 +
801 + // add chart type filter to the query arguments
802 + $type = filter_input( INPUT_GET, 'type' );
803 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
804 + $query[] = array(
805 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
806 + 'value' => $type,
807 + 'compare' => '=',
808 + );
809 + }
810 +
811 + // add chart library filter to the query arguments
812 + $library = filter_input( INPUT_GET, 'library' );
813 + if ( $library ) {
814 + $query[] = array(
815 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
816 + 'value' => $library,
817 + 'compare' => '=',
818 + );
819 + }
820 +
821 + // add date filter to the query arguments
822 + $date = filter_input( INPUT_GET, 'date' );
823 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
824 + if ( $date && in_array( $date, $possible, true ) ) {
825 + $query_args['date_query'] = array(
826 + 'after' => "$date -1 day",
827 + 'inclusive' => true,
828 + );
829 + }
830 +
831 + // add source filter to the query arguments
832 + $source = filter_input( INPUT_GET, 'source' );
833 + if ( $source ) {
834 + $source = ucwords( $source );
835 + $source = "Visualizer_Source_{$source}";
836 + $query[] = array(
837 + 'key' => Visualizer_Plugin::CF_SOURCE,
838 + 'value' => $source,
839 + 'compare' => '=',
840 + );
841 + }
842 +
843 + $query_args['meta_query'] = $query;
844 +
845 + $orderby = filter_input( INPUT_GET, 'orderby' );
846 + $order = filter_input( INPUT_GET, 'order' );
847 + if ( $orderby ) {
848 + $query_args['order_by'] = $orderby;
849 + }
850 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
851 + }
852 +
853 + /**
854 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
855 + */
856 + private function getQuery() {
857 + static $q;
858 + if ( ! is_null( $q ) ) {
859 + return $q;
860 + }
861 +
398 862 // get current page
399 863 $page = filter_input(
400 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
864 + INPUT_GET,
865 + 'vpage',
866 + FILTER_VALIDATE_INT,
867 + array(
401 868 'options' => array(
402 869 'min_range' => 1,
403 870 'default' => 1,
404 871 ),
@@ -403,29 +870,34 @@
403 870 'default' => 1,
404 871 ),
405 872 )
406 873 );
874 +
875 + $per_page = 6;
876 + $screen = get_current_screen();
877 + if ( $screen ) {
878 + // retrieve the per_page option
879 + $screen_option = $screen->get_option( 'per_page', 'option' );
880 + // retrieve the value stored for the current user
881 + $user = get_current_user_id();
882 + $per_page = get_user_meta( $user, $screen_option, true );
883 + if ( empty( $per_page ) || $per_page < 1 ) {
884 + // nothing set, get the default value
885 + $per_page = $screen->get_option( 'per_page', 'default' );
886 + }
887 + }
888 +
407 889 // the initial query arguments to fetch charts
408 890 $query_args = array(
409 891 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
410 - 'posts_per_page' => 6,
892 + 'posts_per_page' => $per_page,
411 893 'paged' => $page,
412 894 );
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 - }
895 +
896 + $this->getDisplayFilters( $query_args );
897 +
426 898 // Added by Ash/Upwork
427 - $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
899 + $filterByMeta = ! empty( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
428 900 if ( $filterByMeta ) {
429 901 $query = array(
430 902 'key' => Visualizer_Plugin::CF_SETTINGS,
431 903 'value' => $filterByMeta,
@@ -434,51 +906,159 @@
434 906 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
435 907 $meta[] = $query;
436 908 $query_args['meta_query'] = $meta;
437 909 }
438 - // Added by Ash/Upwork
439 - // fetch charts
910 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
911 + return $q;
912 + }
913 +
914 + /**
915 + * Renders support page.
916 + *
917 + * @since 3.3.0
918 + *
919 + * @access public
920 + */
921 + public function renderSupportPage() {
922 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
923 + $this->load_survey();
924 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
925 + }
926 +
927 + /**
928 + * Renders visualizer library page.
929 + *
930 + * @since 1.0.0
931 + *
932 + * @access public
933 + */
934 + public function renderLibraryPage() {
440 935 $charts = array();
441 - $query = new WP_Query( $query_args );
936 + $query = $this->getQuery();
937 +
938 + // get current page
939 + $page = filter_input(
940 + INPUT_GET,
941 + 'vpage',
942 + FILTER_VALIDATE_INT,
943 + array(
944 + 'options' => array(
945 + 'min_range' => 1,
946 + 'default' => 1,
947 + ),
948 + )
949 + );
950 + // add chart type filter to the query arguments
951 + $filter = filter_input( INPUT_GET, 'type' );
952 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
953 + $filter = 'all';
954 + }
955 +
956 + $css = '';
442 957 while ( $query->have_posts() ) {
443 958 $chart = $query->next_post();
959 +
960 + // 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.
961 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
962 + // refresh a "live" db query chart.
963 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
964 +
965 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
966 +
444 967 // fetch and update settings
445 968 $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 );
969 +
970 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
971 + if ( ! empty( $atts['settings'] ) ) {
972 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
973 + }
974 +
975 + if ( $settings ) {
976 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
977 + }
978 +
448 979 $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 );
980 + $data = self::get_chart_data( $chart, $type );
981 +
982 + // Set default setting series when add manual chart data - Only during first creation.
983 + if ( isset( $settings['series'] ) && ! empty( $series ) ) {
984 + $count_series = count( $series ) - count( $settings['series'] );
985 + if ( $count_series > 1 ) {
986 + $clone_last_series = end( $settings['series'] );
987 + $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
988 + foreach ( range( 1, $count_series ) as $item ) {
989 + $settings['series'][] = $clone_last_series;
990 + }
991 + }
992 + }
993 +
994 + $library = $this->load_chart_type( $chart->ID );
995 +
996 + $id = 'visualizer-' . $chart->ID;
997 + $arguments = $this->get_inline_custom_css( $id, $settings );
998 + if ( ! empty( $arguments ) ) {
999 + $css .= $arguments[0];
1000 + $settings = $arguments[1];
1001 + }
1002 +
1003 + if ( isset( $settings['controls']['ui']['labelStacking'] ) ) {
1004 + unset( $settings['controls']['ui']['labelStacking'] );
1005 + }
1006 + if ( isset( $settings['controls']['ui']['orientation'] ) ) {
1007 + unset( $settings['controls']['ui']['orientation'] );
1008 + }
1009 +
450 1010 // add chart to the array
451 - $charts[ 'visualizer-' . $chart->ID ] = array(
1011 + $charts[ $id ] = array(
452 1012 'id' => $chart->ID,
453 1013 'type' => $type,
454 1014 'series' => $series,
455 1015 'settings' => $settings,
456 1016 'data' => $data,
1017 + 'library' => $library,
457 1018 );
458 1019 }
459 1020 // enqueue charts array
460 1021 $ajaxurl = admin_url( 'admin-ajax.php' );
461 1022 wp_localize_script(
462 - 'visualizer-library', 'visualizer', array(
1023 + 'visualizer-library',
1024 + 'visualizer',
1025 + array(
463 1026 'language' => $this->get_language(),
464 1027 'map_api_key' => get_option( 'visualizer-map-api-key' ),
465 1028 'charts' => $charts,
466 1029 '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
1030 + 'base' => esc_url( add_query_arg( array( 'vpage' => false, 'vaction' => false ) ) ),
1031 + 'create' => esc_url(
1032 + add_query_arg(
1033 + array(
1034 + 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
1035 + 'library' => 'yes',
1036 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
1037 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
1038 + 'vaction' => false,
1039 + ),
1040 + $ajaxurl
1041 + )
473 1042 ),
474 - 'edit' => add_query_arg(
475 - array(
476 - 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
477 - 'library' => 'yes',
478 - ), $ajaxurl
1043 + 'edit' => esc_url(
1044 + add_query_arg(
1045 + array(
1046 + 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
1047 + 'library' => 'yes',
1048 + 'vaction' => false,
1049 + ),
1050 + $ajaxurl
1051 + )
479 1052 ),
480 1053 ),
1054 + 'page_type' => 'library',
1055 + 'is_front' => false,
1056 + 'i10n' => array(
1057 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
1058 + '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' ),
1059 + ),
1060 + 'is_pro_user' => Visualizer_Module::is_pro(),
481 1061 )
482 1062 );
483 1063 // render library page
484 1064 $render = new Visualizer_Render_Library();
@@ -483,12 +1063,13 @@
483 1063 // render library page
484 1064 $render = new Visualizer_Render_Library();
485 1065 $render->charts = $charts;
486 1066 $render->type = $filter;
487 - $render->types = self::_getChartTypesLocalized();
1067 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
1068 + $render->custom_css = $css;
488 1069 $render->pagination = paginate_links(
489 1070 array(
490 - 'base' => add_query_arg( 'vpage', '%#%' ),
1071 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
491 1072 'format' => '',
492 1073 'current' => $page,
493 1074 'total' => $query->max_num_pages,
494 1075 'type' => 'array',
@@ -493,8 +1074,11 @@
493 1074 'total' => $query->max_num_pages,
494 1075 'type' => 'array',
495 1076 )
496 1077 );
1078 +
1079 + $this->load_survey();
1080 +
497 1081 $render->render();
498 1082 }
499 1083
500 1084 /**
@@ -509,14 +1093,14 @@
509 1093 *
510 1094 * @return array Updated array of action links.
511 1095 */
512 1096 public function getPluginActionLinks( $links, $file ) {
513 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1097 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
514 1098 array_unshift(
515 1099 $links,
516 1100 sprintf(
517 1101 '<a href="%s">%s</a>',
518 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1102 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
519 1103 esc_html__( 'Library', 'visualizer' )
520 1104 )
521 1105 );
522 1106 }
@@ -536,17 +1120,17 @@
536 1120 *
537 1121 * @return array Updated array of plugin meta links.
538 1122 */
539 1123 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
540 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1124 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
541 1125 // knowledge base link
542 1126 $plugin_meta[] = sprintf(
543 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
544 - esc_html__( 'Knowledge Base', 'visualizer' )
1127 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1128 + esc_html__( 'Docs', 'visualizer' )
545 1129 );
546 1130 // flattr link
547 1131 $plugin_meta[] = sprintf(
548 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1132 + '<a style="color:red" href="' . tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'pluginrow' ) . '" target="_blank">%s</a>',
549 1133 esc_html__( 'Pro Addon', 'visualizer' )
550 1134 );
551 1135 }
552 1136
@@ -552,5 +1136,146 @@
552 1136
553 1137 return $plugin_meta;
554 1138 }
555 1139
1140 + /**
1141 + * If check is existing user.
1142 + *
1143 + * @return bool Default false
1144 + */
1145 + public static function proFeaturesLocked() {
1146 + if ( Visualizer_Module::is_pro() ) {
1147 + return true;
1148 + }
1149 + return 'yes' === get_option( 'visualizer-new-user', 'yes' ) ? false : true;
1150 + }
1151 +
1152 + /**
1153 + * Multilingual Support.
1154 + *
1155 + * @param int $chart_id Chart ID.
1156 + * @return bool Default false
1157 + */
1158 + public function addMultilingualSupport( $chart_id ) {
1159 + global $sitepress;
1160 + if ( Visualizer_Module::is_pro() ) {
1161 + return;
1162 + }
1163 + if ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) {
1164 + $language = icl_get_languages();
1165 + $current_lang = icl_get_current_language();
1166 + $default_lang = icl_get_default_language();
1167 + $post_info = wpml_get_language_information( null, $chart_id );
1168 + $translations = array();
1169 + if ( ! empty( $post_info ) && ( $default_lang === $post_info['language_code'] ) ) {
1170 + $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
1171 + $translations = $sitepress->get_element_translations( $trid );
1172 + }
1173 + if ( empty( $translations ) ) {
1174 + return;
1175 + }
1176 + ?>
1177 + <hr><div class="visualizer-languages-list only-pro">
1178 + <?php
1179 + foreach ( $language as $lang ) {
1180 + $lang_code = $lang['code'];
1181 + if ( $current_lang !== $lang_code ) {
1182 + ?>
1183 + <a href="javascript:;">
1184 + <img src="<?php echo esc_url( $lang['country_flag_url'] ); ?>" alt="<?php echo esc_attr( $lang['translated_name'] ); ?>">
1185 + </a>
1186 + <?php
1187 + }
1188 + }
1189 + ?>
1190 + <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>
1191 + </div>
1192 + <?php
1193 + }
1194 + }
1195 +
1196 + /**
1197 + * Check chart is enabled or not.
1198 + *
1199 + * @param string $type Chart ID.
1200 + *
1201 + * @return bool Default false
1202 + */
1203 + public static function checkChartStatus( $type ) {
1204 + $types = self::_getChartTypesLocalized( false, false, false, true );
1205 + if ( isset( $types[ $type ] ) ) {
1206 + return ! empty( $types[ $type ]['enabled'] );
1207 + }
1208 + return false;
1209 + }
1210 +
1211 + /**
1212 + * Get the survey metadata.
1213 + *
1214 + * @return array The survey metadata.
1215 + */
1216 + private function get_survey_metadata() {
1217 + $install_date = get_option( 'visualizer_install', false );
1218 + $install_category = 0;
1219 +
1220 + if ( false !== $install_date ) {
1221 + $days_since_install = round( ( time() - $install_date ) / DAY_IN_SECONDS );
1222 +
1223 + if ( 0 === $days_since_install || 1 === $days_since_install ) {
1224 + $install_category = 0;
1225 + } elseif ( 1 < $days_since_install && 8 > $days_since_install ) {
1226 + $install_category = 7;
1227 + } elseif ( 8 <= $days_since_install && 31 > $days_since_install ) {
1228 + $install_category = 30;
1229 + } elseif ( 30 < $days_since_install && 90 > $days_since_install ) {
1230 + $install_category = 90;
1231 + } elseif ( 90 <= $days_since_install ) {
1232 + $install_category = 91;
1233 + }
1234 + }
1235 +
1236 + $plugin_data = get_plugin_data( VISUALIZER_BASEFILE, false, false );
1237 + $plugin_version = '';
1238 + if ( ! empty( $plugin_data['Version'] ) ) {
1239 + $plugin_version = $plugin_data['Version'];
1240 + }
1241 +
1242 + $user_id = 'visualizer_' . preg_replace( '/[^\w\d]*/', '', get_site_url() ); // Use a normalized version of the site URL as a user ID.
1243 +
1244 + $license_data = get_option( 'visualizer_pro_license_data', false );
1245 + if ( false !== $license_data && isset( $license_data->key ) ) {
1246 + $user_id = 'visualizer_' . $license_data->key;
1247 + }
1248 +
1249 + return array(
1250 + 'userId' => $user_id,
1251 + 'attributes' => array(
1252 + 'days_since_install' => strval( $install_category ),
1253 + 'free_version' => $plugin_version,
1254 + 'pro_version' => defined( 'VISUALIZER_PRO_VERSION' ) ? VISUALIZER_PRO_VERSION : '',
1255 + 'license_status' => apply_filters( 'product_visualizer_license_status', 'invalid' ),
1256 + ),
1257 + );
1258 + }
1259 +
1260 + /**
1261 + * Load the survey.
1262 + */
1263 + private function load_survey() {
1264 +
1265 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
1266 + return;
1267 + }
1268 +
1269 + $survey_handler = apply_filters( 'themeisle_sdk_dependency_script_handler', 'survey' );
1270 +
1271 + if ( empty( $survey_handler ) ) {
1272 + return;
1273 + }
1274 +
1275 + $metadata = $this->get_survey_metadata();
1276 +
1277 + do_action( 'themeisle_sdk_dependency_enqueue_script', 'survey' );
1278 + wp_enqueue_script( 'visualizer_chart_survey', VISUALIZER_ABSURL . 'js/survey.js', array( $survey_handler ), $metadata['attributes']['free_version'], true );
1279 + wp_localize_script( 'visualizer_chart_survey', 'visualizerSurveyData', $metadata );
1280 + }
556 1281 }