PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.6.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.6.1
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
← All changes | classes/Visualizer/Module/Admin.php +572 -70 3.0.63.6.1 View file →
@@ -52,34 +52,193 @@
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 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 +
65 75 $this->_addAction( 'admin_init', 'init' );
76 +
77 + if ( defined( 'TI_CYPRESS_TESTING' ) ) {
78 + $this->load_cypress_hooks();
79 + }
80 +
66 81 }
67 82
68 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 + /**
69 213 * Admin init.
70 214 *
71 215 * @access public
72 216 */
73 217 public function init() {
218 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
74 219 if ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) && 'true' == get_user_option( 'rich_editing' ) ) {
75 220 $this->_addFilter( 'mce_external_languages', 'add_tinymce_lang', 10, 1 );
76 221 $this->_addFilter( 'mce_external_plugins', 'tinymce_plugin', 10, 1 );
77 222 $this->_addFilter( 'mce_buttons', 'register_mce_button', 10, 1 );
223 + $this->_addFilter( 'tiny_mce_before_init', 'get_strings_for_block', 10, 1 );
78 224 }
79 225 }
80 226
81 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 + /**
82 241 * Load plugin translation for - TinyMCE API
83 242 *
84 243 * @access public
85 244 * @param array $arr The tinymce_lang array.
@@ -150,14 +309,28 @@
150 309 public function enqueueMediaScripts() {
151 310 global $typenow;
152 311 if ( post_type_supports( $typenow, 'editor' ) ) {
153 312 wp_enqueue_style( 'visualizer-media', VISUALIZER_ABSURL . 'css/media.css', array( 'media-views' ), Visualizer_Plugin::VERSION );
154 - wp_enqueue_script( 'visualizer-google-jsapi-new', '//www.gstatic.com/charts/loader.js', array( 'media-editor' ), null, true );
155 - wp_enqueue_script( 'visualizer-google-jsapi-old', '//www.google.com/jsapi', array( 'visualizer-google-jsapi-new' ), null, true );
156 - 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 );
157 321 wp_enqueue_script( 'visualizer-media-collection', VISUALIZER_ABSURL . 'js/media/collection.js', array( 'visualizer-media-model' ), Visualizer_Plugin::VERSION, true );
158 322 wp_enqueue_script( 'visualizer-media-controller', VISUALIZER_ABSURL . 'js/media/controller.js', array( 'visualizer-media-collection' ), Visualizer_Plugin::VERSION, true );
159 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 + );
160 333 wp_enqueue_script( 'visualizer-media-toolbar', VISUALIZER_ABSURL . 'js/media/toolbar.js', array( 'visualizer-media-view' ), Visualizer_Plugin::VERSION, true );
161 334 wp_enqueue_script( 'visualizer-media', VISUALIZER_ABSURL . 'js/media.js', array( 'visualizer-media-toolbar' ), Visualizer_Plugin::VERSION, true );
162 335 }
163 336 }
@@ -206,9 +379,9 @@
206 379 * @static
207 380 * @access private
208 381 * @return array The associated array of chart types with localized names.
209 382 */
210 - public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false ) {
383 + public static function _getChartTypesLocalized( $enabledOnly = false, $get2Darray = false, $add_select = false, $where = null ) {
211 384 $additional = array();
212 385 if ( $add_select ) {
213 386 $additional['select'] = array(
214 387 'name' => esc_html__( 'All', 'visualizer' ),
@@ -216,58 +389,88 @@
216 389 );
217 390 }
218 391
219 392 $types = array_merge(
220 - $additional, array(
393 + $additional,
394 + array(
395 + 'tabular' => array(
396 + 'name' => esc_html__( 'Table', 'visualizer' ),
397 + 'enabled' => true,
398 + 'supports' => array( 'Google Charts', 'DataTable' ),
399 + ),
221 400 'pie' => array(
222 - 'name' => esc_html__( 'Pie', 'visualizer' ),
401 + 'name' => esc_html__( 'Pie/Donut', 'visualizer' ),
223 402 'enabled' => true,
403 + 'supports' => array( 'Google Charts', 'ChartJS' ),
224 404 ),
225 405 'line' => array(
226 406 'name' => esc_html__( 'Line', 'visualizer' ),
227 407 'enabled' => true,
408 + 'supports' => array( 'Google Charts', 'ChartJS' ),
228 409 ),
229 410 'area' => array(
230 411 'name' => esc_html__( 'Area', 'visualizer' ),
231 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' ),
232 415 ),
233 416 'geo' => array(
234 417 'name' => esc_html__( 'Geo', 'visualizer' ),
235 418 'enabled' => true,
419 + 'supports' => array( 'Google Charts' ),
236 420 ),
237 421 'bar' => array(
238 422 'name' => esc_html__( 'Bar', 'visualizer' ),
239 423 'enabled' => true,
424 + 'supports' => array( 'Google Charts', 'ChartJS' ),
240 425 ),
241 426 'column' => array(
242 427 'name' => esc_html__( 'Column', 'visualizer' ),
243 428 'enabled' => true,
429 + 'supports' => array( 'Google Charts', 'ChartJS' ),
244 430 ),
245 - 'gauge' => array(
246 - 'name' => esc_html__( 'Gauge', 'visualizer' ),
431 + 'bubble' => array(
432 + 'name' => esc_html__( 'Bubble', 'visualizer' ),
247 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' ),
248 436 ),
249 437 'scatter' => array(
250 438 'name' => esc_html__( 'Scatter', 'visualizer' ),
251 439 'enabled' => true,
440 + 'supports' => array( 'Google Charts' ),
252 441 ),
442 + 'gauge' => array(
443 + 'name' => esc_html__( 'Gauge', 'visualizer' ),
444 + 'enabled' => true,
445 + 'supports' => array( 'Google Charts' ),
446 + ),
253 447 'candlestick' => array(
254 448 'name' => esc_html__( 'Candlestick', 'visualizer' ),
255 449 'enabled' => true,
450 + 'supports' => array( 'Google Charts' ),
256 451 ),
257 452 // pro types
258 - 'table' => array(
259 - 'name' => esc_html__( 'Table', 'visualizer' ),
260 - 'enabled' => false,
261 - ),
262 453 'timeline' => array(
263 454 'name' => esc_html__( 'Timeline', 'visualizer' ),
264 455 'enabled' => false,
456 + 'supports' => array( 'Google Charts', 'ChartJS' ),
265 457 ),
266 458 'combo' => array(
267 459 'name' => esc_html__( 'Combo', 'visualizer' ),
268 460 'enabled' => false,
461 + 'supports' => array( 'Google Charts' ),
269 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 + ),
270 473 )
271 474 );
272 475 $types = apply_filters( 'visualizer_pro_chart_types', $types );
273 476 if ( $enabledOnly ) {
@@ -276,8 +479,12 @@
276 479 if ( ! is_array( $array ) ) {
277 480 // support for old pro
278 481 $array = array( 'enabled' => true, 'name' => $array );
279 482 }
483 + // backward compatibility for PRO before v1.9.0
484 + if ( ! array_key_exists( 'supports', $array ) ) {
485 + $array['supports'] = array( 'Google Charts' );
486 + }
280 487 if ( ! $array['enabled'] ) {
281 488 continue;
282 489 }
283 490 $filtered[ $type ] = $array;
@@ -290,13 +497,74 @@
290 497 if ( ! is_array( $array ) ) {
291 498 // support for old pro
292 499 $array = array( 'enabled' => true, 'name' => $array );
293 500 }
501 + // backward compatibility for PRO before v1.9.0
502 + if ( ! array_key_exists( 'supports', $array ) ) {
503 + $array['supports'] = array( 'Google Charts' );
504 + }
294 505 $doubleD[ $type ] = $array['name'];
295 506 }
296 507 $types = $doubleD;
297 508 }
298 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 +
299 567 return $types;
300 568 }
301 569
302 570 /**
@@ -306,11 +574,11 @@
306 574 * @global string $pagenow The name of the current page.
307 575 *
308 576 * @access public
309 577 */
310 - public function renderTempaltes() {
578 + public function renderTemplates() {
311 579 global $pagenow;
312 - if ( 'post.php' != $pagenow && 'post-new.php' != $pagenow ) {
580 + if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
313 581 return;
314 582 }
315 583 $render = new Visualizer_Render_Templates();
316 584 $render->render();
@@ -328,26 +596,41 @@
328 596 *
329 597 * @param string $suffix The current page suffix.
330 598 */
331 599 public function enqueueLibraryScripts( $suffix ) {
332 - if ( $suffix == $this->_libraryPage ) {
600 + if ( $suffix === $this->_libraryPage ) {
333 601 wp_enqueue_style( 'visualizer-library', VISUALIZER_ABSURL . 'css/library.css', array(), Visualizer_Plugin::VERSION );
334 602 $this->_addFilter( 'media_upload_tabs', 'setupVisualizerTab' );
335 603 wp_enqueue_media();
336 604 wp_enqueue_script(
337 - 'visualizer-library', VISUALIZER_ABSURL . 'js/library.js', array(
605 + 'visualizer-library',
606 + VISUALIZER_ABSURL . 'js/library.js',
607 + array(
338 608 'jquery',
339 609 'media-views',
340 - ), Visualizer_Plugin::VERSION, true
610 + 'clipboard',
611 + ),
612 + Visualizer_Plugin::VERSION,
613 + true
341 614 );
342 - wp_enqueue_script( 'google-jsapi-new', '//www.gstatic.com/charts/loader.js', array(), null, true );
343 - wp_enqueue_script( 'google-jsapi-old', '//www.google.com/jsapi', array( 'google-jsapi-new' ), null, true );
344 - wp_enqueue_script(
345 - 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array(
346 - 'google-jsapi-old',
347 - 'visualizer-library',
348 - ), Visualizer_Plugin::VERSION, true
349 - );
615 +
616 + wp_enqueue_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
617 +
618 + $query = $this->getQuery();
619 + while ( $query->have_posts() ) {
620 + $chart = $query->next_post();
621 + $library = $this->load_chart_type( $chart->ID );
622 + if ( is_null( $library ) ) {
623 + continue;
624 + }
625 + wp_enqueue_script(
626 + "visualizer-render-$library",
627 + VISUALIZER_ABSURL . 'js/render-facade.js',
628 + apply_filters( 'visualizer_assets_render', array( 'visualizer-library', 'visualizer-customization' ), true ),
629 + Visualizer_Plugin::VERSION,
630 + true
631 + );
632 + }
350 633 }
351 634 }
352 635
353 636 /**
@@ -374,24 +657,140 @@
374 657 *
375 658 * @access public
376 659 */
377 660 public function registerAdminMenu() {
378 - $title = esc_html__( 'Visualizer Library', 'visualizer' );
379 - $callback = array( $this, 'renderLibraryPage' );
380 - $this->_libraryPage = add_submenu_page( 'upload.php', $title, $title, 'edit_posts', Visualizer_Plugin::NAME, $callback );
661 + $svg_base64_icon = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPHN2ZyB3aWR0aD0iNzdweCIgaGVpZ2h0PSI3N3B4IiB2aWV3Qm94PSIwIDAgNzcgNzciIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayI+CiAgICA8IS0tIEdlbmVyYXRvcjogU2tldGNoIDUyLjYgKDY3NDkxKSAtIGh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaCAtLT4KICAgIDx0aXRsZT5Db21iaW5lZCBTaGFwZTwvdGl0bGU+CiAgICA8ZGVzYz5DcmVhdGVkIHdpdGggU2tldGNoLjwvZGVzYz4KICAgIDxnIGlkPSJQcm9kdWN0LVBhZ2UiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIiBmaWxsPSJub25lIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiPgogICAgICAgIDxnIGlkPSJXb3JkUHJlc3MtcGx1Z2lucyIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5MC4wMDAwMDAsIC00MzUuMDAwMDAwKSIgZmlsbD0iIzM5QzNEMiI+CiAgICAgICAgICAgIDxwYXRoIGQ9Ik0yMjguNSw1MTIgQzIwNy4yMzcwMzcsNTEyIDE5MCw0OTQuNzYyOTYzIDE5MCw0NzMuNSBDMTkwLDQ1Mi4yMzcwMzcgMjA3LjIzNzAzNyw0MzUgMjI4LjUsNDM1IEMyNDkuNzYyOTYzLDQzNSAyNjcsNDUyLjIzNzAzNyAyNjcsNDczLjUgQzI2Nyw0OTQuNzYyOTYzIDI0OS43NjI5NjMsNTEyIDIyOC41LDUxMiBaIE0yNDYuODQzNzUsNDgzLjU5MjA1OSBMMjE1LjYyNSw0ODMuNTkyMDU5IEwyMTUuNjI1LDQ2MC44MjY1NDQgQzIxNS42MjUsNDYwLjE2NDU0NyAyMTUuMTA3NTc4LDQ1OS42MjgzNTkgMjE0LjQ2ODc1LDQ1OS42MjgzNTkgTDIxMi4xNTYyNSw0NTkuNjI4MzU5IEMyMTEuNTE3NDIyLDQ1OS42MjgzNTkgMjExLDQ2MC4xNjQ1NDcgMjExLDQ2MC44MjY1NDQgTDIxMSw0ODUuOTg4NDI5IEMyMTEsNDg3LjMxMTY3NCAyMTIuMDM1NTY2LDQ4OC4zODQ3OTggMjEzLjMxMjUsNDg4LjM4NDc5OCBMMjQ2Ljg0Mzc1LDQ4OC4zODQ3OTggQzI0Ny40ODI1NzgsNDg4LjM4NDc5OCAyNDgsNDg3Ljg0ODYxMSAyNDgsNDg3LjE4NjYxMyBMMjQ4LDQ4NC43OTAyNDQgQzI0OCw0ODQuMTI4MjQ2IDI0Ny40ODI1NzgsNDgzLjU5MjA1OSAyNDYuODQzNzUsNDgzLjU5MjA1OSBaIE0yNDQuNTMxMjUsNDYyLjAyNDcyOSBMMjM1Ljk5OTU3LDQ2Mi4wMjQ3MjkgQzIzNC40NTQ1MzEsNDYyLjAyNDcyOSAyMzMuNjgwNTY2LDQ2My45NjA1NDcgMjM0Ljc3MzIyMyw0NjUuMDkyODMyIEwyMzcuMTE0NjI5LDQ2Ny41MTkxNTYgTDIzMS44MTI1LDQ3My4wMTQzMzIgTDIyNi41MTAzNzEsNDY3LjUxOTkwNSBDMjI1LjYwNzA1MSw0NjYuNTgzODIzIDIyNC4xNDI5NDksNDY2LjU4MzgyMyAyMjMuMjQwMzUyLDQ2Ny41MTk5MDUgTDIxOC4yNzY0MjYsNDcyLjY2Mzg2MyBDMjE3LjgyNDc2Niw0NzMuMTMxOTA0IDIxNy44MjQ3NjYsNDczLjg5MDUwNSAyMTguMjc2NDI2LDQ3NC4zNTg1NDYgTDIxOS45MTEwNzQsNDc2LjA1MjQ4IEMyMjAuMzYyNzM0LDQ3Ni41MjA1MjEgMjIxLjA5NDc4NSw0NzYuNTIwNTIxIDIyMS41NDY0NDUsNDc2LjA1MjQ4IEwyMjQuODc1LDQ3Mi42MDI0NTYgTDIzMC4xNzcxMjksNDc4LjA5Njg4MyBDMjMxLjA4MDQ0OSw0NzkuMDMyOTY1IDIzMi41NDQ1NTEsNDc5LjAzMjk2NSAyMzMuNDQ3MTQ4LDQ3OC4wOTY4ODMgTDI0MC4zODQ2NDgsNDcwLjkwNzc3MyBMMjQyLjcyNjA1NSw0NzMuMzM0MDk4IEMyNDMuODE4NzExLDQ3NC40NjYzODIgMjQ1LjY4Njc3Nyw0NzMuNjY0MzQ3IDI0NS42ODY3NzcsNDcyLjA2MzI3MyBMMjQ1LjY4Njc3Nyw0NjMuMjIyOTE0IEMyNDUuNjg3NSw0NjIuNTYwOTE3IDI0NS4xNzAwNzgsNDYyLjAyNDcyOSAyNDQuNTMxMjUsNDYyLjAyNDcyOSBaIiBpZD0iQ29tYmluZWQtU2hhcGUiPjwvcGF0aD4KICAgICAgICA8L2c+CiAgICA8L2c+Cjwvc3ZnPg==';
662 +
663 + $this->_libraryPage = add_menu_page( __( 'Visualizer', 'visualizer' ), __( 'Visualizer', 'visualizer' ), 'edit_posts', Visualizer_Plugin::NAME, array( $this, 'renderLibraryPage' ), $svg_base64_icon, 99.7666 );
664 +
665 + add_submenu_page(
666 + Visualizer_Plugin::NAME,
667 + __( 'Chart Library', 'visualizer' ),
668 + __( 'Chart Library', 'visualizer' ),
669 + 'edit_posts',
670 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME )
671 + );
672 + add_submenu_page(
673 + Visualizer_Plugin::NAME,
674 + __( 'Add New Chart', 'visualizer' ),
675 + __( 'Add New Chart', 'visualizer' ),
676 + 'edit_posts',
677 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME . '&vaction=addnew' )
678 + );
679 + add_submenu_page(
680 + Visualizer_Plugin::NAME,
681 + __( 'Support', 'visualizer' ),
682 + __( '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>',
683 + 'edit_posts',
684 + 'viz-support',
685 + array( $this, 'renderSupportPage' )
686 + );
687 + remove_submenu_page( Visualizer_Plugin::NAME, Visualizer_Plugin::NAME );
688 +
689 + add_action( "load-{$this->_libraryPage}", array( $this, 'addScreenOptions' ) );
381 690 }
382 691
383 692 /**
384 - * Renders visualizer library page.
385 - *
386 - * @since 1.0.0
387 - *
388 - * @access public
693 + * Adds the screen options for pagination.
389 694 */
390 - public function renderLibraryPage() {
695 + function addScreenOptions() {
696 + $screen = get_current_screen();
697 +
698 + // bail if it's some other page.
699 + if ( ! is_object( $screen ) || $screen->id !== $this->_libraryPage ) {
700 + return;
701 + }
702 +
703 + $args = array(
704 + 'label' => __( 'Number of charts per page:', 'visualizer' ),
705 + 'default' => 6,
706 + 'option' => 'visualizer_per_page_library',
707 + );
708 + add_screen_option( 'per_page', $args );
709 + }
710 +
711 + /**
712 + * Returns the screen option for pagination.
713 + */
714 + function setScreenOptions( $status, $option, $value ) {
715 + if ( 'visualizer_per_page_library' === $option ) {
716 + return $value;
717 + }
718 + }
719 +
720 + /**
721 + * Adds the display filters to be used in the meta_query while displaying the charts.
722 + */
723 + private function getDisplayFilters( &$query_args ) {
724 + $query = array();
725 +
726 + // add chart type filter to the query arguments
727 + $type = filter_input( INPUT_GET, 'type' );
728 + if ( $type && in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
729 + $query[] = array(
730 + 'key' => Visualizer_Plugin::CF_CHART_TYPE,
731 + 'value' => $type,
732 + 'compare' => '=',
733 + );
734 + }
735 +
736 + // add chart library filter to the query arguments
737 + $library = filter_input( INPUT_GET, 'library' );
738 + if ( $library ) {
739 + $query[] = array(
740 + 'key' => Visualizer_Plugin::CF_CHART_LIBRARY,
741 + 'value' => $library,
742 + 'compare' => '=',
743 + );
744 + }
745 +
746 + // add date filter to the query arguments
747 + $date = filter_input( INPUT_GET, 'date' );
748 + $possible = array_keys( Visualizer_Plugin::getSupportedDateFilter() );
749 + if ( $date && in_array( $date, $possible, true ) ) {
750 + $query_args['date_query'] = array(
751 + 'after' => "$date -1 day",
752 + 'inclusive' => true,
753 + );
754 + }
755 +
756 + // add source filter to the query arguments
757 + $source = filter_input( INPUT_GET, 'source' );
758 + if ( $source ) {
759 + $source = ucwords( $source );
760 + $source = "Visualizer_Source_{$source}";
761 + $query[] = array(
762 + 'key' => Visualizer_Plugin::CF_SOURCE,
763 + 'value' => $source,
764 + 'compare' => '=',
765 + );
766 + }
767 +
768 + $query_args['meta_query'] = $query;
769 +
770 + $orderby = filter_input( INPUT_GET, 'orderby' );
771 + $order = filter_input( INPUT_GET, 'order' );
772 + if ( $orderby ) {
773 + $query_args['order_by'] = $orderby;
774 + }
775 + $query_args['order'] = empty( $order ) ? 'desc' : $order;
776 + }
777 +
778 + /**
779 + * Get the instance of WP_Query that fetches the charts as per the given criteria.
780 + */
781 + private function getQuery() {
782 + static $q;
783 + if ( ! is_null( $q ) ) {
784 + return $q;
785 + }
786 +
391 787 // get current page
392 788 $page = filter_input(
393 - INPUT_GET, 'vpage', FILTER_VALIDATE_INT, array(
789 + INPUT_GET,
790 + 'vpage',
791 + FILTER_VALIDATE_INT,
792 + array(
394 793 'options' => array(
395 794 'min_range' => 1,
396 795 'default' => 1,
397 796 ),
@@ -396,27 +795,32 @@
396 795 'default' => 1,
397 796 ),
398 797 )
399 798 );
799 +
800 + $per_page = 6;
801 + $screen = get_current_screen();
802 + if ( $screen ) {
803 + // retrieve the per_page option
804 + $screen_option = $screen->get_option( 'per_page', 'option' );
805 + // retrieve the value stored for the current user
806 + $user = get_current_user_id();
807 + $per_page = get_user_meta( $user, $screen_option, true );
808 + if ( empty( $per_page ) || $per_page < 1 ) {
809 + // nothing set, get the default value
810 + $per_page = $screen->get_option( 'per_page', 'default' );
811 + }
812 + }
813 +
400 814 // the initial query arguments to fetch charts
401 815 $query_args = array(
402 816 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
403 - 'posts_per_page' => 6,
817 + 'posts_per_page' => $per_page,
404 818 'paged' => $page,
405 819 );
406 - // add chart type filter to the query arguments
407 - $filter = filter_input( INPUT_GET, 'type' );
408 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
409 - $query_args['meta_query'] = array(
410 - array(
411 - 'key' => Visualizer_Plugin::CF_CHART_TYPE,
412 - 'value' => $filter,
413 - 'compare' => '=',
414 - ),
415 - );
416 - } else {
417 - $filter = 'all';
418 - }
820 +
821 + $this->getDisplayFilters( $query_args );
822 +
419 823 // Added by Ash/Upwork
420 824 $filterByMeta = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
421 825 if ( $filterByMeta ) {
422 826 $query = array(
@@ -427,49 +831,146 @@
427 831 $meta = isset( $query_args['meta_query'] ) ? $query_args['meta_query'] : array();
428 832 $meta[] = $query;
429 833 $query_args['meta_query'] = $meta;
430 834 }
431 - // Added by Ash/Upwork
432 - // fetch charts
835 + $q = new WP_Query( apply_filters( 'visualizer_query_args', $query_args ) );
836 + return $q;
837 + }
838 +
839 + /**
840 + * Renders support page.
841 + *
842 + * @since 3.3.0
843 + *
844 + * @access public
845 + */
846 + public function renderSupportPage() {
847 + wp_enqueue_style( 'visualizer-upsell', VISUALIZER_ABSURL . 'css/upsell.css', array(), Visualizer_Plugin::VERSION );
848 + include_once VISUALIZER_ABSPATH . '/templates/support.php';
849 + }
850 +
851 + /**
852 + * Renders visualizer library page.
853 + *
854 + * @since 1.0.0
855 + *
856 + * @access public
857 + */
858 + public function renderLibraryPage() {
433 859 $charts = array();
434 - $query = new WP_Query( $query_args );
860 + $query = $this->getQuery();
861 +
862 + // get current page
863 + $page = filter_input(
864 + INPUT_GET,
865 + 'vpage',
866 + FILTER_VALIDATE_INT,
867 + array(
868 + 'options' => array(
869 + 'min_range' => 1,
870 + 'default' => 1,
871 + ),
872 + )
873 + );
874 + // add chart type filter to the query arguments
875 + $filter = filter_input( INPUT_GET, 'type' );
876 + if ( ! ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) ) {
877 + $filter = 'all';
878 + }
879 +
880 + $css = '';
435 881 while ( $query->have_posts() ) {
436 882 $chart = $query->next_post();
883 +
884 + // 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.
885 + $chart = $this->handleExistingRevisions( $chart->ID, $chart );
886 + // refresh a "live" db query chart.
887 + $chart = apply_filters( 'visualizer_schedule_refresh_chart', $chart, $chart->ID, false );
888 +
889 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
890 +
437 891 // fetch and update settings
438 892 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
439 - unset( $settings['height'], $settings['width'] );
440 - $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
893 +
894 + $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
895 + if ( ! empty( $atts['settings'] ) ) {
896 + $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
897 + }
898 +
899 + if ( $settings ) {
900 + unset( $settings['height'], $settings['width'], $settings['chartArea'] );
901 + }
902 +
441 903 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
442 - $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( html_entity_decode( $chart->post_content ) ), $chart->ID, $type );
904 + $data = self::get_chart_data( $chart, $type );
905 +
906 + // Set default setting series when add manual chart data - Only during first creation.
907 + if ( isset( $settings['series'] ) && ! empty( $series ) ) {
908 + $count_series = count( $series ) - count( $settings['series'] );
909 + if ( $count_series > 1 ) {
910 + $clone_last_series = end( $settings['series'] );
911 + $clone_last_series = array_fill_keys( array_keys( $clone_last_series ), '' );
912 + foreach ( range( 1, $count_series ) as $item ) {
913 + $settings['series'][] = $clone_last_series;
914 + }
915 + }
916 + }
917 +
918 + $library = $this->load_chart_type( $chart->ID );
919 +
920 + $id = 'visualizer-' . $chart->ID;
921 + $arguments = $this->get_inline_custom_css( $id, $settings );
922 + if ( ! empty( $arguments ) ) {
923 + $css .= $arguments[0];
924 + $settings = $arguments[1];
925 + }
926 +
443 927 // add chart to the array
444 - $charts[ 'visualizer-' . $chart->ID ] = array(
928 + $charts[ $id ] = array(
445 929 'id' => $chart->ID,
446 930 'type' => $type,
447 931 'series' => $series,
448 932 'settings' => $settings,
449 933 'data' => $data,
934 + 'library' => $library,
450 935 );
451 936 }
452 937 // enqueue charts array
453 938 $ajaxurl = admin_url( 'admin-ajax.php' );
454 939 wp_localize_script(
455 - 'visualizer-library', 'visualizer', array(
940 + 'visualizer-library',
941 + 'visualizer',
942 + array(
943 + 'language' => $this->get_language(),
944 + 'map_api_key' => get_option( 'visualizer-map-api-key' ),
456 945 'charts' => $charts,
457 946 'urls' => array(
458 - 'base' => add_query_arg( 'vpage', false ),
947 + 'base' => add_query_arg( array( 'vpage' => false, 'vaction' => false ) ),
459 948 'create' => add_query_arg(
460 949 array(
461 950 'action' => Visualizer_Plugin::ACTION_CREATE_CHART,
462 951 'library' => 'yes',
463 - ), $ajaxurl
952 + 'type' => isset( $_GET['type'] ) ? $_GET['type'] : '',
953 + 'chart-library' => isset( $_GET['chart-library'] ) ? $_GET['chart-library'] : '',
954 + 'vaction' => false,
955 + ),
956 + $ajaxurl
464 957 ),
465 958 'edit' => add_query_arg(
466 959 array(
467 960 'action' => Visualizer_Plugin::ACTION_EDIT_CHART,
468 961 'library' => 'yes',
469 - ), $ajaxurl
962 + 'vaction' => false,
963 + ),
964 + $ajaxurl
470 965 ),
471 966 ),
967 + 'page_type' => 'library',
968 + 'is_front' => false,
969 + 'i10n' => array(
970 + 'copied' => __( 'The shortcode has been copied to your clipboard. Hit Ctrl-V/Cmd-V to paste it.', 'visualizer' ),
971 + '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' ),
972 + ),
472 973 )
473 974 );
474 975 // render library page
475 976 $render = new Visualizer_Render_Library();
@@ -474,12 +975,13 @@
474 975 // render library page
475 976 $render = new Visualizer_Render_Library();
476 977 $render->charts = $charts;
477 978 $render->type = $filter;
478 - $render->types = self::_getChartTypesLocalized();
979 + $render->types = self::_getChartTypesLocalized( false, false, false, true );
980 + $render->custom_css = $css;
479 981 $render->pagination = paginate_links(
480 982 array(
481 - 'base' => add_query_arg( 'vpage', '%#%' ),
983 + 'base' => add_query_arg( array( 'vpage' => '%#%', 'vaction' => false ) ),
482 984 'format' => '',
483 985 'current' => $page,
484 986 'total' => $query->max_num_pages,
485 987 'type' => 'array',
@@ -500,14 +1002,14 @@
500 1002 *
501 1003 * @return array Updated array of action links.
502 1004 */
503 1005 public function getPluginActionLinks( $links, $file ) {
504 - if ( $file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1006 + if ( $file === plugin_basename( VISUALIZER_BASEFILE ) ) {
505 1007 array_unshift(
506 1008 $links,
507 1009 sprintf(
508 1010 '<a href="%s">%s</a>',
509 - admin_url( 'upload.php?page=' . Visualizer_Plugin::NAME ),
1011 + admin_url( 'admin.php?page=' . Visualizer_Plugin::NAME ),
510 1012 esc_html__( 'Library', 'visualizer' )
511 1013 )
512 1014 );
513 1015 }
@@ -527,17 +1029,17 @@
527 1029 *
528 1030 * @return array Updated array of plugin meta links.
529 1031 */
530 1032 public function getPluginMetaLinks( $plugin_meta, $plugin_file ) {
531 - if ( $plugin_file == plugin_basename( VISUALIZER_BASEFILE ) ) {
1033 + if ( $plugin_file === plugin_basename( VISUALIZER_BASEFILE ) ) {
532 1034 // knowledge base link
533 1035 $plugin_meta[] = sprintf(
534 - '<a href="https://github.com/codeinwp/visualizer/wiki" target="_blank">%s</a>',
535 - esc_html__( 'Knowledge Base', 'visualizer' )
1036 + '<a href="' . VISUALIZER_MAIN_DOC . '" target="_blank">%s</a>',
1037 + esc_html__( 'Docs', 'visualizer' )
536 1038 );
537 1039 // flattr link
538 1040 $plugin_meta[] = sprintf(
539 - '<a style="color:red" href="https://themeisle.com/plugins/visualizer-charts-and-graphs-pro-addon/" target="_blank">%s</a>',
1041 + '<a style="color:red" href="' . Visualizer_Plugin::PRO_TEASER_URL . '" target="_blank">%s</a>',
540 1042 esc_html__( 'Pro Addon', 'visualizer' )
541 1043 );
542 1044 }
543 1045