PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.4
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.4
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 +690 -113 3.0.53.4.4 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_DataTable::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,104 @@
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 + 'dataTable' => array(
396 + 'name' => esc_html__( 'Table', 'visualizer' ),
397 + 'enabled' => true,
398 + 'supports' => array( '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 + 'table' => array(
454 + 'name' => esc_html__( 'Table (Deprecated)', 'visualizer' ),
455 + 'enabled' => false,
456 + 'supports' => array( 'Google Charts' ),
457 + ),
458 + 'timeline' => array(
459 + 'name' => esc_html__( 'Timeline', 'visualizer' ),
460 + 'enabled' => false,
461 + 'supports' => array( 'Google Charts', 'ChartJS' ),
462 + ),
463 + 'combo' => array(
464 + 'name' => esc_html__( 'Combo', 'visualizer' ),
465 + 'enabled' => false,
466 + 'supports' => array( 'Google Charts' ),
467 + ),
468 + 'polarArea' => array(
469 + 'name' => esc_html__( 'Polar Area', 'visualizer' ),
470 + 'enabled' => false,
471 + 'supports' => array( 'ChartJS' ),
472 + ),
473 + 'radar' => array(
474 + 'name' => esc_html__( 'Radar/Spider', 'visualizer' ),
475 + 'enabled' => false,
476 + 'supports' => array( 'ChartJS' ),
477 + ),
478 + )
207 479 );
208 480 $types = apply_filters( 'visualizer_pro_chart_types', $types );
209 481 if ( $enabledOnly ) {
210 482 $filtered = array();
@@ -212,8 +484,12 @@
212 484 if ( ! is_array( $array ) ) {
213 485 // support for old pro
214 486 $array = array( 'enabled' => true, 'name' => $array );
215 487 }
488 + // backward compatibility for PRO before v1.9.0
489 + if ( ! array_key_exists( 'supports', $array ) ) {
490 + $array['supports'] = array( 'Google Charts' );
491 + }
216 492 if ( ! $array['enabled'] ) {
217 493 continue;
218 494 }
219 495 $filtered[ $type ] = $array;
@@ -226,13 +502,94 @@
226 502 if ( ! is_array( $array ) ) {
227 503 // support for old pro
228 504 $array = array( 'enabled' => true, 'name' => $array );
229 505 }
506 + // backward compatibility for PRO before v1.9.0
507 + if ( ! array_key_exists( 'supports', $array ) ) {
508 + $array['supports'] = array( 'Google Charts' );
509 + }
230 510 $doubleD[ $type ] = $array['name'];
231 511 }
232 512 $types = $doubleD;
233 513 }
234 514
515 + return self::handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where );
516 + }
517 +
518 + /**
519 + * Handle (soon-to-be) deprecated charts.
520 + */
521 + private static function handleDeprecatedCharts( $types, $enabledOnly, $get2Darray, $where ) {
522 + $deprecated = array();
523 +
524 + switch ( $where ) {
525 + case 'types':
526 + // fall-through
527 + case 'library':
528 + // if the user has a Google Table chart, show it as deprecated otherwise remove the option from the library.
529 + if ( ! self::hasChartType( 'table' ) ) {
530 + $deprecated[] = 'table';
531 + if ( $get2Darray ) {
532 + $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
533 + } else {
534 + $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
535 + }
536 + }
537 +
538 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
539 + if ( ! Visualizer_Module::is_pro() ) {
540 + if ( ! self::hasChartType( 'gauge' ) ) {
541 + if ( $get2Darray ) {
542 + $deprecated[] = 'gauge';
543 + } else {
544 + $types['gauge']['enabled'] = false;
545 + }
546 + }
547 + if ( ! self::hasChartType( 'candlestick' ) ) {
548 + if ( $get2Darray ) {
549 + $deprecated[] = 'candlestick';
550 + } else {
551 + $types['candlestick']['enabled'] = false;
552 + }
553 + }
554 + }
555 + break;
556 + default:
557 + // remove the option to create a Google Table chart.
558 + $deprecated[] = 'table';
559 +
560 + // rename the new table chart type.
561 + if ( $get2Darray ) {
562 + $types['dataTable'] = esc_html__( 'Table', 'visualizer' );
563 + } else {
564 + $types['dataTable']['name'] = esc_html__( 'Table', 'visualizer' );
565 + }
566 +
567 + // if a user has a Gauge/Candlestick chart, then let them keep using it.
568 + if ( ! Visualizer_Module::is_pro() ) {
569 + if ( ! self::hasChartType( 'gauge' ) ) {
570 + if ( $get2Darray ) {
571 + $deprecated[] = 'gauge';
572 + } else {
573 + $types['gauge']['enabled'] = false;
574 + }
575 + }
576 + if ( ! self::hasChartType( 'candlestick' ) ) {
577 + if ( $get2Darray ) {
578 + $deprecated[] = 'candlestick';
579 + } else {
580 + $types['candlestick']['enabled'] = false;
581 + }
582 + }
583 + }
584 + }
585 +
586 + if ( $deprecated ) {
587 + foreach ( $deprecated as $type ) {
588 + unset( $types[ $type ] );
589 + }
590 + }
591 +
235 592 return $types;
236 593 }
237 594
238 595 /**
@@ -242,11 +599,11 @@
242 599 * @global string $pagenow The name of the current page.
243 600 *
244 601 * @access public
245 602 */
246 - public function renderTempaltes() {
603 + public function renderTemplates() {
247 604 global $pagenow;
248 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
605 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
249 606 return;
250 607 }
251 608 $render = new Visualizer_Render_Templates();
252 609 $render->render();
@@ -264,26 +621,40 @@
264 621 *
265 622 * @param string $suffix The current page suffix.
266 623 */
267 624 public function enqueueLibraryScripts( $suffix ) {
268 - if ( $suffix == $this->_libraryPage ) {
625 + if ( $suffix === $this->_libraryPage ) {
269 626 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
270 627 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
271 628 wp_enqueue_media();
272 629 wp_enqueue_script(
273 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
630 + 'visualizer-library',
631 + VISUALIZER_ABSURL . 'js/library.js',
632 + array(
274 633 'jquery',
275 634 'media-views',
276 - ), Visualizer_Plugin::VERSION, true
635 + ),
636 + Visualizer_Plugin::VERSION,
637 + true
277 638 );
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 - );
639 +
640 + wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
641 +
642 + $query = $this->getQuery();
643 + while ( $query->have_posts() ) {
644 + $chart = $query->next_post();
645 + $library = $this->load_chart_type( $chart->ID );
646 + if ( is_null( $library ) ) {
647 + continue;
648 + }
649 + wp_enqueue_script(
650 + "visualizer-render-$library",
651 + VISUALIZER_ABSURL . 'js/render-facade.js',
652 + apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
653 + Visualizer_Plugin::VERSION,
654 + true
655 + );
656 + }
286 657 }
287 658 }
288 659
289 660 /**
@@ -310,24 +681,140 @@
310 681 *
311 682 * @access public
312 683 */
313 684 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 );
685 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
686 +
687 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
688 +
689 + add_submenu_page(
690 + Visualizer_Plugin::NAME,
691 + __( 'Chart Library', 'visualizer' ),
692 + __( 'Chart Library', 'visualizer' ),
693 + 'edit_posts',
694 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
695 + );
696 + add_submenu_page(
697 + Visualizer_Plugin::NAME,
698 + __( 'Add New Chart', 'visualizer' ),
699 + __( 'Add New Chart', 'visualizer' ),
700 + 'edit_posts',
701 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
702 + );
703 + add_submenu_page(
704 + Visualizer_Plugin::NAME,
705 + __( 'Support', 'visualizer' ),
706 + __( '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>',
707 + 'edit_posts',
708 + 'viz-support',
709 + array( $this, 'renderSupportPage' )
710 + );
711 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
712 +
713 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
317 714 }
318 715
319 716 /**
320 - * Renders visualizer library page.
321 - *
322 - * @since 1.0.0
323 - *
324 - * @access public
717 + * Adds the screen options for pagination.
325 718 */
326 - public function renderLibraryPage() {
719 + function addScreenOptions() {
720 + $screen = get_current_screen();
721 +
722 + // bail if it's some other page.
723 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
724 + return;
725 + }
726 +
727 + $args = array(
728 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
729 + 'default' => 6,
730 + 'option' => 'visualizer_per_page_library',
731 + );
732 + add_screen_option( 'per_page', $args );
733 + }
734 +
735 + /**
736 + * Returns the screen option for pagination.
737 + */
738 + function setScreenOptions( $status, $option, $value ) {
739 + if ( 'visualizer_per_page_library' === $option ) {
740 + return $value;
741 + }
742 + }
743 +
744 + /**
745 + * Adds the display filters to be used in the meta_query while displaying the charts.
746 + */
747 + private function getDisplayFilters( &$query_args ) {
748 + $query = array();
749 +
750 + // add chart type filter to the query arguments
751 + $type = filter_input( INPUT_GET, 'type' );
752 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
753 + $query[] = array(
754 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
755 + 'value' => $type,
756 + 'compare' => '=',
757 + );
758 + }
759 +
760 + // add chart library filter to the query arguments
761 + $library = filter_input( INPUT_GET, 'library' );
762 + if ( $library ) {
763 + $query[] = array(
764 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
765 + 'value' => $library,
766 + 'compare' => '=',
767 + );
768 + }
769 +
770 + // add date filter to the query arguments
771 + $date = filter_input( INPUT_GET, 'date' );
772 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
773 + if ( $date && in_array( $date, $possible, true ) ) {
774 + $query_args['date_query'] = array(
775 + 'after' => "$date -1 day",
776 + 'inclusive' => true,
777 + );
778 + }
779 +
780 + // add source filter to the query arguments
781 + $source = filter_input( INPUT_GET, 'source' );
782 + if ( $source ) {
783 + $source = ucwords( $source );
784 + $source = "Visualizer_Source_{$source}";
785 + $query[] = array(
786 + 'key' => Visualizer_Plugin::CF_SOURCE,
787 + 'value' => $source,
788 + 'compare' => '=',
789 + );
790 + }
791 +
792 + $query_args['meta_query'] = $query;
793 +
794 + $orderby = filter_input( INPUT_GET, 'orderby' );
795 + $order = filter_input( INPUT_GET, 'order' );
796 + if ( $orderby ) {
797 + $query_args['order_by'] = $orderby;
798 + }
799 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
800 + }
801 +
802 + /**
803 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
804 + */
805 + private function getQuery() {
806 + static $q;
807 + if ( ! is_null( $q ) ) {
808 + return $q;
809 + }
810 +
327 811 // get current page
328 812 $page = filter_input(
329 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
813 + INPUT_GET,
814 + 'vpage',
815 + FILTER_VALIDATE_INT,
816 + array(
330 817 'options' => array(
331 818 'min_range' => 1,
332 819 'default' => 1,
333 820 ),
@@ -332,27 +819,32 @@
332 819 'default' => 1,
333 820 ),
334 821 )
335 822 );
823 +
824 + $per_page = 6;
825 + $screen = get_current_screen();
826 + if ( $screen ) {
827 + // retrieve the per_page option
828 + $screen_option = $screen->get_option( 'per_page', 'option' );
829 + // retrieve the value stored for the current user
830 + $user = get_current_user_id();
831 + $per_page = get_user_meta( $user, $screen_option, true );
832 + if ( empty( $per_page ) || $per_page < 1 ) {
833 + // nothing set, get the default value
834 + $per_page = $screen->get_option( 'per_page', 'default' );
835 + }
836 + }
837 +
336 838 // the initial query arguments to fetch charts
337 839 $query_args = array(
338 840 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
339 - 'posts_per_page' => 6,
841 + 'posts_per_page' => $per_page,
340 842 'paged' => $page,
341 843 );
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 - }
844 +
845 + $this->getDisplayFilters( $query_args );
846 +
355 847 // Added by Ash/Upwork
356 848 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
357 849 if ( $filterByMeta ) {
358 850 $query = array(
@@ -363,49 +855,133 @@
363 855 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
364 856 $meta[] = $query;
365 857 $query_args['meta_query'] = $meta;
366 858 }
367 - // Added by Ash/Upwork
368 - // fetch charts
859 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
860 + return $q;
861 + }
862 +
863 + /**
864 + * Renders support page.
865 + *
866 + * @since 3.3.0
867 + *
868 + * @access public
869 + */
870 + public function renderSupportPage() {
871 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
872 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
873 + }
874 +
875 + /**
876 + * Renders visualizer library page.
877 + *
878 + * @since 1.0.0
879 + *
880 + * @access public
881 + */
882 + public function renderLibraryPage() {
369 883 $charts = array();
370 - $query = new WP_Query( $query_args );
884 + $query = $this->getQuery();
885 +
886 + // get current page
887 + $page = filter_input(
888 + INPUT_GET,
889 + 'vpage',
890 + FILTER_VALIDATE_INT,
891 + array(
892 + 'options' => array(
893 + 'min_range' => 1,
894 + 'default' => 1,
895 + ),
896 + )
897 + );
898 + // add chart type filter to the query arguments
899 + $filter = filter_input( INPUT_GET, 'type' );
900 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
901 + $filter = 'all';
902 + }
903 +
904 + $css = '';
371 905 while ( $query->have_posts() ) {
372 906 $chart = $query->next_post();
907 +
908 + // 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.
909 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
910 + // refresh a "live" db query chart.
911 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
912 +
913 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
914 +
373 915 // fetch and update settings
374 916 $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 );
917 +
918 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
919 + if ( ! empty( $atts['settings'] ) ) {
920 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
921 + }
922 +
923 + if ( $settings ) {
924 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
925 + }
926 +
377 927 $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 );
928 + $data = self::get_chart_data( $chart, $type );
929 +
930 + $library = $this->load_chart_type( $chart->ID );
931 +
932 + $id = 'visualizer-' . $chart->ID;
933 + $arguments = $this->get_inline_custom_css( $id, $settings );
934 + if ( ! empty( $arguments ) ) {
935 + $css .= $arguments[0];
936 + $settings = $arguments[1];
937 + }
938 +
379 939 // add chart to the array
380 - $charts[ 'visualizer-' . $chart->ID ] = array(
940 + $charts[ $id ] = array(
381 941 'id' => $chart->ID,
382 942 'type' => $type,
383 943 'series' => $series,
384 944 'settings' => $settings,
385 945 'data' => $data,
946 + 'library' => $library,
386 947 );
387 948 }
388 949 // enqueue charts array
389 950 $ajaxurl = admin_url( 'admin-ajax.php' );
390 951 wp_localize_script(
391 - 'visualizer-library', 'visualizer', array(
952 + 'visualizer-library',
953 + 'visualizer',
954 + array(
955 + 'language' => $this->get_language(),
956 + 'map_api_key' => get_option( 'visualizer-map-api-key' ),
392 957 'charts' => $charts,
393 958 'urls' => array(
394 - 'base' => add_query_arg( 'vpage', false ),
959 + 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
395 960 'create' => add_query_arg(
396 961 array(
397 962 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
398 963 'library' => 'yes',
399 - ), $ajaxurl
964 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
965 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
966 + 'vaction' => false,
967 + ),
968 + $ajaxurl
400 969 ),
401 970 'edit' => add_query_arg(
402 971 array(
403 972 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
404 973 'library' => 'yes',
405 - ), $ajaxurl
974 + 'vaction' => false,
975 + ),
976 + $ajaxurl
406 977 ),
407 978 ),
979 + 'page_type' => 'library',
980 + 'is_front' => false,
981 + 'i10n' => array(
982 + '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' ),
983 + ),
408 984 )
409 985 );
410 986 // render library page
411 987 $render = new Visualizer_Render_Library();
@@ -410,12 +986,13 @@
410 986 // render library page
411 987 $render = new Visualizer_Render_Library();
412 988 $render->charts = $charts;
413 989 $render->type = $filter;
414 - $render->types = self::_getChartTypesLocalized();
990 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
991 + $render->custom_css = $css;
415 992 $render->pagination = paginate_links(
416 993 array(
417 - 'base' => add_query_arg( 'vpage', '%#%' ),
994 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
418 995 'format' => '',
419 996 'current' => $page,
420 997 'total' => $query->max_num_pages,
421 998 'type' => 'array',
@@ -436,14 +1013,14 @@
436 1013 *
437 1014 * @return array Updated array of action links.
438 1015 */
439 1016 public function getPluginActionLinks( $links, $file ) {
440 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1017 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
441 1018 array_unshift(
442 1019 $links,
443 1020 sprintf(
444 1021 '<a href="%s">%s</a>',
445 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1022 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
446 1023 esc_html__( 'Library', 'visualizer' )
447 1024 )
448 1025 );
449 1026 }
@@ -463,17 +1040,17 @@
463 1040 *
464 1041 * @return array Updated array of plugin meta links.
465 1042 */
466 1043 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
467 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1044 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
468 1045 // knowledge base link
469 1046 $plugin_meta[] = sprintf(
470 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
471 - esc_html__( 'Knowledge Base', 'visualizer' )
1047 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1048 + esc_html__( 'Docs', 'visualizer' )
472 1049 );
473 1050 // flattr link
474 1051 $plugin_meta[] = sprintf(
475 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1052 + '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
476 1053 esc_html__( 'Pro Addon', 'visualizer' )
477 1054 );
478 1055 }
479 1056