PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.5
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.5
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | classes/Visualizer/Module/Admin.php +668 -113 3.0.53.4.5 View file →
@@ -52,19 +52,231 @@
52 52 public function __construct( Visualizer_Plugin $plugin ) {
53 53 parent::__construct( $plugin );
54 54 $this->_addAction( 'load-post.php', 'enqueueMediaScripts' );
55 55 $this->_addAction( 'load-post-new.php', 'enqueueMediaScripts' );
56 - $this->_addAction( 'admin_footer', 'renderTempaltes' );
56 + $this->_addAction( 'admin_footer', 'renderTemplates' );
57 57 $this->_addAction( 'admin_enqueue_scripts', 'enqueueLibraryScripts', null, 8 );
58 58 $this->_addAction( 'admin_menu', 'registerAdminMenu' );
59 59 $this->_addFilter( 'media_view_strings', 'setupMediaViewStrings' );
60 60 $this->_addFilter( 'plugin_action_links', 'getPluginActionLinks', 10, 2 );
61 + $this->_addFilter( 'plugin_row_meta', 'getPluginMetaLinks', 10, 2 );
61 62 $this->_addFilter( 'visualizer_logger_data', 'getLoggerData' );
62 - $this->_addFilter( 'visualizer_get_chart_counts', 'getChartCountsByTypeAndMeta' );
63 63 $this->_addFilter( 'visualizer_feedback_review_trigger', 'feedbackReviewTrigger' );
64 +
65 + // screen pagination
66 + $this->_addFilter( 'set-screen-option', 'setScreenOptions', 10, 3 );
67 +
68 + // revision support.
69 + $this->_addFilter( 'wp_revisions_to_keep', 'limitRevisions', null, 10, 2 );
70 + $this->_addAction( '_wp_put_post_revision', 'addRevision', null, 10, 1 );
71 + $this->_addAction( 'wp_restore_post_revision', 'restoreRevision', null, 10, 2 );
72 +
73 + $this->_addAction( 'visualizer_chart_schedules_spl', 'addSplChartSchedules', null, 10, 3 );
74 +
75 + $this->_addAction( 'admin_init', 'init' );
76 +
77 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
78 + $this->load_cypress_hooks();
79 + }
80 +
64 81 }
65 82
66 83 /**
84 + * Define the hooks that are needed for cypress.
85 + *
86 + * @since 3.4.0
87 + * @access private
88 + */
89 + private function load_cypress_hooks() {
90 + // all charts should load on the same page without pagination.
91 + add_filter(
92 + 'visualizer_query_args', function( $args ) {
93 + $args['posts_per_page'] = 20;
94 + return $args;
95 + }, 10, 1
96 + );
97 + }
98 +
99 + /**
100 + * Add disabled `optgroup` schedules to the drop downs.
101 + *
102 + * @since ?
103 + *
104 + * @access public
105 + *
106 + * @param string $feature The feature for which to add schedules.
107 + * @param int $chart_id The chart ID.
108 + * @param int $plan The plan number.
109 + */
110 + public function addSplChartSchedules( $feature, $chart_id, $plan ) {
111 + if ( apply_filters( 'visualizer_is_business', false ) ) {
112 + return;
113 + }
114 +
115 + $license = __( 'PRO', 'visualizer' );
116 + if ( Visualizer_Module::is_pro() ) {
117 + switch ( $plan ) {
118 + case 1:
119 + $license = __( 'Developer', 'visualizer' );
120 + break;
121 + }
122 + }
123 +
124 + $hours = array(
125 + '0' => __( 'Live', 'visualizer' ),
126 + '1' => __( 'Each hour', 'visualizer' ),
127 + '12' => __( 'Each 12 hours', 'visualizer' ),
128 + '24' => __( 'Each day', 'visualizer' ),
129 + '72' => __( 'Each 3 days', 'visualizer' ),
130 + );
131 +
132 + switch ( $feature ) {
133 + case 'json':
134 + case 'csv':
135 + // no more schedules if pro is already active.
136 + if ( Visualizer_Module::is_pro() ) {
137 + return;
138 + }
139 + break;
140 + case 'wp':
141 + // fall-through.
142 + case 'db':
143 + break;
144 + default:
145 + return;
146 + }
147 +
148 + echo '<optgroup disabled label="' . sprintf( __( 'More in the %s version', 'visualizer' ), $license ) . '">';
149 + foreach ( $hours as $hour => $desc ) {
150 + echo '<option disabled>' . $desc . '</option>';
151 + }
152 + echo '</optgroup>';
153 + }
154 +
155 + /**
156 + * No limits on revisions.
157 + */
158 + public function limitRevisions( $num, $post ) {
159 + if ( Visualizer_Plugin::CPT_VISUALIZER === $post->post_type ) {
160 + return -1;
161 + }
162 + return $num;
163 + }
164 +
165 + /**
166 + * Add a revision.
167 + */
168 + public function addRevision( $revision_id ) {
169 + $parent_id = wp_is_post_revision( $revision_id );
170 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $parent_id ) ) {
171 + // add the meta data to this revision.
172 + $meta = get_post_meta( $parent_id, '', true );
173 +
174 + if ( $meta ) {
175 + foreach ( $meta as $key => $value ) {
176 + if ( 0 === strpos( $key, 'visualizer' ) ) {
177 + add_metadata( 'post', $revision_id, $key, maybe_unserialize( $value[0] ) );
178 + }
179 + }
180 + }
181 + }
182 + }
183 +
184 + /**
185 + * Restore a revision.
186 + */
187 + public function restoreRevision( $post_id, $revision_id ) {
188 + if ( Visualizer_Plugin::CPT_VISUALIZER === get_post_type( $post_id ) ) {
189 + // get the meta information from the revision.
190 + $meta = get_metadata( 'post', $revision_id, '', true );
191 +
192 + // delete all meta information from the post before adding.
193 + $post_meta = get_post_meta( $post_id, '', true );
194 + if ( $post_meta ) {
195 + foreach ( $meta as $key => $value ) {
196 + if ( 0 === strpos( $key, 'visualizer' ) ) {
197 + delete_post_meta( $post_id, $key );
198 + }
199 + }
200 + }
201 +
202 + if ( $meta ) {
203 + foreach ( $meta as $key => $value ) {
204 + if ( 0 === strpos( $key, 'visualizer' ) ) {
205 + add_post_meta( $post_id, $key, maybe_unserialize( $value[0] ) );
206 + }
207 + }
208 + }
209 + }
210 + }
211 +
212 + /**
213 + * Admin init.
214 + *
215 + * @access public
216 + */
217 + public function init() {
218 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
219 + if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
220 + $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
221 + $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
222 + $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
223 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
224 + }
225 + }
226 +
227 + /**
228 + * Add the strings required for the TinyMCE buttons for the classic block (not the classic editor).
229 + *
230 + * @since ?
231 + * @access friendly
232 + */
233 + function get_strings_for_block( $settings ) {
234 + $class = new Visualizer_Module_Language();
235 + $strings = $class->get_strings();
236 + $array = array( 'visualizer_tinymce_plugin' => json_encode( $strings ) );
237 + return array_merge( $settings, $array );
238 + }
239 +
240 + /**
241 + * Load plugin translation for - TinyMCE API
242 + *
243 + * @access public
244 + * @param array $arr The tinymce_lang array.
245 + * @return array
246 + */
247 + public function add_tinymce_lang( $arr ) {
248 + $ui_lang = VISUALIZER_ABSPATH . '/classes/Visualizer/Module/Language.php';
249 + $ui_lang = apply_filters( 'visualizer_ui_lang_filter', $ui_lang );
250 + $arr[] = $ui_lang;
251 + return $arr;
252 + }
253 +
254 + /**
255 + * Load custom js options - TinyMCE API
256 + *
257 + * @access public
258 + * @param array $plugin_array The tinymce plugin array.
259 + * @return array
260 + */
261 + public function tinymce_plugin( $plugin_array ) {
262 + $plugin_array['visualizer_mce_button'] = VISUALIZER_ABSURL . 'js/mce.js';
263 + return $plugin_array;
264 + }
265 +
266 + /**
267 + * Register new button in the editor
268 + *
269 + * @access public
270 + * @param array $buttons The tinymce buttons array.
271 + * @return array
272 + */
273 + public function register_mce_button( $buttons ) {
274 + array_push( $buttons, 'visualizer_mce_button' );
275 + return $buttons;
276 + }
277 +
278 + /**
67 279 * Whether to show the feedback review or not.
68 280 *
69 281 * @access public
70 282 */
@@ -97,14 +309,28 @@
97 309 public function enqueueMediaScripts() {
98 310 global $typenow;
99 311 if ( post_type_supports( $typenow, 'editor' ) ) {
100 312 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 );
313 +
314 + // Load all the assets for the different libraries we support.
315 + $deps = array(
316 + Visualizer_Render_Sidebar_Google::enqueue_assets( array( 'media-editor' ) ),
317 + Visualizer_Render_Sidebar_Type_DataTable_Tabular::enqueue_assets( array( 'media-editor' ) ),
318 + );
319 +
320 + wp_enqueue_script( 'visualizer-media-model', VISUALIZER_ABSURL . 'js/media/model.js', $deps, Visualizer_Plugin::VERSION, true );
104 321 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
105 322 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
106 323 wp_enqueue_script( 'visualizer-media-view', VISUALIZER_ABSURL . 'js/media/view.js', array( 'visualizer-media-controller' ), Visualizer_Plugin::VERSION, true );
324 + wp_localize_script(
325 + 'visualizer-media-view',
326 + 'visualizer',
327 + array(
328 + 'i10n' => array(
329 + 'insert' => __( 'Insert', 'visualizer' ),
330 + ),
331 + )
332 + );
107 333 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
108 334 wp_enqueue_script( 'visualizer-media', VISUALIZER_ABSURL . 'js/media.js', array( 'visualizer-media-toolbar' ), Visualizer_Plugin::VERSION, true );
109 335 }
110 336 }
@@ -120,8 +346,9 @@
120 346 *
121 347 * @return array The extended array of media view strings.
122 348 */
123 349 public function setupMediaViewStrings( $strings ) {
350 + $chart_types = self::_getChartTypesLocalized( true, true, true );
124 351 $strings['visualizer'] = array(
125 352 'actions' => array(
126 353 'get_charts' => Visualizer_Plugin::ACTION_GET_CHARTS,
127 354 'delete_chart' => Visualizer_Plugin::ACTION_DELETE_CHART,
@@ -133,10 +360,10 @@
133 360 'library' => esc_html__( 'From Library', 'visualizer' ),
134 361 'create' => esc_html__( 'Create New', 'visualizer' ),
135 362 ),
136 363 'library' => array(
137 - 'filters' => self::_getChartTypesLocalized( true, true ),
138 - 'types' => array_keys( self::_getChartTypesLocalized( true, true ) ),
364 + 'filters' => $chart_types,
365 + 'types' => array_keys( $chart_types ),
139 366 ),
140 367 'nonce' => wp_create_nonce(),
141 368 'buildurl' => add_query_arg( 'action', Visualizer_Plugin::ACTION_CREATE_CHART, admin_url( 'admin-ajax.php' ) ),
142 369 );
@@ -152,59 +379,99 @@
152 379 * @static
153 380 * @access private
154 381 * @return array The associated array of chart types with localized names.
155 382 */
156 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false ) {
157 - $types = array(
158 - 'pie' => array(
159 - 'name' => esc_html__( 'Pie', 'visualizer' ),
383 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
384 + $additional = array();
385 + if ( $add_select ) {
386 + $additional['select'] = array(
387 + 'name' => esc_html__( 'All', 'visualizer' ),
160 388 '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 - ),
389 + );
390 + }
391 +
392 + $types = array_merge(
393 + $additional,
394 + array(
395 + 'tabular' => array(
396 + 'name' => esc_html__( 'Table', 'visualizer' ),
397 + 'enabled' => true,
398 + 'supports' => array( 'Google Charts', 'DataTable' ),
399 + ),
400 + 'pie' => array(
401 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
402 + 'enabled' => true,
403 + 'supports' => array( 'Google Charts', 'ChartJS' ),
404 + ),
405 + 'line' => array(
406 + 'name' => esc_html__( 'Line', 'visualizer' ),
407 + 'enabled' => true,
408 + 'supports' => array( 'Google Charts', 'ChartJS' ),
409 + ),
410 + 'area' => array(
411 + 'name' => esc_html__( 'Area', 'visualizer' ),
412 + 'enabled' => true,
413 + // in ChartJS, the fill option is used to make Line chart an area: https://www.chartjs.org/docs/latest/charts/area.html
414 + 'supports' => array( 'Google Charts' ),
415 + ),
416 + 'geo' => array(
417 + 'name' => esc_html__( 'Geo', 'visualizer' ),
418 + 'enabled' => true,
419 + 'supports' => array( 'Google Charts' ),
420 + ),
421 + 'bar' => array(
422 + 'name' => esc_html__( 'Bar', 'visualizer' ),
423 + 'enabled' => true,
424 + 'supports' => array( 'Google Charts', 'ChartJS' ),
425 + ),
426 + 'column' => array(
427 + 'name' => esc_html__( 'Column', 'visualizer' ),
428 + 'enabled' => true,
429 + 'supports' => array( 'Google Charts', 'ChartJS' ),
430 + ),
431 + 'bubble' => array(
432 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
433 + 'enabled' => true,
434 + // chartjs' bubble is ugly looking (and it won't work off the default bubble.csv) so it is being excluded for the time being.
435 + 'supports' => array( 'Google Charts' ),
436 + ),
437 + 'scatter' => array(
438 + 'name' => esc_html__( 'Scatter', 'visualizer' ),
439 + 'enabled' => true,
440 + 'supports' => array( 'Google Charts' ),
441 + ),
442 + 'gauge' => array(
443 + 'name' => esc_html__( 'Gauge', 'visualizer' ),
444 + 'enabled' => true,
445 + 'supports' => array( 'Google Charts' ),
446 + ),
447 + 'candlestick' => array(
448 + 'name' => esc_html__( 'Candlestick', 'visualizer' ),
449 + 'enabled' => true,
450 + 'supports' => array( 'Google Charts' ),
451 + ),
452 + // pro types
453 + 'timeline' => array(
454 + 'name' => esc_html__( 'Timeline', 'visualizer' ),
455 + 'enabled' => false,
456 + 'supports' => array( 'Google Charts', 'ChartJS' ),
457 + ),
458 + 'combo' => array(
459 + 'name' => esc_html__( 'Combo', 'visualizer' ),
460 + 'enabled' => false,
461 + 'supports' => array( 'Google Charts' ),
462 + ),
463 + 'polarArea' => array(
464 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
465 + 'enabled' => false,
466 + 'supports' => array( 'ChartJS' ),
467 + ),
468 + 'radar' => array(
469 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
470 + 'enabled' => false,
471 + 'supports' => array( 'ChartJS' ),
472 + ),
473 + )
207 474 );
208 475 $types = apply_filters( 'visualizer_pro_chart_types', $types );
209 476 if ( $enabledOnly ) {
210 477 $filtered = array();
@@ -212,8 +479,12 @@
212 479 if ( ! is_array( $array ) ) {
213 480 // support for old pro
214 481 $array = array( 'enabled' => true, 'name' => $array );
215 482 }
483 + // backward compatibility for PRO before v1.9.0
484 + if ( ! array_key_exists( 'supports', $array ) ) {
485 + $array['supports'] = array( 'Google Charts' );
486 + }
216 487 if ( ! $array['enabled'] ) {
217 488 continue;
218 489 }
219 490 $filtered[ $type ] = $array;
@@ -226,13 +497,74 @@
226 497 if ( ! is_array( $array ) ) {
227 498 // support for old pro
228 499 $array = array( 'enabled' => true, 'name' => $array );
229 500 }
501 + // backward compatibility for PRO before v1.9.0
502 + if ( ! array_key_exists( 'supports', $array ) ) {
503 + $array['supports'] = array( 'Google Charts' );
504 + }
230 505 $doubleD[ $type ] = $array['name'];
231 506 }
232 507 $types = $doubleD;
233 508 }
234 509
510 + return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
511 + }
512 +
513 + /**
514 + * Handle (soon-to-be) deprecated charts.
515 + */
516 + private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
517 + $deprecated = array();
518 +
519 + switch ( $where ) {
520 + case 'types':
521 + // fall-through
522 + case 'library':
523 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
524 + if ( ! Visualizer_Module::is_pro() ) {
525 + if ( ! self::hasChartType( 'gauge' ) ) {
526 + if ( $get2Darray ) {
527 + $deprecated[] = 'gauge';
528 + } else {
529 + $types['gauge']['enabled'] = false;
530 + }
531 + }
532 + if ( ! self::hasChartType( 'candlestick' ) ) {
533 + if ( $get2Darray ) {
534 + $deprecated[] = 'candlestick';
535 + } else {
536 + $types['candlestick']['enabled'] = false;
537 + }
538 + }
539 + }
540 + break;
541 + default:
542 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
543 + if ( ! Visualizer_Module::is_pro() ) {
544 + if ( ! self::hasChartType( 'gauge' ) ) {
545 + if ( $get2Darray ) {
546 + $deprecated[] = 'gauge';
547 + } else {
548 + $types['gauge']['enabled'] = false;
549 + }
550 + }
551 + if ( ! self::hasChartType( 'candlestick' ) ) {
552 + if ( $get2Darray ) {
553 + $deprecated[] = 'candlestick';
554 + } else {
555 + $types['candlestick']['enabled'] = false;
556 + }
557 + }
558 + }
559 + }
560 +
561 + if ( $deprecated ) {
562 + foreach ( $deprecated as $type ) {
563 + unset( $types[ $type ] );
564 + }
565 + }
566 +
235 567 return $types;
236 568 }
237 569
238 570 /**
@@ -242,11 +574,11 @@
242 574 * @global string $pagenow The name of the current page.
243 575 *
244 576 * @access public
245 577 */
246 - public function renderTempaltes() {
578 + public function renderTemplates() {
247 579 global $pagenow;
248 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
580 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
249 581 return;
250 582 }
251 583 $render = new Visualizer_Render_Templates();
252 584 $render->render();
@@ -264,26 +596,42 @@
264 596 *
265 597 * @param string $suffix The current page suffix.
266 598 */
267 599 public function enqueueLibraryScripts( $suffix ) {
268 - if ( $suffix == $this->_libraryPage ) {
600 + if ( $suffix === $this->_libraryPage ) {
601 + wp_register_script( 'visualizer-clipboardjs', VISUALIZER_ABSURL . 'js/lib/clipboardjs/clipboard.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
269 602 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
270 603 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
271 604 wp_enqueue_media();
272 605 wp_enqueue_script(
273 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
606 + 'visualizer-library',
607 + VISUALIZER_ABSURL . 'js/library.js',
608 + array(
274 609 'jquery',
275 610 'media-views',
276 - ), Visualizer_Plugin::VERSION, true
611 + 'visualizer-clipboardjs',
612 + ),
613 + Visualizer_Plugin::VERSION,
614 + true
277 615 );
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 );
280 - wp_enqueue_script(
281 - 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array(
282 - 'google-jsapi-old',
283 - 'visualizer-library',
284 - ), Visualizer_Plugin::VERSION, true
285 - );
616 +
617 + wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
618 +
619 + $query = $this->getQuery();
620 + while ( $query->have_posts() ) {
621 + $chart = $query->next_post();
622 + $library = $this->load_chart_type( $chart->ID );
623 + if ( is_null( $library ) ) {
624 + continue;
625 + }
626 + wp_enqueue_script(
627 + "visualizer-render-$library",
628 + VISUALIZER_ABSURL . 'js/render-facade.js',
629 + apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
630 + Visualizer_Plugin::VERSION,
631 + true
632 + );
633 + }
286 634 }
287 635 }
288 636
289 637 /**
@@ -310,24 +658,140 @@
310 658 *
311 659 * @access public
312 660 */
313 661 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 );
662 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
663 +
664 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
665 +
666 + add_submenu_page(
667 + Visualizer_Plugin::NAME,
668 + __( 'Chart Library', 'visualizer' ),
669 + __( 'Chart Library', 'visualizer' ),
670 + 'edit_posts',
671 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
672 + );
673 + add_submenu_page(
674 + Visualizer_Plugin::NAME,
675 + __( 'Add New Chart', 'visualizer' ),
676 + __( 'Add New Chart', 'visualizer' ),
677 + 'edit_posts',
678 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
679 + );
680 + add_submenu_page(
681 + Visualizer_Plugin::NAME,
682 + __( 'Support', 'visualizer' ),
683 + __( '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>',
684 + 'edit_posts',
685 + 'viz-support',
686 + array( $this, 'renderSupportPage' )
687 + );
688 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
689 +
690 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
317 691 }
318 692
319 693 /**
320 - * Renders visualizer library page.
321 - *
322 - * @since 1.0.0
323 - *
324 - * @access public
694 + * Adds the screen options for pagination.
325 695 */
326 - public function renderLibraryPage() {
696 + function addScreenOptions() {
697 + $screen = get_current_screen();
698 +
699 + // bail if it's some other page.
700 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
701 + return;
702 + }
703 +
704 + $args = array(
705 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
706 + 'default' => 6,
707 + 'option' => 'visualizer_per_page_library',
708 + );
709 + add_screen_option( 'per_page', $args );
710 + }
711 +
712 + /**
713 + * Returns the screen option for pagination.
714 + */
715 + function setScreenOptions( $status, $option, $value ) {
716 + if ( 'visualizer_per_page_library' === $option ) {
717 + return $value;
718 + }
719 + }
720 +
721 + /**
722 + * Adds the display filters to be used in the meta_query while displaying the charts.
723 + */
724 + private function getDisplayFilters( &$query_args ) {
725 + $query = array();
726 +
727 + // add chart type filter to the query arguments
728 + $type = filter_input( INPUT_GET, 'type' );
729 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
730 + $query[] = array(
731 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
732 + 'value' => $type,
733 + 'compare' => '=',
734 + );
735 + }
736 +
737 + // add chart library filter to the query arguments
738 + $library = filter_input( INPUT_GET, 'library' );
739 + if ( $library ) {
740 + $query[] = array(
741 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
742 + 'value' => $library,
743 + 'compare' => '=',
744 + );
745 + }
746 +
747 + // add date filter to the query arguments
748 + $date = filter_input( INPUT_GET, 'date' );
749 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
750 + if ( $date && in_array( $date, $possible, true ) ) {
751 + $query_args['date_query'] = array(
752 + 'after' => "$date -1 day",
753 + 'inclusive' => true,
754 + );
755 + }
756 +
757 + // add source filter to the query arguments
758 + $source = filter_input( INPUT_GET, 'source' );
759 + if ( $source ) {
760 + $source = ucwords( $source );
761 + $source = "Visualizer_Source_{$source}";
762 + $query[] = array(
763 + 'key' => Visualizer_Plugin::CF_SOURCE,
764 + 'value' => $source,
765 + 'compare' => '=',
766 + );
767 + }
768 +
769 + $query_args['meta_query'] = $query;
770 +
771 + $orderby = filter_input( INPUT_GET, 'orderby' );
772 + $order = filter_input( INPUT_GET, 'order' );
773 + if ( $orderby ) {
774 + $query_args['order_by'] = $orderby;
775 + }
776 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
777 + }
778 +
779 + /**
780 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
781 + */
782 + private function getQuery() {
783 + static $q;
784 + if ( ! is_null( $q ) ) {
785 + return $q;
786 + }
787 +
327 788 // get current page
328 789 $page = filter_input(
329 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
790 + INPUT_GET,
791 + 'vpage',
792 + FILTER_VALIDATE_INT,
793 + array(
330 794 'options' => array(
331 795 'min_range' => 1,
332 796 'default' => 1,
333 797 ),
@@ -332,27 +796,32 @@
332 796 'default' => 1,
333 797 ),
334 798 )
335 799 );
800 +
801 + $per_page = 6;
802 + $screen = get_current_screen();
803 + if ( $screen ) {
804 + // retrieve the per_page option
805 + $screen_option = $screen->get_option( 'per_page', 'option' );
806 + // retrieve the value stored for the current user
807 + $user = get_current_user_id();
808 + $per_page = get_user_meta( $user, $screen_option, true );
809 + if ( empty( $per_page ) || $per_page < 1 ) {
810 + // nothing set, get the default value
811 + $per_page = $screen->get_option( 'per_page', 'default' );
812 + }
813 + }
814 +
336 815 // the initial query arguments to fetch charts
337 816 $query_args = array(
338 817 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
339 - 'posts_per_page' => 6,
818 + 'posts_per_page' => $per_page,
340 819 'paged' => $page,
341 820 );
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 - }
821 +
822 + $this->getDisplayFilters( $query_args );
823 +
355 824 // Added by Ash/Upwork
356 825 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
357 826 if ( $filterByMeta ) {
358 827 $query = array(
@@ -363,49 +832,134 @@
363 832 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
364 833 $meta[] = $query;
365 834 $query_args['meta_query'] = $meta;
366 835 }
367 - // Added by Ash/Upwork
368 - // fetch charts
836 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
837 + return $q;
838 + }
839 +
840 + /**
841 + * Renders support page.
842 + *
843 + * @since 3.3.0
844 + *
845 + * @access public
846 + */
847 + public function renderSupportPage() {
848 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
849 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
850 + }
851 +
852 + /**
853 + * Renders visualizer library page.
854 + *
855 + * @since 1.0.0
856 + *
857 + * @access public
858 + */
859 + public function renderLibraryPage() {
369 860 $charts = array();
370 - $query = new WP_Query( $query_args );
861 + $query = $this->getQuery();
862 +
863 + // get current page
864 + $page = filter_input(
865 + INPUT_GET,
866 + 'vpage',
867 + FILTER_VALIDATE_INT,
868 + array(
869 + 'options' => array(
870 + 'min_range' => 1,
871 + 'default' => 1,
872 + ),
873 + )
874 + );
875 + // add chart type filter to the query arguments
876 + $filter = filter_input( INPUT_GET, 'type' );
877 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
878 + $filter = 'all';
879 + }
880 +
881 + $css = '';
371 882 while ( $query->have_posts() ) {
372 883 $chart = $query->next_post();
884 +
885 + // 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.
886 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
887 + // refresh a "live" db query chart.
888 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
889 +
890 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
891 +
373 892 // fetch and update settings
374 893 $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 );
894 +
895 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
896 + if ( ! empty( $atts['settings'] ) ) {
897 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
898 + }
899 +
900 + if ( $settings ) {
901 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
902 + }
903 +
377 904 $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 );
905 + $data = self::get_chart_data( $chart, $type );
906 +
907 + $library = $this->load_chart_type( $chart->ID );
908 +
909 + $id = 'visualizer-' . $chart->ID;
910 + $arguments = $this->get_inline_custom_css( $id, $settings );
911 + if ( ! empty( $arguments ) ) {
912 + $css .= $arguments[0];
913 + $settings = $arguments[1];
914 + }
915 +
379 916 // add chart to the array
380 - $charts[ 'visualizer-' . $chart->ID ] = array(
917 + $charts[ $id ] = array(
381 918 'id' => $chart->ID,
382 919 'type' => $type,
383 920 'series' => $series,
384 921 'settings' => $settings,
385 922 'data' => $data,
923 + 'library' => $library,
386 924 );
387 925 }
388 926 // enqueue charts array
389 927 $ajaxurl = admin_url( 'admin-ajax.php' );
390 928 wp_localize_script(
391 - 'visualizer-library', 'visualizer', array(
929 + 'visualizer-library',
930 + 'visualizer',
931 + array(
932 + 'language' => $this->get_language(),
933 + 'map_api_key' => get_option( 'visualizer-map-api-key' ),
392 934 'charts' => $charts,
393 935 'urls' => array(
394 - 'base' => add_query_arg( 'vpage', false ),
936 + 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
395 937 'create' => add_query_arg(
396 938 array(
397 939 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
398 940 'library' => 'yes',
399 - ), $ajaxurl
941 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
942 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
943 + 'vaction' => false,
944 + ),
945 + $ajaxurl
400 946 ),
401 947 'edit' => add_query_arg(
402 948 array(
403 949 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
404 950 'library' => 'yes',
405 - ), $ajaxurl
951 + 'vaction' => false,
952 + ),
953 + $ajaxurl
406 954 ),
407 955 ),
956 + 'page_type' => 'library',
957 + 'is_front' => false,
958 + 'i10n' => array(
959 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
960 + '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' ),
961 + ),
408 962 )
409 963 );
410 964 // render library page
411 965 $render = new Visualizer_Render_Library();
@@ -410,12 +964,13 @@
410 964 // render library page
411 965 $render = new Visualizer_Render_Library();
412 966 $render->charts = $charts;
413 967 $render->type = $filter;
414 - $render->types = self::_getChartTypesLocalized();
968 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
969 + $render->custom_css = $css;
415 970 $render->pagination = paginate_links(
416 971 array(
417 - 'base' => add_query_arg( 'vpage', '%#%' ),
972 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
418 973 'format' => '',
419 974 'current' => $page,
420 975 'total' => $query->max_num_pages,
421 976 'type' => 'array',
@@ -436,14 +991,14 @@
436 991 *
437 992 * @return array Updated array of action links.
438 993 */
439 994 public function getPluginActionLinks( $links, $file ) {
440 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
995 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
441 996 array_unshift(
442 997 $links,
443 998 sprintf(
444 999 '<a href="%s">%s</a>',
445 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1000 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
446 1001 esc_html__( 'Library', 'visualizer' )
447 1002 )
448 1003 );
449 1004 }
@@ -463,17 +1018,17 @@
463 1018 *
464 1019 * @return array Updated array of plugin meta links.
465 1020 */
466 1021 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
467 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1022 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
468 1023 // knowledge base link
469 1024 $plugin_meta[] = sprintf(
470 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
471 - esc_html__( 'Knowledge Base', 'visualizer' )
1025 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1026 + esc_html__( 'Docs', 'visualizer' )
472 1027 );
473 1028 // flattr link
474 1029 $plugin_meta[] = sprintf(
475 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1030 + '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
476 1031 esc_html__( 'Pro Addon', 'visualizer' )
477 1032 );
478 1033 }
479 1034