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