PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.0
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 +1280 -130 3.0.54.0.0 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,19 +70,261 @@
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' );
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 +
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 + }
64 111 }
112 + /**
113 + * Display review notice.
114 + */
115 + public function render_review_notice( $footer_text ) {
116 + $current_screen = get_current_screen();
65 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 +
66 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 + /**
262 + * Admin init.
263 + *
264 + * @access public
265 + */
266 + public function init() {
267 + if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' === get_user_option( 'rich_editing' ) ) {
268 + $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
269 + $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
270 + $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
271 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
272 + }
273 + }
274 +
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 + /**
289 + * Load plugin translation for - TinyMCE API
290 + *
291 + * @access public
292 + * @param array $arr The tinymce_lang array.
293 + * @return array
294 + */
295 + public function add_tinymce_lang( $arr ) {
296 + $ui_lang = VISUALIZER_ABSPATH . '/classes/Visualizer/Module/Language.php';
297 + $ui_lang = apply_filters( 'visualizer_ui_lang_filter', $ui_lang );
298 + $arr[] = $ui_lang;
299 + return $arr;
300 + }
301 +
302 + /**
303 + * Load custom js options - TinyMCE API
304 + *
305 + * @access public
306 + * @param array $plugin_array The tinymce plugin array.
307 + * @return array
308 + */
309 + public function tinymce_plugin( $plugin_array ) {
310 + $plugin_array['visualizer_mce_button'] = VISUALIZER_ABSURL . 'js/mce.js';
311 + return $plugin_array;
312 + }
313 +
314 + /**
315 + * Register new button in the editor
316 + *
317 + * @access public
318 + * @param array $buttons The tinymce buttons array.
319 + * @return array
320 + */
321 + public function register_mce_button( $buttons ) {
322 + array_push( $buttons, 'visualizer_mce_button' );
323 + return $buttons;
324 + }
325 +
326 + /**
67 327 * Whether to show the feedback review or not.
68 328 *
69 329 * @access public
70 330 */
@@ -95,16 +355,55 @@
95 355 * @access public
96 356 */
97 357 public function enqueueMediaScripts() {
98 358 global $typenow;
99 - 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' ) {
100 362 wp_enqueue_style( 'visualizer-media', VISUALIZER_ABSURL . 'css/media.css', array( 'media-views' ), Visualizer_Plugin::VERSION );
101 - wp_enqueue_script( 'visualizer-google-jsapi-new', '//www.gstatic.com/charts/loader.js', array( 'media-editor' ), null, true );
102 - wp_enqueue_script( 'visualizer-google-jsapi-old', '//www.google.com/jsapi', array( 'visualizer-google-jsapi-new' ), null, true );
103 - 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 );
104 394 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
105 395 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
106 396 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
397 + wp_localize_script(
398 + 'visualizer-media-view',
399 + 'visualizer',
400 + array(
401 + 'i10n' => array(
402 + 'insert' => __( 'Insert Chart', 'visualizer' ),
403 + ),
404 + )
405 + );
107 406 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
108 407 wp_enqueue_script( 'visualizer-media', VISUALIZER_ABSURL . 'js/media.js', array( 'visualizer-media-toolbar' ), Visualizer_Plugin::VERSION, true );
109 408 }
110 409 }
@@ -120,8 +419,9 @@
120 419 *
121 420 * @return array The extended array of media view strings.
122 421 */
123 422 public function setupMediaViewStrings( $strings ) {
423 + $chart_types = self::_getChartTypesLocalized( true, true, true );
124 424 $strings['visualizer'] = array(
125 425 'actions' => array(
126 426 'get_charts' => Visualizer_Plugin::ACTION_GET_CHARTS,
127 427 'delete_chart' => Visualizer_Plugin::ACTION_DELETE_CHART,
@@ -129,17 +429,17 @@
129 429 'controller' => array(
130 430 'title' => esc_html__( 'Visualizations', 'visualizer' ),
131 431 ),
132 432 'routers' => array(
133 - 'library' => esc_html__( 'From Library', 'visualizer' ),
433 + 'library' => esc_html__( 'Insert from Library', 'visualizer' ),
134 434 'create' => esc_html__( 'Create New', 'visualizer' ),
135 435 ),
136 436 'library' => array(
137 - 'filters' => self::_getChartTypesLocalized( true, true ),
138 - 'types' => array_keys( self::_getChartTypesLocalized( true, true ) ),
437 + 'filters' => $chart_types,
438 + 'types' => array_keys( $chart_types ),
139 439 ),
140 440 'nonce' => wp_create_nonce(),
141 - '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' ) ) ),
142 442 );
143 443
144 444 return $strings;
145 445 }
@@ -152,59 +452,112 @@
152 452 * @static
153 453 * @access private
154 454 * @return array The associated array of chart types with localized names.
155 455 */
156 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false ) {
157 - $types = array(
158 - 'pie' => array(
159 - 'name' => esc_html__( 'Pie', 'visualizer' ),
456 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
457 + $additional = array();
458 + if ( $add_select ) {
459 + $additional['select'] = array(
460 + 'name' => esc_html__( 'All', 'visualizer' ),
160 461 'enabled' => true,
161 - ),
162 - 'line' => array(
163 - 'name' => esc_html__( 'Line', 'visualizer' ),
164 - 'enabled' => true,
165 - ),
166 - 'area' => array(
167 - 'name' => esc_html__( 'Area', 'visualizer' ),
168 - 'enabled' => true,
169 - ),
170 - 'geo' => array(
171 - 'name' => esc_html__( 'Geo', 'visualizer' ),
172 - 'enabled' => true,
173 - ),
174 - 'bar' => array(
175 - 'name' => esc_html__( 'Bar', 'visualizer' ),
176 - 'enabled' => true,
177 - ),
178 - 'column' => array(
179 - 'name' => esc_html__( 'Column', 'visualizer' ),
180 - 'enabled' => true,
181 - ),
182 - 'gauge' => array(
183 - 'name' => esc_html__( 'Gauge', 'visualizer' ),
184 - 'enabled' => true,
185 - ),
186 - 'scatter' => array(
187 - 'name' => esc_html__( 'Scatter', 'visualizer' ),
188 - 'enabled' => true,
189 - ),
190 - 'candlestick' => array(
191 - 'name' => esc_html__( 'Candlestick', 'visualizer' ),
192 - 'enabled' => true,
193 - ),
194 - // pro types
195 - 'table' => array(
196 - 'name' => esc_html__( 'Table', 'visualizer' ),
197 - 'enabled' => false,
198 - ),
199 - 'timeline' => array(
200 - 'name' => esc_html__( 'Timeline', 'visualizer' ),
201 - 'enabled' => false,
202 - ),
203 - 'combo' => array(
204 - 'name' => esc_html__( 'Combo', 'visualizer' ),
205 - 'enabled' => false,
206 - ),
462 + );
463 + }
464 +
465 + $enabled = self::proFeaturesEnabled();
466 +
467 + $types = array_merge(
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 + ),
475 + 'pie' => array(
476 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
477 + 'enabled' => true,
478 + 'supports' => array( 'Google Charts', 'ChartJS' ),
479 + ),
480 + 'line' => array(
481 + 'name' => esc_html__( 'Line', 'visualizer' ),
482 + 'enabled' => true,
483 + 'supports' => array( 'Google Charts', 'ChartJS' ),
484 + ),
485 + 'bar' => array(
486 + 'name' => esc_html__( 'Bar', 'visualizer' ),
487 + 'enabled' => true,
488 + 'supports' => $enabled ? array( 'Google Charts', 'ChartJS' ) : array( 'Google Charts' ),
489 + ),
490 + 'area' => array(
491 + 'name' => esc_html__( 'Area', 'visualizer' ),
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/',
496 + ),
497 + 'geo' => array(
498 + 'name' => esc_html__( 'Geo', 'visualizer' ),
499 + 'enabled' => $enabled,
500 + 'supports' => array( 'Google Charts' ),
501 + 'demo_url' => 'https://demo.themeisle.com/visualizer/geo-chart/',
502 + ),
503 + 'column' => array(
504 + 'name' => esc_html__( 'Column', 'visualizer' ),
505 + 'enabled' => $enabled,
506 + 'supports' => array( 'Google Charts', 'ChartJS' ),
507 + 'demo_url' => 'https://demo.themeisle.com/visualizer/column-chart/',
508 + ),
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/',
515 + ),
516 + 'scatter' => array(
517 + 'name' => esc_html__( 'Scatter', 'visualizer' ),
518 + 'enabled' => $enabled,
519 + 'supports' => array( 'Google Charts' ),
520 + 'demo_url' => 'https://demo.themeisle.com/visualizer/scatter-chart/',
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 + ),
528 + 'candlestick' => array(
529 + 'name' => esc_html__( 'Candlestick', 'visualizer' ),
530 + 'enabled' => $enabled,
531 + 'supports' => array( 'Google Charts' ),
532 + 'demo_url' => 'https://demo.themeisle.com/visualizer/candlestick-chart/',
533 + ),
534 + // pro types
535 + 'timeline' => array(
536 + 'name' => esc_html__( 'Timeline', 'visualizer' ),
537 + 'enabled' => false,
538 + 'supports' => array( 'Google Charts', 'ChartJS' ),
539 + 'demo_url' => 'https://demo.themeisle.com/visualizer/timeline-chart/',
540 + ),
541 + 'combo' => array(
542 + 'name' => esc_html__( 'Combo', 'visualizer' ),
543 + 'enabled' => false,
544 + 'supports' => array( 'Google Charts' ),
545 + 'demo_url' => 'https://demo.themeisle.com/visualizer/combo-chart/',
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 + ),
559 + )
207 560 );
208 561 $types = apply_filters( 'visualizer_pro_chart_types', $types );
209 562 if ( $enabledOnly ) {
210 563 $filtered = array();
@@ -212,8 +565,12 @@
212 565 if ( ! is_array( $array ) ) {
213 566 // support for old pro
214 567 $array = array( 'enabled' => true, 'name' => $array );
215 568 }
569 + // backward compatibility for PRO before v1.9.0
570 + if ( ! array_key_exists( 'supports', $array ) ) {
571 + $array['supports'] = array( 'Google Charts' );
572 + }
216 573 if ( ! $array['enabled'] ) {
217 574 continue;
218 575 }
219 576 $filtered[ $type ] = $array;
@@ -226,13 +583,74 @@
226 583 if ( ! is_array( $array ) ) {
227 584 // support for old pro
228 585 $array = array( 'enabled' => true, 'name' => $array );
229 586 }
587 + // backward compatibility for PRO before v1.9.0
588 + if ( ! array_key_exists( 'supports', $array ) ) {
589 + $array['supports'] = array( 'Google Charts' );
590 + }
230 591 $doubleD[ $type ] = $array['name'];
231 592 }
232 593 $types = $doubleD;
233 594 }
234 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 +
235 653 return $types;
236 654 }
237 655
238 656 /**
@@ -242,11 +660,11 @@
242 660 * @global string $pagenow The name of the current page.
243 661 *
244 662 * @access public
245 663 */
246 - public function renderTempaltes() {
664 + public function renderTemplates() {
247 665 global $pagenow;
248 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
666 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
249 667 return;
250 668 }
251 669 $render = new Visualizer_Render_Templates();
252 670 $render->render();
@@ -264,30 +682,159 @@
264 682 *
265 683 * @param string $suffix The current page suffix.
266 684 */
267 685 public function enqueueLibraryScripts( $suffix ) {
268 - if ( $suffix == $this->_libraryPage ) {
269 - wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
270 - $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
271 - 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 + }
272 715 wp_enqueue_script(
273 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
274 - 'jquery',
275 - 'media-views',
276 - ), 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
277 721 );
278 - wp_enqueue_script( 'google-jsapi-new', '//www.gstatic.com/charts/loader.js', array(), null, true );
279 - 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 + }
280 787 wp_enqueue_script(
281 - 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array(
282 - 'google-jsapi-old',
283 - 'visualizer-library',
284 - ), 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
285 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 + );
286 819 }
820 +
821 + do_action( 'themeisle_internal_page', VISUALIZER_DIRNAME, 'library' );
287 822 }
288 823
289 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 + /**
290 837 * Adds visualizer tab for media upload tabs array.
291 838 *
292 839 * @since 1.0.0
293 840 *
@@ -310,24 +857,201 @@
310 857 *
311 858 * @access public
312 859 */
313 860 public function registerAdminMenu() {
314 - $title = esc_html__( 'Visualizer Library', 'visualizer' );
315 - $callback = array( $this, 'renderLibraryPage' );
316 - $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' ) );
317 902 }
318 903
319 904 /**
320 - * Renders visualizer library page.
321 - *
322 - * @since 1.0.0
323 - *
324 - * @access public
905 + * Handle get pro plugin submenu.
325 906 */
326 - 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 +
327 1048 // get current page
328 1049 $page = filter_input(
329 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
1050 + INPUT_GET,
1051 + 'vpage',
1052 + FILTER_VALIDATE_INT,
1053 + array(
330 1054 'options' => array(
331 1055 'min_range' => 1,
332 1056 'default' => 1,
333 1057 ),
@@ -332,29 +1056,34 @@
332 1056 'default' => 1,
333 1057 ),
334 1058 )
335 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 +
336 1075 // the initial query arguments to fetch charts
337 1076 $query_args = array(
338 1077 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
339 - 'posts_per_page' => 6,
1078 + 'posts_per_page' => $per_page,
340 1079 'paged' => $page,
341 1080 );
342 - // add chart type filter to the query arguments
343 - $filter = filter_input( INPUT_GET, 'type' );
344 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
345 - $query_args['meta_query'] = array(
346 - array(
347 - 'key' => Visualizer_Plugin::CF_CHART_TYPE,
348 - 'value' => $filter,
349 - 'compare' => '=',
350 - ),
351 - );
352 - } else {
353 - $filter = 'all';
354 - }
1081 +
1082 + $this->getDisplayFilters( $query_args );
1083 +
355 1084 // Added by Ash/Upwork
356 - $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
357 1086 if ( $filterByMeta ) {
358 1087 $query = array(
359 1088 'key' => Visualizer_Plugin::CF_SETTINGS,
360 1089 'value' => $filterByMeta,
@@ -363,49 +1092,246 @@
363 1092 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
364 1093 $meta[] = $query;
365 1094 $query_args['meta_query'] = $meta;
366 1095 }
367 - // Added by Ash/Upwork
368 - // 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() {
369 1203 $charts = array();
370 - $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 = '';
371 1225 while ( $query->have_posts() ) {
372 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 +
373 1235 // fetch and update settings
374 1236 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
375 - unset( $settings['height'], $settings['width'] );
376 - $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 +
377 1247 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
378 - $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 +
379 1278 // add chart to the array
380 - $charts[ 'visualizer-' . $chart->ID ] = array(
1279 + $charts[ $id ] = array(
381 1280 'id' => $chart->ID,
1281 + 'title' => $chart->post_title,
382 1282 'type' => $type,
383 1283 'series' => $series,
384 1284 'settings' => $settings,
385 1285 'data' => $data,
1286 + 'library' => $library,
386 1287 );
1288 + if ( 'd3' === $library ) {
1289 + $charts[ $id ]['code'] = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
1290 + }
387 1291 }
388 1292 // enqueue charts array
389 1293 $ajaxurl = admin_url( 'admin-ajax.php' );
1294 +
390 1295 wp_localize_script(
391 - 'visualizer-library', 'visualizer', array(
1296 + 'visualizer-library',
1297 + 'visualizer',
1298 + array(
1299 + 'language' => $this->get_language(),
1300 + 'map_api_key' => get_option( 'visualizer-map-api-key' ),
392 1301 'charts' => $charts,
393 1302 'urls' => array(
394 - 'base' => add_query_arg( 'vpage', false ),
395 - 'create' => add_query_arg(
396 - array(
397 - 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
398 - 'library' => 'yes',
399 - ), $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 + )
400 1315 ),
401 - 'edit' => add_query_arg(
402 - array(
403 - 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
404 - 'library' => 'yes',
405 - ), $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 + )
406 1325 ),
407 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(),
408 1334 )
409 1335 );
410 1336 // render library page
411 1337 $render = new Visualizer_Render_Library();
@@ -410,12 +1336,13 @@
410 1336 // render library page
411 1337 $render = new Visualizer_Render_Library();
412 1338 $render->charts = $charts;
413 1339 $render->type = $filter;
414 - $render->types = self::_getChartTypesLocalized();
1340 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
1341 + $render->custom_css = $css;
415 1342 $render->pagination = paginate_links(
416 1343 array(
417 - 'base' => add_query_arg( 'vpage', '%#%' ),
1344 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
418 1345 'format' => '',
419 1346 'current' => $page,
420 1347 'total' => $query->max_num_pages,
421 1348 'type' => 'array',
@@ -420,8 +1347,9 @@
420 1347 'total' => $query->max_num_pages,
421 1348 'type' => 'array',
422 1349 )
423 1350 );
1351 +
424 1352 $render->render();
425 1353 }
426 1354
427 1355 /**
@@ -436,14 +1364,14 @@
436 1364 *
437 1365 * @return array Updated array of action links.
438 1366 */
439 1367 public function getPluginActionLinks( $links, $file ) {
440 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1368 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
441 1369 array_unshift(
442 1370 $links,
443 1371 sprintf(
444 1372 '<a href="%s">%s</a>',
445 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1373 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
446 1374 esc_html__( 'Library', 'visualizer' )
447 1375 )
448 1376 );
449 1377 }
@@ -463,18 +1391,32 @@
463 1391 *
464 1392 * @return array Updated array of plugin meta links.
465 1393 */
466 1394 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
467 - 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 ) ) {
468 1410 // knowledge base link
469 1411 $plugin_meta[] = sprintf(
470 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
471 - esc_html__( 'Knowledge Base', 'visualizer' )
1412 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1413 + esc_html__( 'Docs', 'visualizer' )
472 1414 );
473 1415 // flattr link
474 1416 $plugin_meta[] = sprintf(
475 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
476 - esc_html__( 'Pro Addon', 'visualizer' )
1417 + '<a style="color:red" href="' . tsdk_utmify( Visualizer_Plugin::PRO_TEASER_URL, 'pluginrow' ) . '" target="_blank">%s</a>',
1418 + esc_html__( 'Get Visualizer Pro', 'visualizer' )
477 1419 );
478 1420 }
479 1421
480 1422 return $plugin_meta;
@@ -479,5 +1421,213 @@
479 1421
480 1422 return $plugin_meta;
481 1423 }
482 1424
1425 + /**
1426 + * Returns true when premium chart types should be enabled for the current user.
1427 + *
1428 + * Pro 1.9.0+ hooks the 'visualizer_is_pro' filter and returns true only when
1429 + * the license is valid. Pre-1.9.0 Pro defined a Visualizer_Pro class instead;
1430 + * we detect that as a fallback so those legacy installs still work.
1431 + *
1432 + * Passing false as the filter default ensures the constant VISUALIZER_PRO
1433 + * (which is set to true whenever the Pro class exists, regardless of license
1434 + * state) cannot bypass the license check.
1435 + *
1436 + * @return bool
1437 + */
1438 + public static function proFeaturesEnabled() {
1439 + $is_pro_filter = apply_filters( 'visualizer_is_pro', false );
1440 +
1441 + // Pro 1.9.0+: filter is hooked and returns true only with a valid license.
1442 + if ( $is_pro_filter ) {
1443 + return true;
1444 + }
1445 +
1446 + // Pro is installed (active) but the license check above did not pass.
1447 + // Do NOT fall through to the legacy "old user" path — that path exists
1448 + // only for sites that never had Pro installed. If Pro is present but
1449 + // the license is inactive we should lock, regardless of chart history.
1450 + if ( class_exists( 'Visualizer_Pro', false ) ) {
1451 + return false;
1452 + }
1453 +
1454 + // No Pro installed at all: grant legacy access to existing users so
1455 + // their charts are not suddenly broken when they upgrade the free plugin.
1456 + return 'yes' === get_option( 'visualizer-new-user' ) ? false : true;
1457 + }
1458 +
1459 + /**
1460 + * Multilingual Support.
1461 + *
1462 + * @param int $chart_id Chart ID.
1463 + * @return bool Default false
1464 + */
1465 + public function addMultilingualSupport( $chart_id ) {
1466 + global $sitepress;
1467 + if ( Visualizer_Module::is_pro() ) {
1468 + return;
1469 + }
1470 + if ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) {
1471 + $language = icl_get_languages();
1472 + $current_lang = icl_get_current_language();
1473 + $default_lang = icl_get_default_language();
1474 + $post_info = wpml_get_language_information( null, $chart_id );
1475 + $translations = array();
1476 + if ( ! empty( $post_info ) && ( $default_lang === $post_info['language_code'] ) ) {
1477 + $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
1478 + $translations = $sitepress->get_element_translations( $trid );
1479 + }
1480 + if ( empty( $translations ) ) {
1481 + return;
1482 + }
1483 + ?>
1484 + <hr><div class="visualizer-languages-list only-pro">
1485 + <?php
1486 + foreach ( $language as $lang ) {
1487 + $lang_code = $lang['code'];
1488 + if ( $current_lang !== $lang_code ) {
1489 + ?>
1490 + <a href="javascript:;">
1491 + <img src="<?php echo esc_url( $lang['country_flag_url'] ); ?>" alt="<?php echo esc_attr( $lang['translated_name'] ); ?>">
1492 + </a>
1493 + <?php
1494 + }
1495 + }
1496 + ?>
1497 + <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>
1498 + </div>
1499 + <?php
1500 + }
1501 + }
1502 +
1503 + /**
1504 + * Check chart is enabled or not.
1505 + *
1506 + * @param string $type Chart ID.
1507 + *
1508 + * @return bool Default false
1509 + */
1510 + public static function checkChartStatus( $type ) {
1511 + $types = self::_getChartTypesLocalized( false, false, false, true );
1512 + if ( isset( $types[ $type ] ) ) {
1513 + return ! empty( $types[ $type ]['enabled'] );
1514 + }
1515 + return false;
1516 + }
1517 +
1518 + /**
1519 + * Get the survey metadata.
1520 + *
1521 + * @param array $data The data for survey in Formbricks format.
1522 + * @param string $page_slug The slug of the loaded page.
1523 + *
1524 + * @return array The survey metadata.
1525 + */
1526 + public function get_survey_metadata( $data, $page_slug ) {
1527 + $install_date = get_option( 'visualizer_install', time() );
1528 + $install_days_number = intval( ( time() - $install_date ) / DAY_IN_SECONDS );
1529 +
1530 + $license_status = apply_filters( 'product_visualizer_license_status', 'invalid' );
1531 + $license_plan = apply_filters( 'product_visualizer_license_plan', false );
1532 + $license_key = apply_filters( 'product_visualizer_license_key', false );
1533 +
1534 + $plugin_data = get_plugin_data( VISUALIZER_BASEFILE, false, false );
1535 + $plugin_version = '';
1536 +
1537 + if ( ! empty( $plugin_data['Version'] ) ) {
1538 + $plugin_version = $plugin_data['Version'];
1539 + }
1540 +
1541 + $count_charts_cache_key = 'visualizer_count_charts';
1542 + $charts_number = get_transient( $count_charts_cache_key );
1543 +
1544 + if ( false === $charts_number ) {
1545 + $charts_number = $this->count_charts( 100 );
1546 + set_transient( $count_charts_cache_key, $charts_number, 100 === $charts_number ? WEEK_IN_SECONDS : 6 * HOUR_IN_SECONDS );
1547 + } else {
1548 + $charts_number = strval( $charts_number );
1549 + }
1550 +
1551 + $data = array(
1552 + 'environmentId' => 'cltef8cut1s7wyyfxy3rlxzs5',
1553 + 'attributes' => array(
1554 + 'free_version' => $plugin_version,
1555 + 'pro_version' => defined( 'VISUALIZER_PRO_VERSION' ) ? VISUALIZER_PRO_VERSION : '',
1556 + 'license_status' => $license_status,
1557 + 'install_days_number' => $install_days_number,
1558 + 'charts_number' => $charts_number,
1559 + ),
1560 + );
1561 +
1562 + if ( ! empty( $license_plan ) ) {
1563 + $data['attributes']['plan'] = $license_plan;
1564 + }
1565 +
1566 + if ( ! empty( $license_key ) ) {
1567 + $data['attributes']['license_key'] = apply_filters( 'themeisle_sdk_secret_masking', $license_key );
1568 + }
1569 +
1570 + return $data;
1571 + }
1572 +
1573 + /**
1574 + * Count the charts.
1575 + *
1576 + * @param int $limit The count limit (optional).
1577 + *
1578 + * @return int The number of charts.
1579 + */
1580 + public function count_charts( $limit = -1 ) {
1581 + $args = array(
1582 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
1583 + 'post_status' => 'publish',
1584 + 'posts_per_page' => $limit,
1585 + 'fields' => 'ids',
1586 + );
1587 +
1588 + $query = new WP_Query( $args);
1589 + return $query->post_count;
1590 + }
1591 +
1592 + /**
1593 + * Set the black friday data.
1594 + *
1595 + * @param array $configs The configuration array for the loaded products.
1596 + * @return array
1597 + */
1598 + public function add_black_friday_data( $configs ) {
1599 + $config = $configs['default'];
1600 +
1601 + // translators: %1$s - HTML tag, %2$s - discount, %3$s - HTML tag, %4$s - product name.
1602 + $message_template = __( 'Our biggest sale of the year: %1$sup to %2$s OFF%3$s on %4$s. Don\'t miss this limited-time offer.', 'visualizer' );
1603 + $product_label = 'Visualizer';
1604 + $discount = '70%';
1605 +
1606 + $plan = apply_filters( 'product_visualizer_license_plan', 0 );
1607 + $license = apply_filters( 'product_visualizer_license_key', false );
1608 + $is_pro = 0 < $plan;
1609 +
1610 + if ( $is_pro ) {
1611 + // translators: %1$s - HTML tag, %2$s - discount, %3$s - HTML tag, %4$s - product name.
1612 + $message_template = __( 'Get %1$sup to %2$s off%3$s when you upgrade your %4$s plan or renew early.', 'visualizer' );
1613 + $product_label = 'Visualizer Pro';
1614 + $discount = '30%';
1615 + }
1616 +
1617 + $product_label = sprintf( '<strong>%s</strong>', $product_label );
1618 + $url_params = array(
1619 + 'utm_term' => $is_pro ? 'plan-' . $plan : 'free',
1620 + 'lkey' => ! empty( $license ) ? $license : false,
1621 + );
1622 +
1623 + $config['message'] = sprintf( $message_template, '<strong>', $discount, '</strong>', $product_label );
1624 + $config['sale_url'] = add_query_arg(
1625 + $url_params,
1626 + tsdk_translate_link( tsdk_utmify( 'https://themeisle.link/vizualizer-bf', 'bfcm', 'visualizer' ) )
1627 + );
1628 +
1629 + $configs[ VISUALIZER_DIRNAME ] = $config;
1630 +
1631 + return $configs;
1632 + }
483 1633 }