PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.2
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 3.10.4 All 148 releases
visualizer / classes / Visualizer / Module / Setup.php

Setup.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 4.0.2, at classes/Visualizer/Module/Setup.php

533 lines 16.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
5 // +----------------------------------------------------------------------+
6 // | This program is free software; you can redistribute it and/or modify |
7 // | it under the terms of the GNU General Public License, version 2, as |
8 // | published by the Free Software Foundation. |
9 // | |
10 // | This program is distributed in the hope that it will be useful, |
11 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 // | GNU General Public License for more details. |
14 // | |
15 // | You should have received a copy of the GNU General Public License |
16 // | along with this program; if not, write to the Free Software |
17 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
18 // | MA 02110-1301 USA |
19 // +----------------------------------------------------------------------+
20 // | Author: Eugene Manuilov <eugene@manuilov.org> |
21 // +----------------------------------------------------------------------+
22 /**
23 * General module what setups all required environment.
24 *
25 * @category Visualizer
26 * @package Module
27 *
28 * @since 1.0.0
29 */
30 class Visualizer_Module_Setup extends Visualizer_Module {
31
32 const NAME = __CLASS__;
33
34 /**
35 * Constructor.
36 *
37 * @since 1.0.0
38 *
39 * @access public
40 * @param Visualizer_Plugin $plugin The instance of the plugin.
41 */
42 public function __construct( Visualizer_Plugin $plugin ) {
43 parent::__construct( $plugin );
44
45 register_activation_hook( VISUALIZER_BASEFILE, array( $this, 'activate' ) );
46 register_deactivation_hook( VISUALIZER_BASEFILE, array( $this, 'deactivate' ) );
47 $this->_addAction( 'visualizer_schedule_refresh_db', 'refreshDbChart' );
48 $this->_addFilter( 'visualizer_schedule_refresh_chart', 'refresh_db_for_chart', 10, 3 );
49
50 $this->_addAction( 'admin_init', 'adminInit' );
51 $this->_addAction( 'init', 'setupCustomPostTypes' );
52 $this->_addFilter( 'cron_schedules', 'custom_cron_schedules' );
53 $this->_addAction( 'plugins_loaded', 'loadTextDomain' );
54 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
55 $this->_addFilter( 'visualizer_get_chart_counts', 'getUsage', 10, 2 );
56
57 $this->_addAction( 'init', 'checkIsExistingUser' );
58
59 // only for testing
60 // $this->_addAction( 'admin_init', 'getUsage' );
61 }
62 /**
63 * Fetches the SDK logger data.
64 *
65 * @param array $data The default data that needs to be sent.
66 *
67 * @access public
68 */
69 public function getLoggerData( $data ) {
70 return $this->getUsage( $data );
71 }
72
73 /**
74 * Fetches the usage of charts.
75 *
76 * @param array $data The default data that needs to be sent.
77 * @param array $meta_keys An array of name vs. meta keys - to return how many charts have these keys.
78 *
79 * @access public
80 */
81 public function getUsage( $data, $meta_keys = array() ) {
82 $charts = array( 'types' => array(), 'sources' => array(), 'library' => array(), 'permissions' => 0, 'manual_config' => 0, 'scheduled' => 0 );
83 $query_args = array(
84 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
85 'posts_per_page' => 300,
86 'post_status' => 'publish',
87 'fields' => 'ids',
88 'no_rows_found' => false,
89 'update_post_meta_cache' => false,
90 'update_post_term_cache' => false,
91 );
92
93 // default permissions.
94 $default_perms = array(
95 'read' => 'all',
96 'read-specific' => null,
97 'edit' => 'roles',
98 'edit-specific' => array( 'administrator' ),
99 );
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 );
106 $query = new WP_Query( $query_args );
107 while ( $query->have_posts() ) {
108 $chart_id = $query->next_post();
109 $type = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true );
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 ( array_key_exists( 'manual', $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 ( empty( $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 ] ) && count( $permissions[ $key ] ) !== count( $val ) ) {
136 $customized = true;
137 }
138 }
139 if ( $customized ) {
140 $charts['permissions'] = $charts['permissions'] + 1;
141 }
142 }
143
144 if ( ! empty( $meta_keys ) ) {
145 foreach ( $meta_keys as $name => $key ) {
146 $data = get_post_meta( $chart_id, $key, true );
147 if ( ! empty( $data ) ) {
148 $charts[ $name ] = isset( $charts[ $name ] ) ? $charts[ $name ] + 1 : 1;
149 } else {
150 $charts[ $name ] = 0;
151 }
152 }
153 }
154 }
155
156 return $charts;
157 }
158
159 /**
160 * Registers custom post type for charts.
161 *
162 * @since 1.0.0
163 * @uses register_post_type() To register custom post type for charts.
164 *
165 * @access public
166 */
167 public function setupCustomPostTypes() {
168 register_post_type(
169 Visualizer_Plugin::CPT_VISUALIZER,
170 array(
171 'label' => 'Visualizer Charts',
172 'public' => false,
173 'supports' => array( 'revisions' ),
174 'show_in_rest' => true,
175 'rest_base' => 'visualizer',
176 'rest_controller_class' => 'WP_REST_Posts_Controller',
177 )
178 );
179 }
180
181 /**
182 * Loads plugin text domain translations.
183 *
184 * @since 1.0.0
185 * @uses load_plugin_textdomain() To load translations for the plugin.
186 *
187 * @access public
188 */
189 public function loadTextDomain() {
190 load_plugin_textdomain( Visualizer_Plugin::NAME, false, dirname( plugin_basename( VISUALIZER_BASEFILE ) ) . '/languages/' );
191 }
192
193 /**
194 * Activate the plugin
195 */
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 }
206 }
207
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 /**
221 * Deactivate the plugin
222 */
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 }
233 }
234
235 /**
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.
294 *
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.
298 *
299 * @access public
300 */
301 public function refresh_db_for_chart( $chart, $chart_id, $force = false ) {
302 if ( ! $chart_id ) {
303 return $chart;
304 }
305
306 if ( ! $chart ) {
307 $chart = get_post( $chart_id );
308 }
309
310 if ( ! $chart ) {
311 return $chart;
312 }
313
314 // check if the source is correct.
315 $source = get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true );
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;
363 }
364
365 $error = $source->get_error();
366 if ( empty( $error ) ) {
367 $this->disableRevisionsTemporarily();
368 if ( $load_series ) {
369 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
370 }
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
384 wp_update_post(
385 array(
386 'ID' => $chart_id,
387 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
388 )
389 );
390
391 if ( $allow_html ) {
392 kses_init_filters();
393 }
394
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 ) );
399 }
400
401 return $chart;
402 }
403
404 /**
405 * Refresh the Database chart type.
406 *
407 * @access public
408 */
409 public function refreshDbChart() {
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 ) {
413 return;
414 }
415
416 if ( ! defined( 'VISUALIZER_DO_NOT_DIE' ) ) {
417 // define this so that the ajax call does not die
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
419 define( 'VISUALIZER_DO_NOT_DIE', true );
420 }
421
422 $new_schedules = array();
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 ) ) {
428 continue;
429 }
430
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;
448 }
449 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $new_schedules );
450 }
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 }
532 }
533