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/Setup.php +336 -44 3.1.14.0.8 View file →
@@ -44,15 +44,21 @@
44 44
45 45 register_activation_hook( VISUALIZER_BASEFILE, array( $this, 'activate' ) );
46 46 register_deactivation_hook( VISUALIZER_BASEFILE, array( $this, 'deactivate' ) );
47 47 $this->_addAction( 'visualizer_schedule_refresh_db', 'refreshDbChart' );
48 - $this->_addFilter( 'visualizer_schedule_refresh_chart', 'refresh_db_for_chart', null, 10, 3 );
48 + $this->_addFilter( 'visualizer_schedule_refresh_chart', 'refresh_db_for_chart', 10, 3 );
49 49
50 + $this->_addAction( 'admin_init', 'adminInit' );
50 51 $this->_addAction( 'init', 'setupCustomPostTypes' );
52 + $this->_addFilter( 'cron_schedules', 'custom_cron_schedules' );
51 53 $this->_addAction( 'plugins_loaded', 'loadTextDomain' );
52 54 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
53 - $this->_addFilter( 'visualizer_get_chart_counts', 'getChartCountsByTypeAndMeta' );
55 + $this->_addFilter( 'visualizer_get_chart_counts', 'getUsage', 10, 2 );
54 56
57 + $this->_addAction( 'init', 'checkIsExistingUser' );
58 +
59 + // only for testing
60 + // $this->_addAction( 'admin_init', 'getUsage' );
55 61 }
56 62 /**
57 63 * Fetches the SDK logger data.
58 64 *
@@ -60,36 +66,82 @@
60 66 *
61 67 * @access public
62 68 */
63 69 public function getLoggerData( $data ) {
64 - return $this->getChartCountsByTypeAndMeta();
70 + return $this->getUsage( $data );
65 71 }
66 72
67 73 /**
68 - * Fetches the types of charts created and their counts.
74 + * Fetches the usage of charts.
69 75 *
76 + * @param array $data The default data that needs to be sent.
70 77 * @param array $meta_keys An array of name vs. meta keys - to return how many charts have these keys.
71 - * @access private
78 + *
79 + * @access public
72 80 */
73 - public function getChartCountsByTypeAndMeta( $meta_keys = array() ) {
74 - $charts = array();
75 - $charts['chart_types'] = array();
76 - // the initial query arguments to fetch charts
81 + public function getUsage( $data, $meta_keys = array() ) {
82 + $charts = array( 'types' => array(), 'sources' => array(), 'library' => array(), 'permissions' => 0, 'manual_config' => 0, 'scheduled' => 0 );
77 83 $query_args = array(
78 84 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
79 85 'posts_per_page' => 300,
86 + 'post_status' => 'publish',
80 87 'fields' => 'ids',
81 88 'no_rows_found' => false,
82 89 'update_post_meta_cache' => false,
83 90 'update_post_term_cache' => false,
91 + );
84 92
93 + // default permissions.
94 + $default_perms = array(
95 + 'read' => 'all',
96 + 'read-specific' => null,
97 + 'edit' => 'roles',
98 + 'edit-specific' => array( 'administrator' ),
85 99 );
86 100
101 + // collect all schedules chart ids.
102 + $scheduled = array_merge(
103 + array_keys( get_option( Visualizer_Plugin::CF_CHART_SCHEDULE, array() ) ),
104 + array_keys( get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() ) )
105 + );
87 106 $query = new WP_Query( $query_args );
88 107 while ( $query->have_posts() ) {
89 108 $chart_id = $query->next_post();
90 109 $type = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true );
91 - $charts['chart_types'][ $type ] = isset( $charts['chart_types'][ $type ] ) ? $charts['chart_types'][ $type ] + 1 : 1;
110 + $charts['types'][ $type ] = isset( $charts['types'][ $type ] ) ? $charts['types'][ $type ] + 1 : 1;
111 + $source = get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true );
112 + $charts['sources'][ $source ] = isset( $charts['sources'][ $source ] ) ? $charts['sources'][ $source ] + 1 : 1;
113 + $lib = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, true );
114 + $charts['library'][ $lib ] = isset( $charts['library'][ $lib ] ) ? $charts['library'][ $lib ] + 1 : 1;
115 + $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
116 + if ( is_array( $settings ) && ! empty( $settings['manual'] ) ) {
117 + $charts['manual_config'] = $charts['manual_config'] + 1;
118 + }
119 +
120 + // phpcs:ignore WordPress.PHP.StrictInArray.FoundNonStrictFalse
121 + if ( in_array( $chart_id, $scheduled, false ) ) {
122 + $charts['scheduled'] = $charts['scheduled'] + 1;
123 + }
124 +
125 + if ( Visualizer_Module::is_pro() ) {
126 + $permissions = get_post_meta( $chart_id, Visualizer_Pro::CF_PERMISSIONS, true );
127 + if ( ! is_array( $permissions ) || empty( $permissions['permissions'] ) || ! is_array( $permissions['permissions'] ) ) {
128 + continue;
129 + }
130 + $permissions = $permissions['permissions'];
131 + $customized = false;
132 + foreach ( $default_perms as $key => $val ) {
133 + if ( ! is_array( $val ) && ! is_null( $val ) && isset( $permissions[ $key ] ) && $permissions[ $key ] !== $val ) {
134 + $customized = true;
135 + } elseif ( is_array( $val ) && ! is_null( $val ) && isset( $permissions[ $key ] ) && is_array( $permissions[ $key ] ) && count( $permissions[ $key ] ) !== count( $val ) ) {
136 + $customized = true;
137 + }
138 + }
139 + if ( $customized ) {
140 + $charts['permissions'] = $charts['permissions'] + 1;
141 + }
142 + }
143 +
92 144 if ( ! empty( $meta_keys ) ) {
93 145 foreach ( $meta_keys as $name => $key ) {
94 146 $data = get_post_meta( $chart_id, $key, true );
95 147 if ( ! empty( $data ) ) {
@@ -99,8 +151,9 @@
99 151 }
100 152 }
101 153 }
102 154 }
155 +
103 156 return $charts;
104 157 }
105 158
106 159 /**
@@ -139,27 +192,110 @@
139 192
140 193 /**
141 194 * Activate the plugin
142 195 */
143 - public function activate() {
144 - wp_clear_scheduled_hook( 'visualizer_schedule_refresh_db' );
145 - wp_schedule_event( strtotime( 'midnight' ) - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS, 'hourly', 'visualizer_schedule_refresh_db' );
196 + public function activate( $network_wide ) {
197 + if ( is_multisite() && $network_wide ) {
198 + foreach ( get_sites( array( 'fields' => 'ids' ) ) as $blog_id ) {
199 + switch_to_blog( $blog_id );
200 + $this->activate_on_site();
201 + restore_current_blog();
202 + }
203 + } else {
204 + $this->activate_on_site();
205 + }
146 206 }
147 207
148 208 /**
209 + * Activates the plugin on a particular blog instance (supports multisite and single site).
210 + */
211 + private function activate_on_site() {
212 + $this->schedule_refresh_db_action();
213 + add_option( 'visualizer-activated', true );
214 + $is_fresh_install = get_option( 'visualizer_fresh_install', false );
215 + if ( ! defined( 'TI_E2E_TESTING' ) && false === $is_fresh_install ) {
216 + update_option( 'visualizer_fresh_install', '1' );
217 + }
218 + }
219 +
220 + /**
149 221 * Deactivate the plugin
150 222 */
151 - public function deactivate() {
152 - wp_clear_scheduled_hook( 'visualizer_schedule_refresh_db' );
223 + public function deactivate( $network_wide ) {
224 + if ( is_multisite() && $network_wide ) {
225 + foreach ( get_sites( array( 'fields' => 'ids' ) ) as $blog_id ) {
226 + switch_to_blog( $blog_id );
227 + $this->deactivate_on_site();
228 + restore_current_blog();
229 + }
230 + } else {
231 + $this->deactivate_on_site();
232 + }
153 233 }
154 234
155 235 /**
156 - * Refresh the specific chart from the db. This is mostly for charts that have 0 refresh time i.e. live data.
236 + * Deactivates the plugin on a particular blog instance (supports multisite and single site).
237 + */
238 + private function deactivate_on_site() {
239 + $this->unschedule_refresh_db_action();
240 + delete_option( 'visualizer-activated', true );
241 + }
242 +
243 + /**
244 + * Check if plugin has been activated and then redirect to the correct page.
245 + */
246 + public function adminInit() {
247 + if ( defined( 'TI_UNIT_TESTING' ) ) {
248 + return;
249 + }
250 +
251 + define( 'VISUALIZER_SURVEY', Visualizer_Module::is_pro() ? 'https://forms.gle/7Zo7FuZbvQ8DTvRi6' : 'https://forms.gle/muMtbcyvHn1aTvmJ7' );
252 + // fire any upgrades necessary.
253 + Visualizer_Module_Upgrade::upgrade();
254 +
255 + $activated_flag = get_option( 'visualizer-activated' );
256 + $fresh_install = get_option( 'visualizer_fresh_install', false );
257 + $is_pro = Visualizer_Module::is_pro();
258 + if ( $activated_flag ) {
259 + if ( function_exists( 'wp_doing_ajax' ) && wp_doing_ajax() ) {
260 + // Defer redirect until a normal admin request.
261 + return;
262 + }
263 + if ( wp_doing_cron() ) {
264 + // Defer redirect during cron requests.
265 + return;
266 + }
267 + delete_option( 'visualizer-activated' );
268 + if ( ! headers_sent() ) {
269 + if ( ! $is_pro && ! empty( $fresh_install ) ) {
270 + $redirect_url = array(
271 + 'page' => 'visualizer-setup-wizard',
272 + 'tab' => '#step-1',
273 + );
274 + } else {
275 + $page_name = Visualizer_Module::numberOfCharts() > 0 ? Visualizer_Plugin::NAME : 'viz-support';
276 + $redirect_url = array(
277 + 'page' => $page_name,
278 + );
279 + }
280 + wp_safe_redirect(
281 + add_query_arg(
282 + $redirect_url,
283 + admin_url( 'admin.php' )
284 + )
285 + );
286 + exit();
287 + }
288 + }
289 + }
290 +
291 +
292 + /**
293 + * Refresh the specific chart from the db.
157 294 *
158 - * @param WP_Post $chart The chart object.
159 - * @param int $chart_id The chart id.
160 - * @param bool $force If this is true, then the chart data will be refreshed no matter if the chart requests live data or cached data.
161 - * If false, data will be refreshed only if the chart requests live data.
295 + * @param WP_Post|null $chart The chart object.
296 + * @param int $chart_id The chart id.
297 + * @param bool $force If this is true, then the chart data will be force refreshed. If false, data will be refreshed only if the chart requests live data.
162 298 *
163 299 * @access public
164 300 */
165 301 public function refresh_db_for_chart( $chart, $chart_id, $force = false ) {
@@ -170,38 +306,97 @@
170 306 if ( ! $chart ) {
171 307 $chart = get_post( $chart_id );
172 308 }
173 309
174 - // check if its a live-data chart or a cached-data chart.
175 - if ( ! $force ) {
176 - $hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, true );
177 - if ( ! empty( $hours ) ) {
178 - // cached, bail!
179 - return $chart;
180 - }
310 + if ( ! $chart ) {
311 + return $chart;
181 312 }
182 313
183 314 // check if the source is correct.
184 315 $source = get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true );
185 - if ( $source !== 'Visualizer_Source_Query_Params' ) {
186 - return $chart;
316 + $load_series = false;
317 + switch ( $source ) {
318 + case 'Visualizer_Source_Query':
319 + // check if its a live-data chart or a cached-data chart.
320 + if ( ! $force ) {
321 + $hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, true );
322 + if ( ! empty( $hours ) ) {
323 + // cached, bail!
324 + return $chart;
325 + }
326 + }
327 +
328 + $params = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, true );
329 + $source = new Visualizer_Source_Query( $params, $chart_id );
330 + $source->fetch( false );
331 + $load_series = true;
332 + break;
333 + case 'Visualizer_Source_Json':
334 + // check if its a live-data chart or a cached-data chart.
335 + if ( ! $force ) {
336 + $hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, true );
337 + if ( ! empty( $hours ) ) {
338 + // cached, bail!
339 + return $chart;
340 + }
341 + }
342 +
343 + $url = get_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL, true );
344 + $root = get_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT, true );
345 + $paging = get_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING, true );
346 + $series = get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true );
347 + $source = new Visualizer_Source_Json( array( 'url' => $url, 'root' => $root, 'paging' => $paging ) );
348 + $source->refresh( $series );
349 + break;
350 + case 'Visualizer_Source_Csv_Remote':
351 + // check if its a live-data chart or a cached-data chart.
352 + if ( ! $force ) {
353 + $hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_SCHEDULE, true );
354 + if ( ! empty( $hours ) ) {
355 + // cached, bail!
356 + return $chart;
357 + }
358 + }
359 + do_action( 'visualizer_schedule_import' );
360 + return get_post( $chart_id );
361 + default:
362 + return $chart;
187 363 }
188 364
189 - $params = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, true );
190 - $source = new Visualizer_Source_Query( $params );
191 - $source->fetch( false );
192 365 $error = $source->get_error();
193 366 if ( empty( $error ) ) {
194 - update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
367 + $this->disableRevisionsTemporarily();
368 + if ( $load_series ) {
369 + update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
370 + }
195 371
372 + $allow_html = false;
373 + $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
374 + if ( isset( $settings['allowHtml'] ) && intval( $settings['allowHtml'] ) === 1 ) {
375 + $allow_html = true;
376 + }
377 +
378 + $allow_html = apply_filters( 'visualizer_allow_html_content', $allow_html, $chart_id, $chart );
379 +
380 + if ( $allow_html ) {
381 + kses_remove_filters();
382 + }
383 +
196 384 wp_update_post(
197 385 array(
198 386 'ID' => $chart_id,
199 - 'post_content' => $source->getData(),
387 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
200 388 )
201 389 );
202 390
391 + if ( $allow_html ) {
392 + kses_init_filters();
393 + }
394 +
203 395 $chart = get_post( $chart_id );
396 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR );
397 + } else {
398 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, sprintf( 'Error while updating chart: %s', $error ) );
204 399 }
205 400
206 401 return $chart;
207 402 }
@@ -206,17 +401,19 @@
206 401 return $chart;
207 402 }
208 403
209 404 /**
210 - * Refresh the db chart.
405 + * Refresh the Database chart type.
211 406 *
212 407 * @access public
213 408 */
214 409 public function refreshDbChart() {
215 - $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
216 - if ( ! $schedules ) {
410 + // NOTE: This use a different key from normal schedule. Updated only by Database chart. Check `visualizer_schedule_import` action.
411 + $chart_schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
412 + if ( ! $chart_schedules ) {
217 413 return;
218 414 }
415 +
219 416 if ( ! defined( 'VISUALIZER_DO_NOT_DIE' ) ) {
220 417 // define this so that the ajax call does not die
221 418 // this means that if the new version of pro and the old version of free are installed, only the first chart will be updated
222 419 define( 'VISUALIZER_DO_NOT_DIE', true );
@@ -222,19 +419,114 @@
222 419 define( 'VISUALIZER_DO_NOT_DIE', true );
223 420 }
224 421
225 422 $new_schedules = array();
226 - $now = time();
227 - foreach ( $schedules as $chart_id => $time ) {
228 - $new_schedules[ $chart_id ] = $time;
229 - if ( $time > $now ) {
423 + $current_time = time();
424 + foreach ( $chart_schedules as $chart_id => $scheduled_time ) {
425 +
426 + // Skip deleted charts.
427 + if ( false === get_post_status( $chart_id ) ) {
230 428 continue;
231 429 }
232 430
233 - $this->refresh_db_for_chart( null, $chart_id, false );
234 - $hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, true );
235 - $new_schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
431 + $new_schedules[ $chart_id ] = $scheduled_time;
432 +
433 + // Should we do an update?
434 + if ( $scheduled_time > $current_time ) {
435 + continue;
436 + }
437 +
438 + $this->refresh_db_for_chart( null, $chart_id, true );
439 +
440 + // Clear existing chart cache.
441 + $cache_key = Visualizer_Plugin::CF_CHART_CACHE . '_' . $chart_id;
442 + if ( get_transient( $cache_key ) ) {
443 + delete_transient( $cache_key );
444 + }
445 +
446 + $scheduled_hours = get_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, true );
447 + $new_schedules[ $chart_id ] = $current_time + $scheduled_hours * HOUR_IN_SECONDS;
236 448 }
237 449 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $new_schedules );
238 450 }
239 451
452 + /**
453 + * Save flag for existing users.
454 + */
455 + public function checkIsExistingUser() {
456 + $chart_exists = get_option( 'visualizer-new-user', '' );
457 + if ( '' === $chart_exists ) {
458 + $charts = get_posts(
459 + array(
460 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
461 + 'fields' => 'ids',
462 + )
463 + );
464 + update_option( 'visualizer-new-user', ! empty( $charts ) ? 'no' : 'yes' );
465 + }
466 + }
467 +
468 + /**
469 + * Add custom cron schedules.
470 + *
471 + * @param array $schedules The current schedules options.
472 + * @return array The modified schedules options.
473 + */
474 + public function custom_cron_schedules( $schedules ) {
475 + $schedules['visualizer_ten_minutes'] = array(
476 + 'interval' => 600,
477 + 'display' => __( 'Every 10 minutes', 'visualizer' ),
478 + );
479 +
480 + return $schedules;
481 + }
482 +
483 + /**
484 + * Schedule the recurring DB refresh action.
485 + */
486 + private function schedule_refresh_db_action(): void {
487 + $hook = 'visualizer_schedule_refresh_db';
488 + $group = 'visualizer';
489 + $interval_key = apply_filters( 'visualizer_chart_schedule_interval', 'visualizer_ten_minutes' );
490 + $interval = $this->get_schedule_interval_seconds( $interval_key );
491 + $timestamp = strtotime( 'midnight' ) - get_option( 'gmt_offset' ) * HOUR_IN_SECONDS;
492 +
493 + if ( function_exists( 'as_next_scheduled_action' ) && function_exists( 'as_schedule_recurring_action' ) ) {
494 + $next = as_next_scheduled_action( $hook, array(), $group );
495 + if ( false === $next ) {
496 + as_schedule_recurring_action( $timestamp, $interval, $hook, array(), $group );
497 + }
498 + wp_clear_scheduled_hook( $hook );
499 + return;
500 + }
501 +
502 + wp_clear_scheduled_hook( $hook );
503 + wp_schedule_event( $timestamp, $interval_key, $hook );
504 + }
505 +
506 + /**
507 + * Unschedule the recurring DB refresh action.
508 + */
509 + private function unschedule_refresh_db_action(): void {
510 + $hook = 'visualizer_schedule_refresh_db';
511 + $group = 'visualizer';
512 + if ( function_exists( 'as_unschedule_all_actions' ) ) {
513 + as_unschedule_all_actions( $hook, array(), $group );
514 + }
515 + wp_clear_scheduled_hook( $hook );
516 + }
517 +
518 + /**
519 + * Resolve a cron schedule key to seconds.
520 + *
521 + * @param string $interval_key Cron schedule key.
522 + * @return int Interval in seconds.
523 + */
524 + private function get_schedule_interval_seconds( $interval_key ) {
525 + $schedules = wp_get_schedules();
526 + if ( isset( $schedules[ $interval_key ]['interval'] ) ) {
527 + return (int) $schedules[ $interval_key ]['interval'];
528 + }
529 +
530 + return 600;
531 + }
240 532 }