PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.5
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.5
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 +1205 -103 3.0.74.0.5 View file →
@@ -29,8 +29,10 @@
29 29 class Visualizer_Module_Admin extends Visualizer_Module {
30 30
31 31 const NAME = __CLASS__;
32 32
33 + const OPTION_GLOBAL_SETTINGS = 'visualizer_global_settings';
34 +
33 35 /**
34 36 * Library page suffix.
35 37 *
36 38 * @since 1.0.0
@@ -40,8 +42,24 @@
40 42 */
41 43 private $_libraryPage;
42 44
43 45 /**
46 + * Support page suffix.
47 + *
48 + * @access private
49 + * @var string
50 + */
51 + private $_supportPage;
52 +
53 + /**
54 + * Settings page suffix.
55 + *
56 + * @access private
57 + * @var string
58 + */
59 + private $_settingsPage;
60 +
61 + /**
44 62 * Constructor.
45 63 *
46 64 * @since 1.0.0
47 65 *
@@ -52,34 +70,223 @@
52 70 public function __construct( Visualizer_Plugin $plugin ) {
53 71 parent::__construct( $plugin );
54 72 $this->_addAction( 'load-post.php', 'enqueueMediaScripts' );
55 73 $this->_addAction( 'load-post-new.php', 'enqueueMediaScripts' );
56 - $this->_addAction( 'admin_footer', 'renderTempaltes' );
57 - $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 8 );
74 + $this->_addAction( 'enqueue_block_editor_assets', 'enqueueMediaScripts' );
75 + $this->_addAction( 'admin_footer', 'renderTemplates' );
76 + $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 0 );
77 + $this->_addAction( 'admin_enqueue_scripts', 'enqueue_support_page' );
78 + $this->_addAction( 'admin_enqueue_scripts', 'enqueueSettingsScripts' );
79 + $this->_addAction( 'admin_post_visualizer_save_global_settings', 'saveGlobalSettings' );
58 80 $this->_addAction( 'admin_menu', 'registerAdminMenu' );
59 81 $this->_addFilter( 'media_view_strings', 'setupMediaViewStrings' );
60 82 $this->_addFilter( 'plugin_action_links', 'getPluginActionLinks', 10, 2 );
83 + $this->_addFilter( 'plugin_row_meta', 'getPluginMetaLinks', 10, 2 );
61 84 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
62 - $this->_addFilter( 'visualizer_get_chart_counts', 'getChartCountsByTypeAndMeta' );
63 85 $this->_addFilter( 'visualizer_feedback_review_trigger', 'feedbackReviewTrigger' );
86 + $this->_addFilter( 'themeisle_sdk_blackfriday_data', 'add_black_friday_data' );
64 87
88 + // screen pagination
89 + $this->_addFilter( 'set-screen-option', 'setScreenOptions', 10, 3 );
90 +
91 + // revision support.
92 + $this->_addFilter( 'wp_revisions_to_keep', 'limitRevisions', null, 10, 2 );
93 + $this->_addAction( '_wp_put_post_revision', 'addRevision', null, 10, 1 );
94 + $this->_addAction( 'wp_restore_post_revision', 'restoreRevision', null, 10, 2 );
95 +
96 + $this->_addAction( 'visualizer_chart_schedules_spl', 'addSplChartSchedules', null, 10, 3 );
97 +
65 98 $this->_addAction( 'admin_init', 'init' );
99 +
100 + $this->_addAction( 'visualizer_chart_languages', 'addMultilingualSupport' );
101 +
102 + $this->_addFilter( 'admin_footer_text', 'render_review_notice' );
103 +
104 + if ( ! defined( 'TI_E2E_TESTING' ) ) {
105 + $this->_addFilter( 'themeisle-sdk/survey/' . VISUALIZER_DIRNAME, 'get_survey_metadata', 10, 2 );
106 + }
107 +
108 + if ( defined( 'TI_E2E_TESTING' ) ) {
109 + $this->load_cypress_hooks();
110 + }
66 111 }
112 + /**
113 + * Display review notice.
114 + */
115 + public function render_review_notice( $footer_text ) {
116 + $current_screen = get_current_screen();
67 117
118 + $visualizer_page_ids = array( 'toplevel_page_visualizer', 'visualizer_page_viz-support', 'visualizer_page_ti-about-visualizer' );
119 +
120 + if ( ! empty( $current_screen ) && isset( $current_screen->id ) ) {
121 + foreach ( $visualizer_page_ids as $page_to_check ) {
122 + if ( strpos( $current_screen->id, $page_to_check ) !== false ) {
123 + $footer_text = sprintf(
124 + // translators: %1$s - the name of the plugin (Visualizer), %2$s - message (You can help us by leaving a), %3$s - HTML entity code.
125 + __( 'Enjoying %1$s? %2$s %3$s rating. Thank you for being so supportive!', 'visualizer' ),
126 + '<b>Visualizer</b>',
127 + esc_html__( 'You can help us by leaving a', 'visualizer' ),
128 + '<a href="https://wordpress.org/support/plugin/visualizer/reviews/#new-post" target="_blank">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
129 + );
130 + break;
131 + }
132 + }
133 + }
134 +
135 + return $footer_text;
136 + }
137 +
138 +
68 139 /**
140 + * Define the hooks that are needed for cypress.
141 + *
142 + * @since 3.4.0
143 + * @access private
144 + */
145 + private function load_cypress_hooks() {
146 + // all charts should load on the same page without pagination.
147 + add_filter(
148 + 'visualizer_query_args', function ( $args ) {
149 + $args['posts_per_page'] = 20;
150 + return $args;
151 + }, 10, 1
152 + );
153 + }
154 +
155 + /**
156 + * Add disabled `optgroup` schedules to the drop downs.
157 + *
158 + * @since ?
159 + *
160 + * @access public
161 + *
162 + * @param string $feature The feature for which to add schedules.
163 + * @param int $chart_id The chart ID.
164 + * @param int $plan The plan number.
165 + */
166 + public function addSplChartSchedules( $feature, $chart_id, $plan ) {
167 + if ( apply_filters( 'visualizer_is_business', false ) ) {
168 + return;
169 + }
170 +
171 + $is_new_personal = apply_filters( 'visualizer_is_new_personal', false );
172 +
173 + $hours = array(
174 + '0.16' => __( '10 minutes', 'visualizer' ),
175 + '1' => __( 'Each hour', 'visualizer' ),
176 + '12' => __( 'Each 12 hours', 'visualizer' ),
177 + '24' => __( 'Each day', 'visualizer' ),
178 + '72' => __( 'Each 3 days', 'visualizer' ),
179 + );
180 +
181 + switch ( $feature ) {
182 + case 'json':
183 + case 'csv':
184 + // no more schedules if pro is already active.
185 + if ( Visualizer_Module::is_pro() && ! $is_new_personal ) {
186 + return;
187 + }
188 + break;
189 + case 'wp':
190 + // fall-through.
191 + case 'db':
192 + break;
193 + default:
194 + return;
195 + }
196 +
197 + echo '<optgroup disabled label="' . __( 'Upgrade required', 'visualizer' ) . '">';
198 + foreach ( $hours as $hour => $desc ) {
199 + echo '<option disabled>' . $desc . '</option>';
200 + }
201 + echo '</optgroup>';
202 + }
203 +
204 + /**
205 + * No limits on revisions.
206 + */
207 + public function limitRevisions( $num, $post ) {
208 + if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
209 + return -1;
210 + }
211 + return $num;
212 + }
213 +
214 + /**
215 + * Add a revision.
216 + */
217 + public function addRevision( $revision_id ) {
218 + $parent_id = wp_is_post_revision( $revision_id );
219 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $parent_id ) ) {
220 + // add the meta data to this revision.
221 + $meta = get_post_meta( $parent_id, '', true );
222 +
223 + if ( $meta ) {
224 + foreach ( $meta as $key => $value ) {
225 + if ( 0 === strpos( $key, 'visualizer' ) ) {
226 + add_metadata( 'post', $revision_id, $key, maybe_unserialize( $value[0] ) );
227 + }
228 + }
229 + }
230 + }
231 + }
232 +
233 + /**
234 + * Restore a revision.
235 + */
236 + public function restoreRevision( $post_id, $revision_id ) {
237 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $post_id ) ) {
238 + // get the meta information from the revision.
239 + $meta = get_metadata( 'post', $revision_id, '', true );
240 +
241 + // delete all meta information from the post before adding.
242 + $post_meta = get_post_meta( $post_id, '', true );
243 + if ( $post_meta ) {
244 + foreach ( $meta as $key => $value ) {
245 + if ( 0 === strpos( $key, 'visualizer' ) ) {
246 + delete_post_meta( $post_id, $key );
247 + }
248 + }
249 + }
250 +
251 + if ( $meta ) {
252 + foreach ( $meta as $key => $value ) {
253 + if ( 0 === strpos( $key, 'visualizer' ) ) {
254 + add_post_meta( $post_id, $key, maybe_unserialize( $value[0] ) );
255 + }
256 + }
257 + }
258 + }
259 + }
260 +
261 + /**
69 262 * Admin init.
70 263 *
71 264 * @access public
72 265 */
73 266 public function init() {
74 - if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
267 + if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' === get_user_option( 'rich_editing' ) ) {
75 268 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
76 269 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
77 270 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
271 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
78 272 }
79 273 }
80 274
81 275 /**
276 + * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
277 + *
278 + * @since ?
279 + * @access friendly
280 + */
281 + public function get_strings_for_block( $settings ) {
282 + $class = new Visualizer_Module_Language();
283 + $strings = $class->get_strings();
284 + $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
285 + return array_merge( $settings, $array );
286 + }
287 +
288 + /**
82 289 * Load plugin translation for - TinyMCE API
83 290 *
84 291 * @access public
85 292 * @param array $arr The tinymce_lang array.
@@ -148,20 +355,52 @@
148 355 * @access public
149 356 */
150 357 public function enqueueMediaScripts() {
151 358 global $typenow;
152 - if ( post_type_supports( $typenow, 'editor' ) ) {
359 + global $current_screen;
360 +
361 + if ( post_type_supports( $typenow, 'editor' ) || $current_screen->id === 'widgets' || $current_screen->id === 'customize' ) {
153 362 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 );
363 +
364 + $d3_renderer_asset = VISUALIZER_ABSPATH . '/classes/Visualizer/D3Renderer/build/index.asset.php';
365 + if ( file_exists( $d3_renderer_asset ) && ! wp_script_is( 'visualizer-d3-renderer', 'registered' ) ) {
366 + // @phpstan-ignore-next-line
367 + $d3_asset = include $d3_renderer_asset;
368 + wp_register_script(
369 + 'visualizer-d3-renderer',
370 + VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/index.js',
371 + array_merge( $d3_asset['dependencies'], array( 'jquery' ) ),
372 + $d3_asset['version'],
373 + true
374 + );
375 + }
376 + if ( wp_script_is( 'visualizer-d3-renderer', 'registered' ) ) {
377 + wp_enqueue_script( 'visualizer-d3-renderer' );
378 + wp_localize_script(
379 + 'visualizer-d3-renderer',
380 + 'vizD3Renderer',
381 + array(
382 + 'iframeJsUrl' => VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/iframe.js',
383 + )
384 + );
385 + }
386 +
387 + // Load all the assets for the different libraries we support.
388 + $deps = array(
389 + Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
390 + Visualizer_Render_Sidebar_Type_DataTable_Tabular::enqueue_assets( array( 'media-editor' ) ),
391 + );
392 +
393 + wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
157 394 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
158 395 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
159 396 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
160 397 wp_localize_script(
161 - 'visualizer-media-view', 'visualizer', array(
398 + 'visualizer-media-view',
399 + 'visualizer',
400 + array(
162 401 'i10n' => array(
163 - 'insert' => __( 'Insert', 'visualizer' ),
402 + 'insert' => __( 'Insert Chart', 'visualizer' ),
164 403 ),
165 404 )
166 405 );
167 406 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
@@ -190,9 +429,9 @@
190 429 'controller' => array(
191 430 'title' => esc_html__( 'Visualizations', 'visualizer' ),
192 431 ),
193 432 'routers' => array(
194 - 'library' => esc_html__( 'From Library', 'visualizer' ),
433 + 'library' => esc_html__( 'Insert from Library', 'visualizer' ),
195 434 'create' => esc_html__( 'Create New', 'visualizer' ),
196 435 ),
197 436 'library' => array(
198 437 'filters' => $chart_types,
@@ -198,9 +437,9 @@
198 437 'filters' => $chart_types,
199 438 'types' => array_keys( $chart_types ),
200 439 ),
201 440 'nonce' => wp_create_nonce(),
202 - 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
441 + 'buildurl' => esc_url( add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ) ),
203 442 );
204 443
205 444 return $strings;
206 445 }
@@ -213,9 +452,9 @@
213 452 * @static
214 453 * @access private
215 454 * @return array The associated array of chart types with localized names.
216 455 */
217 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false ) {
456 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
218 457 $additional = array();
219 458 if ( $add_select ) {
220 459 $additional['select'] = array(
221 460 'name' => esc_html__( 'All', 'visualizer' ),
@@ -222,59 +461,102 @@
222 461 'enabled' => true,
223 462 );
224 463 }
225 464
465 + $enabled = self::proFeaturesEnabled();
466 +
226 467 $types = array_merge(
227 - $additional, array(
468 + $additional,
469 + array(
470 + 'tabular' => array(
471 + 'name' => esc_html__( 'Table', 'visualizer' ),
472 + 'enabled' => true,
473 + 'supports' => $enabled ? array( 'Google Charts', 'DataTable' ) : array( 'DataTable' ),
474 + ),
228 475 'pie' => array(
229 - 'name' => esc_html__( 'Pie', 'visualizer' ),
476 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
230 477 'enabled' => true,
478 + 'supports' => array( 'Google Charts', 'ChartJS' ),
231 479 ),
232 480 'line' => array(
233 481 'name' => esc_html__( 'Line', 'visualizer' ),
234 482 'enabled' => true,
483 + 'supports' => array( 'Google Charts', 'ChartJS' ),
235 484 ),
485 + 'bar' => array(
486 + 'name' => esc_html__( 'Bar', 'visualizer' ),
487 + 'enabled' => true,
488 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
489 + ),
236 490 'area' => array(
237 491 'name' => esc_html__( 'Area', 'visualizer' ),
238 - 'enabled' => true,
492 + 'enabled' => $enabled,
493 + // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
494 + 'supports' => array( 'Google Charts' ),
495 + 'demo_url' => 'https://demo.themeisle.com/visualizer/area-chart/',
239 496 ),
240 497 'geo' => array(
241 498 'name' => esc_html__( 'Geo', 'visualizer' ),
242 - 'enabled' => true,
499 + 'enabled' => $enabled,
500 + 'supports' => array( 'Google Charts' ),
501 + 'demo_url' => 'https://demo.themeisle.com/visualizer/geo-chart/',
243 502 ),
244 - 'bar' => array(
245 - 'name' => esc_html__( 'Bar', 'visualizer' ),
246 - 'enabled' => true,
247 - ),
248 503 'column' => array(
249 504 'name' => esc_html__( 'Column', 'visualizer' ),
250 - 'enabled' => true,
505 + 'enabled' => $enabled,
506 + 'supports' => array( 'Google Charts', 'ChartJS' ),
507 + 'demo_url' => 'https://demo.themeisle.com/visualizer/column-chart/',
251 508 ),
252 - 'gauge' => array(
253 - 'name' => esc_html__( 'Gauge', 'visualizer' ),
254 - 'enabled' => true,
509 + 'bubble' => array(
510 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
511 + 'enabled' => $enabled,
512 + // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
513 + 'supports' => array( 'Google Charts' ),
514 + 'demo_url' => 'https://demo.themeisle.com/visualizer/bubble-chart/',
255 515 ),
256 516 'scatter' => array(
257 517 'name' => esc_html__( 'Scatter', 'visualizer' ),
258 - 'enabled' => true,
518 + 'enabled' => $enabled,
519 + 'supports' => array( 'Google Charts' ),
520 + 'demo_url' => 'https://demo.themeisle.com/visualizer/scatter-chart/',
259 521 ),
522 + 'gauge' => array(
523 + 'name' => esc_html__( 'Gauge', 'visualizer' ),
524 + 'enabled' => $enabled,
525 + 'supports' => array( 'Google Charts' ),
526 + 'demo_url' => 'https://demo.themeisle.com/visualizer/gauge-chart/',
527 + ),
260 528 'candlestick' => array(
261 529 'name' => esc_html__( 'Candlestick', 'visualizer' ),
262 - 'enabled' => true,
530 + 'enabled' => $enabled,
531 + 'supports' => array( 'Google Charts' ),
532 + 'demo_url' => 'https://demo.themeisle.com/visualizer/candlestick-chart/',
263 533 ),
264 534 // pro types
265 - 'table' => array(
266 - 'name' => esc_html__( 'Table', 'visualizer' ),
267 - 'enabled' => false,
268 - ),
269 535 'timeline' => array(
270 536 'name' => esc_html__( 'Timeline', 'visualizer' ),
271 537 'enabled' => false,
538 + 'supports' => array( 'Google Charts', 'ChartJS' ),
539 + 'demo_url' => 'https://demo.themeisle.com/visualizer/timeline-chart/',
272 540 ),
273 541 'combo' => array(
274 542 'name' => esc_html__( 'Combo', 'visualizer' ),
275 543 'enabled' => false,
544 + 'supports' => array( 'Google Charts' ),
545 + 'demo_url' => 'https://demo.themeisle.com/visualizer/combo-chart/',
276 546 ),
547 + 'polarArea' => array(
548 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
549 + 'enabled' => false,
550 + 'supports' => array( 'ChartJS' ),
551 + 'demo_url' => 'https://demo.themeisle.com/visualizer/polar-area-chart/',
552 + ),
553 + 'radar' => array(
554 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
555 + 'enabled' => false,
556 + 'supports' => array( 'ChartJS' ),
557 + 'demo_url' => 'https://demo.themeisle.com/visualizer/radar-spider-chart/',
558 + ),
277 559 )
278 560 );
279 561 $types = apply_filters( 'visualizer_pro_chart_types', $types );
280 562 if ( $enabledOnly ) {
@@ -283,8 +565,12 @@
283 565 if ( ! is_array( $array ) ) {
284 566 // support for old pro
285 567 $array = array( 'enabled' => true, 'name' => $array );
286 568 }
569 + // backward compatibility for PRO before v1.9.0
570 + if ( ! array_key_exists( 'supports', $array ) ) {
571 + $array['supports'] = array( 'Google Charts' );
572 + }
287 573 if ( ! $array['enabled'] ) {
288 574 continue;
289 575 }
290 576 $filtered[ $type ] = $array;
@@ -297,13 +583,74 @@
297 583 if ( ! is_array( $array ) ) {
298 584 // support for old pro
299 585 $array = array( 'enabled' => true, 'name' => $array );
300 586 }
587 + // backward compatibility for PRO before v1.9.0
588 + if ( ! array_key_exists( 'supports', $array ) ) {
589 + $array['supports'] = array( 'Google Charts' );
590 + }
301 591 $doubleD[ $type ] = $array['name'];
302 592 }
303 593 $types = $doubleD;
304 594 }
305 595
596 + return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
597 + }
598 +
599 + /**
600 + * Handle (soon-to-be) deprecated charts.
601 + */
602 + private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
603 + $deprecated = array();
604 +
605 + switch ( $where ) {
606 + case 'types':
607 + // fall-through
608 + case 'library':
609 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
610 + if ( ! Visualizer_Module::is_pro() ) {
611 + if ( ! self::hasChartType( 'gauge' ) ) {
612 + if ( $get2Darray ) {
613 + $deprecated[] = 'gauge';
614 + } else {
615 + $types['gauge']['enabled'] = false;
616 + }
617 + }
618 + if ( ! self::hasChartType( 'candlestick' ) ) {
619 + if ( $get2Darray ) {
620 + $deprecated[] = 'candlestick';
621 + } else {
622 + $types['candlestick']['enabled'] = false;
623 + }
624 + }
625 + }
626 + break;
627 + default:
628 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
629 + if ( ! Visualizer_Module::is_pro() ) {
630 + if ( ! self::hasChartType( 'gauge' ) ) {
631 + if ( $get2Darray ) {
632 + $deprecated[] = 'gauge';
633 + } else {
634 + $types['gauge']['enabled'] = false;
635 + }
636 + }
637 + if ( ! self::hasChartType( 'candlestick' ) ) {
638 + if ( $get2Darray ) {
639 + $deprecated[] = 'candlestick';
640 + } else {
641 + $types['candlestick']['enabled'] = false;
642 + }
643 + }
644 + }
645 + }
646 +
647 + if ( $deprecated ) {
648 + foreach ( $deprecated as $type ) {
649 + unset( $types[ $type ] );
650 + }
651 + }
652 +
306 653 return $types;
307 654 }
308 655
309 656 /**
@@ -313,11 +660,11 @@
313 660 * @global string $pagenow The name of the current page.
314 661 *
315 662 * @access public
316 663 */
317 - public function renderTempaltes() {
664 + public function renderTemplates() {
318 665 global $pagenow;
319 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
666 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
320 667 return;
321 668 }
322 669 $render = new Visualizer_Render_Templates();
323 670 $render->render();
@@ -335,30 +682,159 @@
335 682 *
336 683 * @param string $suffix The current page suffix.
337 684 */
338 685 public function enqueueLibraryScripts( $suffix ) {
339 - if ( $suffix == $this->_libraryPage ) {
340 - wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
341 - $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
342 - wp_enqueue_media();
686 + if ( $suffix !== $this->_libraryPage ) {
687 + return;
688 + }
689 +
690 + wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
691 + $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
692 + wp_enqueue_media();
693 + wp_enqueue_script(
694 + 'visualizer-library',
695 + VISUALIZER_ABSURL . 'js/library.js',
696 + array(
697 + 'jquery',
698 + 'media-views',
699 + 'clipboard',
700 + ),
701 + Visualizer_Plugin::VERSION,
702 + true
703 + );
704 +
705 + wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
706 +
707 + $has_d3 = false;
708 + $query = $this->getQuery();
709 + while ( $query->have_posts() ) {
710 + $chart = $query->next_post();
711 + $library = $this->load_chart_type( $chart->ID );
712 + if ( is_null( $library ) ) {
713 + continue;
714 + }
343 715 wp_enqueue_script(
344 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
345 - 'jquery',
346 - 'media-views',
347 - ), Visualizer_Plugin::VERSION, true
716 + "visualizer-render-$library",
717 + VISUALIZER_ABSURL . 'js/render-facade.js',
718 + apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
719 + Visualizer_Plugin::VERSION,
720 + true
348 721 );
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 );
722 + if ( 'd3' === $library ) {
723 + $has_d3 = true;
724 + }
725 + }
726 +
727 + if ( $has_d3 ) {
728 + $d3_renderer_asset = VISUALIZER_ABSPATH . '/classes/Visualizer/D3Renderer/build/index.asset.php';
729 + if ( file_exists( $d3_renderer_asset ) && ! wp_script_is( 'visualizer-d3-renderer', 'registered' ) ) {
730 + /**
731 + * Ignore missing build asset in source checkout.
732 + *
733 + * @phpstan-ignore-next-line
734 + */
735 + $d3_asset = include $d3_renderer_asset;
736 + wp_register_script(
737 + 'visualizer-d3-renderer',
738 + VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/index.js',
739 + array_merge( $d3_asset['dependencies'], array( 'jquery' ) ),
740 + $d3_asset['version'],
741 + true
742 + );
743 + wp_enqueue_script( 'visualizer-d3-renderer' );
744 + }
745 + wp_localize_script(
746 + 'visualizer-d3-renderer',
747 + 'vizD3Renderer',
748 + array(
749 + 'iframeJsUrl' => VISUALIZER_ABSURL . 'classes/Visualizer/D3Renderer/build/iframe.js',
750 + )
751 + );
752 + }
753 +
754 + $chart_builder_asset = VISUALIZER_ABSPATH . '/classes/Visualizer/ChartBuilder/build/index.asset.php';
755 + if ( file_exists( $chart_builder_asset ) ) {
756 + /**
757 + * Ignore missing build asset in source checkout.
758 + *
759 + * @phpstan-ignore-next-line
760 + */
761 + $asset = include $chart_builder_asset;
762 + $chart_builder_deps = $asset['dependencies'];
763 + if ( ! wp_script_is( 'visualizer-handsontable', 'registered' ) && defined( 'Visualizer_Pro_ABSURL' ) && defined( 'VISUALIZER_PRO_VERSION' ) ) {
764 + wp_register_script(
765 + 'visualizer-handsontable',
766 + Visualizer_Pro_ABSURL . 'vendor/handsontable/dist/handsontable.full.min.js',
767 + array(),
768 + VISUALIZER_PRO_VERSION,
769 + true
770 + );
771 + }
772 + if ( ! wp_style_is( 'visualizer-handsontable', 'registered' ) && defined( 'Visualizer_Pro_ABSURL' ) && defined( 'VISUALIZER_PRO_VERSION' ) ) {
773 + wp_register_style(
774 + 'visualizer-handsontable',
775 + Visualizer_Pro_ABSURL . 'vendor/handsontable/dist/handsontable.full.min.css',
776 + array(),
777 + VISUALIZER_PRO_VERSION
778 + );
779 + }
780 + if ( wp_script_is( 'visualizer-handsontable', 'registered' ) ) {
781 + wp_enqueue_script( 'visualizer-handsontable' );
782 + $chart_builder_deps = array_unique( array_merge( $chart_builder_deps, array( 'visualizer-handsontable' ) ) );
783 + }
784 + if ( wp_style_is( 'visualizer-handsontable', 'registered' ) ) {
785 + wp_enqueue_style( 'visualizer-handsontable' );
786 + }
351 787 wp_enqueue_script(
352 - 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array(
353 - 'google-jsapi-old',
354 - 'visualizer-library',
355 - ), Visualizer_Plugin::VERSION, true
788 + 'visualizer-chart-builder',
789 + VISUALIZER_ABSURL . 'classes/Visualizer/ChartBuilder/build/index.js',
790 + $chart_builder_deps,
791 + $asset['version'],
792 + true
356 793 );
794 + wp_enqueue_style(
795 + 'visualizer-chart-builder',
796 + VISUALIZER_ABSURL . 'classes/Visualizer/ChartBuilder/build/style-index.css',
797 + array(),
798 + $asset['version']
799 + );
800 + $chart_builder_css = VISUALIZER_ABSPATH . '/classes/Visualizer/ChartBuilder/build/index.css';
801 + if ( file_exists( $chart_builder_css ) ) {
802 + wp_enqueue_style(
803 + 'visualizer-chart-builder-runtime',
804 + VISUALIZER_ABSURL . 'classes/Visualizer/ChartBuilder/build/index.css',
805 + array( 'visualizer-chart-builder' ),
806 + $asset['version']
807 + );
808 + }
809 + wp_localize_script(
810 + 'visualizer-chart-builder',
811 + 'vizAIBuilder',
812 + array(
813 + 'ajaxUrl' => admin_url( 'admin-ajax.php' ),
814 + 'nonce' => wp_create_nonce( 'visualizer-ai-builder' ),
815 + 'isPro' => Visualizer_Module::is_pro(),
816 + 'upgradeUrl' => tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'aiBuilderUpgrade', 'dataSource' ),
817 + )
818 + );
357 819 }
820 +
821 + do_action( 'themeisle_internal_page', VISUALIZER_DIRNAME, 'library' );
358 822 }
359 823
360 824 /**
825 + * Enqueue script for support page.
826 + *
827 + * @param string $hook_suffix Current hook.
828 + */
829 + public function enqueue_support_page( $hook_suffix ) {
830 + if ( $this->_supportPage !== $hook_suffix ) {
831 + return;
832 + }
833 + do_action( 'themeisle_internal_page', VISUALIZER_DIRNAME, 'support' );
834 + }
835 +
836 + /**
361 837 * Adds visualizer tab for media upload tabs array.
362 838 *
363 839 * @since 1.0.0
364 840 *
@@ -381,24 +857,201 @@
381 857 *
382 858 * @access public
383 859 */
384 860 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 );
861 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
862 +
863 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
864 +
865 + add_submenu_page(
866 + Visualizer_Plugin::NAME,
867 + __( 'Chart Library', 'visualizer' ),
868 + __( 'Chart Library', 'visualizer' ),
869 + 'edit_posts',
870 + 'admin.php?page=' . Visualizer_Plugin::NAME
871 + );
872 + add_submenu_page(
873 + Visualizer_Plugin::NAME,
874 + __( 'Add New Chart', 'visualizer' ),
875 + __( 'Add New Chart', 'visualizer' ),
876 + 'edit_posts',
877 + 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew'
878 + );
879 +
880 + $this->_settingsPage = add_submenu_page(
881 + Visualizer_Plugin::NAME,
882 + __( 'Settings', 'visualizer' ),
883 + __( 'Settings', 'visualizer' ),
884 + 'manage_options',
885 + 'viz-settings',
886 + array( $this, 'renderSettingsPage' )
887 + );
888 +
889 + $this->_supportPage = add_submenu_page(
890 + Visualizer_Plugin::NAME,
891 + __( 'Support', 'visualizer' ),
892 + __( '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>',
893 + 'edit_posts',
894 + 'viz-support',
895 + array( $this, 'renderSupportPage' )
896 + );
897 +
898 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
899 +
900 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
901 + add_action( 'admin_footer', array( $this, 'handleGetProSubMenu' ) );
388 902 }
389 903
390 904 /**
391 - * Renders visualizer library page.
392 - *
393 - * @since 1.0.0
394 - *
395 - * @access public
905 + * Handle get pro plugin submenu.
396 906 */
397 - public function renderLibraryPage() {
907 + public function handleGetProSubMenu() {
908 + if ( ! Visualizer_Module::is_pro() ) {
909 + ?>
910 + <style type="text/css">
911 + #toplevel_page_visualizer ul.wp-submenu li:last-child {
912 + background: #FF7E65;
913 + font-size: 14px;
914 + font-weight: 600;
915 + color: #fff;
916 + }
917 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a > span {
918 + color: #fff !important;
919 + }
920 + #toplevel_page_visualizer ul.wp-submenu li:last-child > a:hover {
921 + box-shadow: inherit;
922 + }
923 + </style>
924 + <?php
925 + if ( get_option( 'visualizer_fresh_install', false ) ) {
926 + ?>
927 + <style type="text/css">
928 + #toplevel_page_visualizer ul.wp-submenu li.wp-first-item + li + li + li {
929 + display: none;
930 + }
931 + </style>
932 + <?php
933 + }
934 + }
935 + }
936 +
937 + /**
938 + * Adds the screen options for pagination.
939 + */
940 + public function addScreenOptions() {
941 + $screen = get_current_screen();
942 +
943 + // bail if it's some other page.
944 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
945 + return;
946 + }
947 +
948 + $args = array(
949 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
950 + 'default' => 6,
951 + 'option' => 'visualizer_library_per_page',
952 + );
953 + add_screen_option( 'per_page', $args );
954 + }
955 +
956 + /**
957 + * Returns the screen option for pagination.
958 + */
959 + public function setScreenOptions( $status, $option, $value ) {
960 + if ( 'visualizer_library_per_page' === $option ) {
961 + return $value;
962 + }
963 + }
964 +
965 + /**
966 + * Adds the display filters to be used in the meta_query while displaying the charts.
967 + */
968 + private function getDisplayFilters( &$query_args ) {
969 + $query = array();
970 + global $sitepress;
971 + if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
972 + $current_lang = icl_get_current_language();
973 + if ( in_array( $current_lang, array( 'all', icl_get_default_language() ), true ) ) {
974 + $query[] = array(
975 + 'key' => 'chart_lang',
976 + 'compare' => 'NOT EXISTS',
977 + );
978 + } else {
979 + $query[] = array(
980 + 'key' => 'chart_lang',
981 + 'value' => $current_lang,
982 + 'compare' => '=',
983 + );
984 + }
985 + }
986 +
987 + // add chart type filter to the query arguments
988 + $type = filter_input( INPUT_GET, 'type' );
989 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
990 + $query[] = array(
991 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
992 + 'value' => $type,
993 + 'compare' => '=',
994 + );
995 + }
996 +
997 + // add chart library filter to the query arguments
998 + $library = filter_input( INPUT_GET, 'library' );
999 + if ( $library ) {
1000 + $query[] = array(
1001 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
1002 + 'value' => $library,
1003 + 'compare' => '=',
1004 + );
1005 + }
1006 +
1007 + // add date filter to the query arguments
1008 + $date = filter_input( INPUT_GET, 'date' );
1009 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
1010 + if ( $date && in_array( $date, $possible, true ) ) {
1011 + $query_args['date_query'] = array(
1012 + 'after' => "$date -1 day",
1013 + 'inclusive' => true,
1014 + );
1015 + }
1016 +
1017 + // add source filter to the query arguments
1018 + $source = filter_input( INPUT_GET, 'source' );
1019 + if ( $source ) {
1020 + $source = ucwords( $source );
1021 + $source = "Visualizer_Source_{$source}";
1022 + $query[] = array(
1023 + 'key' => Visualizer_Plugin::CF_SOURCE,
1024 + 'value' => $source,
1025 + 'compare' => '=',
1026 + );
1027 + }
1028 +
1029 + $query_args['meta_query'] = $query;
1030 +
1031 + $orderby = filter_input( INPUT_GET, 'orderby' );
1032 + $order = filter_input( INPUT_GET, 'order' );
1033 + if ( $orderby ) {
1034 + $query_args['order_by'] = $orderby;
1035 + }
1036 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
1037 + }
1038 +
1039 + /**
1040 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
1041 + */
1042 + private function getQuery() {
1043 + static $q;
1044 + if ( ! is_null( $q ) ) {
1045 + return $q;
1046 + }
1047 +
398 1048 // get current page
399 1049 $page = filter_input(
400 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
1050 + INPUT_GET,
1051 + 'vpage',
1052 + FILTER_VALIDATE_INT,
1053 + array(
401 1054 'options' => array(
402 1055 'min_range' => 1,
403 1056 'default' => 1,
404 1057 ),
@@ -403,29 +1056,34 @@
403 1056 'default' => 1,
404 1057 ),
405 1058 )
406 1059 );
1060 +
1061 + $per_page = 6;
1062 + $screen = get_current_screen();
1063 + if ( $screen ) {
1064 + // retrieve the per_page option
1065 + $screen_option = $screen->get_option( 'per_page', 'option' );
1066 + // retrieve the value stored for the current user
1067 + $user = get_current_user_id();
1068 + $per_page = get_user_meta( $user, $screen_option, true );
1069 + if ( empty( $per_page ) || $per_page < 1 ) {
1070 + // nothing set, get the default value
1071 + $per_page = $screen->get_option( 'per_page', 'default' );
1072 + }
1073 + }
1074 +
407 1075 // the initial query arguments to fetch charts
408 1076 $query_args = array(
409 1077 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
410 - 'posts_per_page' => 6,
1078 + 'posts_per_page' => $per_page,
411 1079 'paged' => $page,
412 1080 );
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 - }
1081 +
1082 + $this->getDisplayFilters( $query_args );
1083 +
426 1084 // Added by Ash/Upwork
427 - $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
1085 + $filterByMeta = ! empty( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : null; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
428 1086 if ( $filterByMeta ) {
429 1087 $query = array(
430 1088 'key' => Visualizer_Plugin::CF_SETTINGS,
431 1089 'value' => $filterByMeta,
@@ -434,51 +1092,246 @@
434 1092 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
435 1093 $meta[] = $query;
436 1094 $query_args['meta_query'] = $meta;
437 1095 }
438 - // Added by Ash/Upwork
439 - // fetch charts
1096 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
1097 + return $q;
1098 + }
1099 +
1100 + /**
1101 + * Renders support page.
1102 + *
1103 + * @since 3.3.0
1104 + *
1105 + * @access public
1106 + */
1107 + public function renderSupportPage() {
1108 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
1109 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
1110 + }
1111 +
1112 + /**
1113 + * Enqueues scripts/styles for the Settings page.
1114 + *
1115 + * @access public
1116 + */
1117 + public function enqueueSettingsScripts( string $hook_suffix ): void {
1118 + if ( $this->_settingsPage !== $hook_suffix ) {
1119 + return;
1120 + }
1121 + wp_enqueue_style( 'wp-color-picker' );
1122 + wp_enqueue_script( 'wp-color-picker' );
1123 + }
1124 +
1125 + /**
1126 + * Renders the global style settings page.
1127 + *
1128 + * @access public
1129 + */
1130 + public function renderSettingsPage(): void {
1131 + if ( ! current_user_can( 'manage_options' ) ) {
1132 + wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'visualizer' ) );
1133 + }
1134 + $settings = self::getGlobalSettings();
1135 + include_once VISUALIZER_ABSPATH . '/templates/global-settings.php';
1136 + }
1137 +
1138 + /**
1139 + * Returns the global style settings option.
1140 + *
1141 + * @return array<string, string>
1142 + * @access public
1143 + * @static
1144 + */
1145 + public static function getGlobalSettings(): array {
1146 + $defaults = array(
1147 + 'color_primary' => '',
1148 + 'color_secondary' => '',
1149 + 'apply_existing' => '0',
1150 + );
1151 + $saved = get_option( self::OPTION_GLOBAL_SETTINGS, array() );
1152 + return wp_parse_args( $saved, $defaults );
1153 + }
1154 +
1155 + /**
1156 + * Handles saving of the global style settings.
1157 + *
1158 + * @access public
1159 + */
1160 + public function saveGlobalSettings(): void {
1161 + if ( ! current_user_can( 'manage_options' ) ) {
1162 + wp_die( esc_html__( 'You do not have sufficient permissions to access this page.', 'visualizer' ) );
1163 + }
1164 +
1165 + check_admin_referer( 'visualizer_save_global_settings' );
1166 +
1167 + $color_primary = sanitize_hex_color( wp_unslash( $_POST['visualizer_color_primary'] ?? '' ) );
1168 + $color_secondary = sanitize_hex_color( wp_unslash( $_POST['visualizer_color_secondary'] ?? '' ) );
1169 + $apply_existing = ! empty( $_POST['visualizer_apply_existing'] ) ? '1' : '0';
1170 + $clear = ! empty( $_POST['visualizer_clear_settings'] );
1171 +
1172 + if ( $clear ) {
1173 + delete_option( self::OPTION_GLOBAL_SETTINGS );
1174 + } else {
1175 + $settings = array(
1176 + 'color_primary' => $color_primary ? $color_primary : '',
1177 + 'color_secondary' => $color_secondary ? $color_secondary : '',
1178 + 'apply_existing' => $apply_existing,
1179 + );
1180 + update_option( self::OPTION_GLOBAL_SETTINGS, $settings );
1181 + }
1182 +
1183 + wp_safe_redirect(
1184 + add_query_arg(
1185 + array(
1186 + 'page' => 'viz-settings',
1187 + 'updated' => $clear ? 'cleared' : 'true',
1188 + ),
1189 + admin_url( 'admin.php' )
1190 + )
1191 + );
1192 + exit;
1193 + }
1194 +
1195 + /**
1196 + * Renders visualizer library page.
1197 + *
1198 + * @since 1.0.0
1199 + *
1200 + * @access public
1201 + */
1202 + public function renderLibraryPage() {
440 1203 $charts = array();
441 - $query = new WP_Query( $query_args );
1204 + $query = $this->getQuery();
1205 +
1206 + // get current page
1207 + $page = filter_input(
1208 + INPUT_GET,
1209 + 'vpage',
1210 + FILTER_VALIDATE_INT,
1211 + array(
1212 + 'options' => array(
1213 + 'min_range' => 1,
1214 + 'default' => 1,
1215 + ),
1216 + )
1217 + );
1218 + // add chart type filter to the query arguments
1219 + $filter = filter_input( INPUT_GET, 'type' );
1220 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
1221 + $filter = 'all';
1222 + }
1223 +
1224 + $css = '';
442 1225 while ( $query->have_posts() ) {
443 1226 $chart = $query->next_post();
1227 +
1228 + // 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.
1229 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
1230 + // refresh a "live" db query chart.
1231 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
1232 +
1233 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
1234 +
444 1235 // fetch and update settings
445 1236 $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 );
1237 +
1238 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
1239 + if ( ! empty( $atts['settings'] ) ) {
1240 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
1241 + }
1242 +
1243 + if ( $settings ) {
1244 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
1245 + }
1246 +
448 1247 $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 );
1248 + $data = self::get_chart_data( $chart, $type );
1249 +
1250 + // Set default setting series when add manual chart data - Only during first creation.
1251 + if ( isset( $settings['series'] ) && ! empty( $series ) ) {
1252 + $count_series = count( $series ) - count( $settings['series'] );
1253 + if ( $count_series > 1 ) {
1254 + $clone_last_series = end( $settings['series'] );
1255 + $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
1256 + foreach ( range( 1, $count_series ) as $item ) {
1257 + $settings['series'][] = $clone_last_series;
1258 + }
1259 + }
1260 + }
1261 +
1262 + $library = $this->load_chart_type( $chart->ID );
1263 +
1264 + $id = 'visualizer-' . $chart->ID;
1265 + $arguments = $this->get_inline_custom_css( $id, $settings );
1266 + if ( ! empty( $arguments ) ) {
1267 + $css .= $arguments[0];
1268 + $settings = $arguments[1];
1269 + }
1270 +
1271 + if ( isset( $settings['controls']['ui']['labelStacking'] ) ) {
1272 + unset( $settings['controls']['ui']['labelStacking'] );
1273 + }
1274 + if ( isset( $settings['controls']['ui']['orientation'] ) ) {
1275 + unset( $settings['controls']['ui']['orientation'] );
1276 + }
1277 +
450 1278 // add chart to the array
451 - $charts[ 'visualizer-' . $chart->ID ] = array(
1279 + $charts[ $id ] = array(
452 1280 'id' => $chart->ID,
1281 + 'title' => $chart->post_title,
453 1282 'type' => $type,
454 1283 'series' => $series,
455 1284 'settings' => $settings,
456 1285 'data' => $data,
1286 + 'library' => $library,
457 1287 );
1288 + if ( 'd3' === $library ) {
1289 + $charts[ $id ]['code'] = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
1290 + }
458 1291 }
459 1292 // enqueue charts array
460 1293 $ajaxurl = admin_url( 'admin-ajax.php' );
1294 +
461 1295 wp_localize_script(
462 - 'visualizer-library', 'visualizer', array(
1296 + 'visualizer-library',
1297 + 'visualizer',
1298 + array(
463 1299 'language' => $this->get_language(),
464 1300 'map_api_key' => get_option( 'visualizer-map-api-key' ),
465 1301 'charts' => $charts,
466 1302 '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
1303 + 'base' => esc_url( add_query_arg( array( 'vpage' => false, 'vaction' => false ) ) ),
1304 + 'create' => esc_url(
1305 + add_query_arg(
1306 + array(
1307 + 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
1308 + 'library' => 'yes',
1309 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
1310 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
1311 + 'vaction' => false,
1312 + ),
1313 + $ajaxurl
1314 + )
473 1315 ),
474 - 'edit' => add_query_arg(
475 - array(
476 - 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
477 - 'library' => 'yes',
478 - ), $ajaxurl
1316 + 'edit' => esc_url(
1317 + add_query_arg(
1318 + array(
1319 + 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
1320 + 'library' => 'yes',
1321 + 'vaction' => false,
1322 + ),
1323 + $ajaxurl
1324 + )
479 1325 ),
480 1326 ),
1327 + 'page_type' => 'library',
1328 + 'is_front' => false,
1329 + 'i10n' => array(
1330 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
1331 + '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' ),
1332 + ),
1333 + 'is_pro_user' => Visualizer_Module::is_pro(),
481 1334 )
482 1335 );
483 1336 // render library page
484 1337 $render = new Visualizer_Render_Library();
@@ -483,12 +1336,13 @@
483 1336 // render library page
484 1337 $render = new Visualizer_Render_Library();
485 1338 $render->charts = $charts;
486 1339 $render->type = $filter;
487 - $render->types = self::_getChartTypesLocalized();
1340 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
1341 + $render->custom_css = $css;
488 1342 $render->pagination = paginate_links(
489 1343 array(
490 - 'base' => add_query_arg( 'vpage', '%#%' ),
1344 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
491 1345 'format' => '',
492 1346 'current' => $page,
493 1347 'total' => $query->max_num_pages,
494 1348 'type' => 'array',
@@ -493,8 +1347,9 @@
493 1347 'total' => $query->max_num_pages,
494 1348 'type' => 'array',
495 1349 )
496 1350 );
1351 +
497 1352 $render->render();
498 1353 }
499 1354
500 1355 /**
@@ -509,14 +1364,14 @@
509 1364 *
510 1365 * @return array Updated array of action links.
511 1366 */
512 1367 public function getPluginActionLinks( $links, $file ) {
513 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1368 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
514 1369 array_unshift(
515 1370 $links,
516 1371 sprintf(
517 1372 '<a href="%s">%s</a>',
518 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1373 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
519 1374 esc_html__( 'Library', 'visualizer' )
520 1375 )
521 1376 );
522 1377 }
@@ -536,21 +1391,268 @@
536 1391 *
537 1392 * @return array Updated array of plugin meta links.
538 1393 */
539 1394 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
540 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1395 + if ( Visualizer_Module::is_pro() ) {
1396 + return $plugin_meta;
1397 + }
1398 +
1399 + // Also suppress the upsell when Pro is installed but not currently active.
1400 + if ( ! function_exists( 'get_plugins' ) ) {
1401 + require_once ABSPATH . 'wp-admin/includes/plugin.php';
1402 + }
1403 + foreach ( array_keys( get_plugins() ) as $installed_plugin ) {
1404 + if ( false !== strpos( $installed_plugin, 'visualizer-pro' ) ) {
1405 + return $plugin_meta;
1406 + }
1407 + }
1408 +
1409 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
1410 + $is_black_friday = apply_filters( 'themeisle_sdk_is_black_friday_sale', false );
541 1411 // knowledge base link
542 1412 $plugin_meta[] = sprintf(
543 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
544 - esc_html__( 'Knowledge Base', 'visualizer' )
1413 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1414 + esc_html__( 'Docs', 'visualizer' )
545 1415 );
546 - // flattr link
547 - $plugin_meta[] = sprintf(
548 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
549 - esc_html__( 'Pro Addon', 'visualizer' )
550 - );
1416 + if ( ! $is_black_friday ) {
1417 + // flattr link
1418 + $plugin_meta[] = sprintf(
1419 + '<a style="color:red" href="' . tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'pluginrow' ) . '" target="_blank">%s</a>',
1420 + esc_html__( 'Get Visualizer Pro', 'visualizer' )
1421 + );
1422 + }
551 1423 }
552 1424
553 1425 return $plugin_meta;
554 1426 }
555 1427
1428 + /**
1429 + * Returns true when premium chart types should be enabled for the current user.
1430 + *
1431 + * Pro 1.9.0+ hooks the 'visualizer_is_pro' filter and returns true only when
1432 + * the license is valid. Pre-1.9.0 Pro defined a Visualizer_Pro class instead;
1433 + * we detect that as a fallback so those legacy installs still work.
1434 + *
1435 + * Passing false as the filter default ensures the constant VISUALIZER_PRO
1436 + * (which is set to true whenever the Pro class exists, regardless of license
1437 + * state) cannot bypass the license check.
1438 + *
1439 + * @return bool
1440 + */
1441 + public static function proFeaturesEnabled() {
1442 + $is_pro_filter = apply_filters( 'visualizer_is_pro', false );
1443 +
1444 + // Pro 1.9.0+: filter is hooked and returns true only with a valid license.
1445 + if ( $is_pro_filter ) {
1446 + return true;
1447 + }
1448 +
1449 + // Pro is installed (active) but the license check above did not pass.
1450 + // Do NOT fall through to the legacy "old user" path — that path exists
1451 + // only for sites that never had Pro installed. If Pro is present but
1452 + // the license is inactive we should lock, regardless of chart history.
1453 + if ( class_exists( 'Visualizer_Pro', false ) ) {
1454 + return false;
1455 + }
1456 +
1457 + // No Pro installed at all: grant legacy access to existing users so
1458 + // their charts are not suddenly broken when they upgrade the free plugin.
1459 + return 'yes' === get_option( 'visualizer-new-user' ) ? false : true;
1460 + }
1461 +
1462 + /**
1463 + * Multilingual Support.
1464 + *
1465 + * @param int $chart_id Chart ID.
1466 + * @return bool Default false
1467 + */
1468 + public function addMultilingualSupport( $chart_id ) {
1469 + global $sitepress;
1470 + if ( Visualizer_Module::is_pro() ) {
1471 + return;
1472 + }
1473 + if ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) {
1474 + $language = icl_get_languages();
1475 + $current_lang = icl_get_current_language();
1476 + $default_lang = icl_get_default_language();
1477 + $post_info = wpml_get_language_information( null, $chart_id );
1478 + $translations = array();
1479 + if ( ! empty( $post_info ) && ( $default_lang === $post_info['language_code'] ) ) {
1480 + $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
1481 + $translations = $sitepress->get_element_translations( $trid );
1482 + }
1483 + if ( empty( $translations ) ) {
1484 + return;
1485 + }
1486 + ?>
1487 + <hr><div class="visualizer-languages-list only-pro">
1488 + <?php
1489 + foreach ( $language as $lang ) {
1490 + $lang_code = $lang['code'];
1491 + if ( $current_lang !== $lang_code ) {
1492 + ?>
1493 + <a href="javascript:;">
1494 + <img src="<?php echo esc_url( $lang['country_flag_url'] ); ?>" alt="<?php echo esc_attr( $lang['translated_name'] ); ?>">
1495 + </a>
1496 + <?php
1497 + }
1498 + }
1499 + ?>
1500 + <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>
1501 + </div>
1502 + <?php
1503 + }
1504 + }
1505 +
1506 + /**
1507 + * Check chart is enabled or not.
1508 + *
1509 + * @param string $type Chart ID.
1510 + *
1511 + * @return bool Default false
1512 + */
1513 + public static function checkChartStatus( $type ) {
1514 + $types = self::_getChartTypesLocalized( false, false, false, true );
1515 + if ( isset( $types[ $type ] ) ) {
1516 + return ! empty( $types[ $type ]['enabled'] );
1517 + }
1518 + return false;
1519 + }
1520 +
1521 + /**
1522 + * Get the survey metadata.
1523 + *
1524 + * @param array $data The data for survey in Formbricks format.
1525 + * @param string $page_slug The slug of the loaded page.
1526 + *
1527 + * @return array The survey metadata.
1528 + */
1529 + public function get_survey_metadata( $data, $page_slug ) {
1530 + $install_date = get_option( 'visualizer_install', time() );
1531 + $install_days_number = intval( ( time() - $install_date ) / DAY_IN_SECONDS );
1532 +
1533 + $license_status = apply_filters( 'product_visualizer_license_status', 'invalid' );
1534 + $license_plan = apply_filters( 'product_visualizer_license_plan', false );
1535 + $license_key = apply_filters( 'product_visualizer_license_key', false );
1536 +
1537 + $plugin_data = get_plugin_data( VISUALIZER_BASEFILE, false, false );
1538 + $plugin_version = '';
1539 +
1540 + if ( ! empty( $plugin_data['Version'] ) ) {
1541 + $plugin_version = $plugin_data['Version'];
1542 + }
1543 +
1544 + $count_charts_cache_key = 'visualizer_count_charts';
1545 + $charts_number = get_transient( $count_charts_cache_key );
1546 +
1547 + if ( false === $charts_number ) {
1548 + $charts_number = $this->count_charts( 100 );
1549 + set_transient( $count_charts_cache_key, $charts_number, 100 === $charts_number ? WEEK_IN_SECONDS : 6 * HOUR_IN_SECONDS );
1550 + } else {
1551 + $charts_number = strval( $charts_number );
1552 + }
1553 +
1554 + $data = array(
1555 + 'environmentId' => 'cltef8cut1s7wyyfxy3rlxzs5',
1556 + 'attributes' => array(
1557 + 'free_version' => $plugin_version,
1558 + 'pro_version' => defined( 'VISUALIZER_PRO_VERSION' ) ? VISUALIZER_PRO_VERSION : '',
1559 + 'license_status' => $license_status,
1560 + 'install_days_number' => $install_days_number,
1561 + 'charts_number' => $charts_number,
1562 + ),
1563 + );
1564 +
1565 + if ( ! empty( $license_plan ) ) {
1566 + $data['attributes']['plan'] = $license_plan;
1567 + }
1568 +
1569 + if ( ! empty( $license_key ) ) {
1570 + $data['attributes']['license_key'] = apply_filters( 'themeisle_sdk_secret_masking', $license_key );
1571 + }
1572 +
1573 + return $data;
1574 + }
1575 +
1576 + /**
1577 + * Count the charts.
1578 + *
1579 + * @param int $limit The count limit (optional).
1580 + *
1581 + * @return int The number of charts.
1582 + */
1583 + public function count_charts( $limit = -1 ) {
1584 + $args = array(
1585 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
1586 + 'post_status' => 'publish',
1587 + 'posts_per_page' => $limit,
1588 + 'fields' => 'ids',
1589 + );
1590 +
1591 + $query = new WP_Query( $args);
1592 + return $query->post_count;
1593 + }
1594 +
1595 + /**
1596 + * Set the black friday data.
1597 + *
1598 + * @param array $configs The configuration array for the loaded products.
1599 + * @return array
1600 + */
1601 + public function add_black_friday_data( $configs ) {
1602 + $config = $configs['default'];
1603 +
1604 + $message = __( 'Database queries, private charts, auto-sync. Go beyond basic charts. Exclusively for existing Visualizer users.', 'visualizer' );
1605 + $cta_label = __( 'Get Visualizer Pro', 'visualizer' );
1606 +
1607 + $plan = apply_filters( 'product_visualizer_license_plan', 0 );
1608 + $license = apply_filters( 'product_visualizer_license_key', false );
1609 + $status = apply_filters( 'product_visualizer_license_status', false );
1610 + $pro_product_slug = defined( 'VISUALIZER_PRO_BASEFILE' ) ? basename( dirname( VISUALIZER_PRO_BASEFILE ) ) : '';
1611 +
1612 + $is_pro = 'valid' === $status;
1613 + $is_expired = 'expired' === $status || 'active-expired' === $status;
1614 +
1615 + if ( $is_pro ) {
1616 + // translators: %s is the discount percentage.
1617 + $config['plugin_meta_message'] = sprintf( __( 'Black Friday Sale - up to %s off', 'visualizer' ), '30%' );
1618 + // translators: %1$s - discount, %2$s - discount.
1619 + $message = sprintf( __( 'Upgrade your Visualizer Pro plan: %1$s off this week. Already on the plan you need? Renew early and save up to %2$s.', 'visualizer' ), '30%', '20%' );
1620 + $cta_label = __( 'See your options', 'visualizer' );
1621 + } elseif ( $is_expired ) {
1622 + // translators: %s is the discount percentage.
1623 + $config['upgrade_menu_text'] = sprintf( __( 'BF Sale - %s off', 'visualizer' ), '50%' );
1624 + // translators: %s is the discount percentage.
1625 + $config['plugin_meta_message'] = sprintf( __( 'Black Friday Sale - %s off', 'visualizer' ), '50%' );
1626 + $message = __( 'Your Visualizer Pro features are still here, just locked. Renew at a reduced rate this week.', 'visualizer' );
1627 + $cta_label = __( 'Reactivate now', 'visualizer' );
1628 + } else {
1629 + // translators: %s is the discount percentage.
1630 + $config['plugin_meta_message'] = sprintf( __( 'Black Friday Sale - %s off', 'visualizer' ), '60%' );
1631 + $config['title'] = __( 'Visualizer Pro: 60% off this week', 'visualizer' );
1632 + // translators: %s is the discount percentage.
1633 + $config['upgrade_menu_text'] = sprintf( __( 'BF Sale - %s off', 'visualizer' ), '60%' );
1634 + }
1635 +
1636 + $url_params = array(
1637 + 'utm_term' => $is_pro ? 'plan-' . $plan : 'free',
1638 + 'lkey' => ! empty( $license ) ? $license : false,
1639 + 'expired' => $is_expired ? '1' : false,
1640 + );
1641 +
1642 + if ( ( $is_pro || $is_expired ) && ! empty( $pro_product_slug ) ) {
1643 + $config['plugin_meta_targets'] = array( $pro_product_slug );
1644 + }
1645 +
1646 + $config['message'] = $message;
1647 + $config['cta_label'] = $cta_label;
1648 +
1649 + $config['sale_url'] = add_query_arg(
1650 + $url_params,
1651 + tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/vizualizer-bf', 'bfcm', 'visualizer' ) )
1652 + );
1653 +
1654 + $configs[ VISUALIZER_DIRNAME ] = $config;
1655 +
1656 + return $configs;
1657 + }
556 1658 }