PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.7.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.7.2
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/Chart.php +86 -330 4.0.53.7.2 View file →
@@ -69,8 +69,9 @@
69 69
70 70 $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY, 'saveFilter' );
71 71
72 72 $this->_addFilter( 'visualizer_get_sidebar', 'getSidebar', 10, 2 );
73 +
73 74 }
74 75
75 76 /**
76 77 * Generates the HTML of the sidebar for the chart.
@@ -133,22 +134,8 @@
133 134 ),
134 135 )
135 136 );
136 137
137 - if ( Visualizer_Module::is_pro() ) {
138 - $is_woocommerce_report = filter_input(
139 - INPUT_POST,
140 - 'is_woocommerce_report',
141 - FILTER_VALIDATE_BOOLEAN
142 - );
143 -
144 - if ( $is_woocommerce_report ) {
145 - update_post_meta( $chart_id, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE, true );
146 - } else {
147 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE );
148 - }
149 - }
150 -
151 138 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
152 139
153 140 if ( -1 < $time ) {
154 141 add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
@@ -169,12 +156,8 @@
169 156 */
170 157 public function getJsonRoots() {
171 158 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
172 159
173 - if ( ! current_user_can( 'edit_posts' ) ) {
174 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ) );
175 - }
176 -
177 160 $params = wp_parse_args( $_POST['params'] );
178 161
179 162 $source = new Visualizer_Source_Json( $params );
180 163
@@ -195,12 +178,8 @@
195 178 */
196 179 public function getJsonData() {
197 180 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
198 181
199 - if ( ! current_user_can( 'edit_posts' ) ) {
200 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ) );
201 - }
202 -
203 182 $params = wp_parse_args( $_POST['params'] );
204 183
205 184 $chart_id = $params['chart'];
206 185
@@ -266,16 +245,8 @@
266 245 if ( ! empty( $params['paging'] ) ) {
267 246 add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
268 247 }
269 248
270 - if ( Visualizer_Module::is_pro() ) {
271 - if ( ! empty( $params['vz_woo_source'] ) ) {
272 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE, $params['vz_woo_source'] );
273 - } else {
274 - delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE );
275 - }
276 - }
277 -
278 249 $time = filter_input(
279 250 INPUT_POST,
280 251 'time',
281 252 FILTER_VALIDATE_INT,
@@ -303,9 +274,9 @@
303 274 $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
304 275 $render->series = json_encode( $source->getSeries() );
305 276 $render->render();
306 277
307 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
278 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
308 279 }
309 280
310 281
311 282 /**
@@ -381,13 +352,13 @@
381 352 * @since 1.0.0
382 353 *
383 354 * @access private
384 355 *
385 - * @param WP_Post|null $chart The chart object.
356 + * @param WP_Post $chart The chart object.
386 357 *
387 358 * @return array The array of chart data.
388 359 */
389 - private function _getChartArray( $chart = null ) {
360 + private function _getChartArray( WP_Post $chart = null ) {
390 361 if ( is_null( $chart ) ) {
391 362 $chart = $this->_chart;
392 363 }
393 364 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
@@ -409,13 +380,8 @@
409 380 }
410 381
411 382 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
412 383
413 - $code = '';
414 - if ( 'd3' === $library ) {
415 - $code = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
416 - }
417 -
418 384 return array(
419 385 'type' => $type,
420 386 'series' => $series,
421 387 'settings' => $settings,
@@ -420,9 +386,8 @@
420 386 'series' => $series,
421 387 'settings' => $settings,
422 388 'data' => $data,
423 389 'library' => $library,
424 - 'code' => $code,
425 390 'css' => $css,
426 391 'date_formats' => $date_formats,
427 392 );
428 393 }
@@ -439,9 +404,9 @@
439 404 public static function _sendResponse( $results ) {
440 405 header( 'Content-type: application/json' );
441 406 nocache_headers();
442 407 echo json_encode( $results );
443 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
408 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
444 409 }
445 410
446 411 /**
447 412 * Deletes a chart from database.
@@ -473,22 +438,9 @@
473 438 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
474 439 }
475 440 }
476 441 if ( $success ) {
477 - global $sitepress;
478 - if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
479 - $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
480 - $translations = $sitepress->get_element_translations( $trid );
481 - if ( ! empty( $translations ) ) {
482 - foreach ( $translations as $translated_post ) {
483 - wp_delete_post( $translated_post->element_id, true );
484 - }
485 - } else {
486 - wp_delete_post( $chart_id, true );
487 - }
488 - } else {
489 - wp_delete_post( $chart_id, true );
490 - }
442 + wp_delete_post( $chart_id, true );
491 443 }
492 444 if ( $is_post ) {
493 445 self::_sendResponse(
494 446 array(
@@ -536,97 +488,44 @@
536 488 *
537 489 * @access public
538 490 */
539 491 public function renderChartPages() {
540 - if ( ! current_user_can( 'edit_posts' ) ) {
541 - wp_die( __( 'You do not have permission to access this page.', 'visualizer' ) );
542 - }
543 -
544 492 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
545 - if ( ! defined( 'ET_BUILDER_PRODUCT_VERSION' ) && function_exists( 'et_get_theme_version' ) ) {
546 - define( 'ET_BUILDER_PRODUCT_VERSION', et_get_theme_version() );
547 - }
548 493 // Set current screen for the render chart.
549 494 set_current_screen( 'visualizer_render_chart' );
550 495 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
551 496 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
552 - if ( ! empty( $_POST ) ) {
553 - $_POST = map_deep( $_POST, 'wp_strip_all_tags' );
554 - }
555 - $chart = $chart_id ? get_post( $chart_id ) : null;
556 - if ( ! $chart_id || ! $chart || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
557 - if ( empty( $_GET['lang'] ) || empty( $_GET['parent_chart_id'] ) ) {
558 - $this->deleteOldCharts();
559 - $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
560 - $chart_status = Visualizer_Module_Admin::checkChartStatus( $default_type );
561 - if ( ! $chart_status ) {
562 - $default_type = 'line';
563 - }
564 - $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
565 - $source->fetch();
566 - $chart_id = wp_insert_post(
497 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
498 + $this->deleteOldCharts();
499 + $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
500 + $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
501 + $source->fetch();
502 + $chart_id = wp_insert_post(
503 + array(
504 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
505 + 'post_title' => 'Visualization',
506 + 'post_author' => get_current_user_id(),
507 + 'post_status' => 'auto-draft',
508 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
509 + )
510 + );
511 + if ( $chart_id && ! is_wp_error( $chart_id ) ) {
512 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
513 + add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
514 + add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
515 + add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
516 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
517 + add_post_meta(
518 + $chart_id,
519 + Visualizer_Plugin::CF_SETTINGS,
567 520 array(
568 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
569 - 'post_title' => 'Visualization',
570 - 'post_author' => get_current_user_id(),
571 - 'post_status' => 'auto-draft',
572 - 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
521 + 'focusTarget' => 'datum',
573 522 )
574 523 );
575 - if ( $chart_id && ! is_wp_error( $chart_id ) ) {
576 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
577 - add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
578 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
579 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
580 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
581 - add_post_meta(
582 - $chart_id,
583 - Visualizer_Plugin::CF_SETTINGS,
584 - array(
585 - 'focusTarget' => 'datum',
586 - )
587 - );
588 -
589 - do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
590 - }
591 - } else {
592 - $parent_chart_id = filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT );
593 - $success = false;
594 - if ( $parent_chart_id ) {
595 - $parent_chart = get_post( $parent_chart_id );
596 - $success = $parent_chart && $parent_chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
597 - }
598 - if ( $success ) {
599 - $new_chart_id = wp_insert_post(
600 - array(
601 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
602 - 'post_title' => 'Visualization',
603 - 'post_author' => get_current_user_id(),
604 - 'post_status' => $parent_chart->post_status,
605 - 'post_content' => $parent_chart->post_content,
606 - )
607 - );
608 -
609 - if ( is_wp_error( $new_chart_id ) ) {
610 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Error while cloning chart %d = %s', $parent_chart_id, print_r( $new_chart_id, true ) ), 'error', __FILE__, __LINE__ );
611 - } else {
612 - $post_meta = get_post_meta( $parent_chart_id );
613 - $chart_id = $new_chart_id;
614 - foreach ( $post_meta as $key => $value ) {
615 - if ( strpos( $key, 'visualizer-' ) !== false ) {
616 - add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
617 - }
618 - }
619 - }
620 - }
621 524 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
622 525 }
623 - wp_redirect( esc_url_raw( add_query_arg( 'chart', (int) $chart_id ) ) );
624 -
625 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
626 - wp_die();
627 - }
628 - exit();
526 + wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
527 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
629 528 }
630 529
631 530 $_POST['save_chart_image'] = isset( $_POST['save_chart_image'] ) && 'yes' === $_POST['save_chart_image'] ? true : false;
632 531 $_POST['lazy_load_chart'] = isset( $_POST['lazy_load_chart'] ) && 'yes' === $_POST['lazy_load_chart'] ? true : false;
@@ -719,9 +618,9 @@
719 618 default:
720 619 // this should never happen.
721 620 break;
722 621 }
723 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
622 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
724 623 }
725 624
726 625 /**
727 626 * Load code editor assets.
@@ -733,9 +632,9 @@
733 632
734 633 // data tables assets.
735 634 wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
736 635 wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
737 - wp_register_style( 'visualizer-jquery-ui', sprintf( '//code.jquery.com/ui/%s/themes/smoothness/jquery-ui.css', $wp_scripts->registered['jquery-ui-core']->ver ), array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
636 + wp_register_style( 'visualizer-jquery-ui', sprintf( '//ajax.googleapis.com/ajax/libs/jqueryui/%s/themes/smoothness/jquery-ui.css', $wp_scripts->registered['jquery-ui-core']->ver ), array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
738 637 wp_enqueue_script( 'visualizer-datatables' );
739 638 wp_enqueue_style( 'visualizer-jquery-ui' );
740 639
741 640 if ( ! Visualizer_Module::is_pro() ) {
@@ -751,9 +650,9 @@
751 650 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
752 651 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
753 652 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
754 653 wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
755 - wp_register_script( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.js', array( 'visualizer-codemirror-sql', 'visualizer-codemirror-sql-hint', 'visualizer-codemirror-placeholder', 'visualizer-codemirror-matchbrackets', 'visualizer-codemirror-closebrackets' ), Visualizer_Plugin::VERSION );
654 + wp_register_script( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.js', array( 'visualizer-codemirror-sql', 'visualizer-codemirror-sql-hint', 'visualizer-codemirror-placeholder', 'visualizer-codemirror-matchbrackets', 'visualizer-codemirror-closebrackets' ), Visualizer_Plugin::VERSION );
756 655 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
757 656 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
758 657
759 658 wp_enqueue_script( 'visualizer-codemirror-hint' );
@@ -767,9 +666,9 @@
767 666 'lineWrapping' => true,
768 667 'dragDrop' => false,
769 668 'matchBrackets' => true,
770 669 'autoCloseBrackets' => true,
771 - 'extraKeys' => array( 'Shift-Space' => 'autocomplete' ),
670 + 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
772 671 'hintOptions' => array( 'tables' => $table_col_mapping ),
773 672 ),
774 673 )
775 674 );
@@ -803,12 +702,9 @@
803 702 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
804 703 }
805 704
806 705 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
807 - $is_canceled = isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] );
808 - $is_newly_created = $this->_chart->post_status === 'auto-draft';
809 -
810 - if ( $is_newly_created && ! $is_canceled ) {
706 + if ( $this->_chart->post_status === 'auto-draft' ) {
811 707 $this->_chart->post_status = 'publish';
812 708
813 709 // ensure that a revision is not created. If a revision is created it will have the proper data and the parent of the revision will have default data.
814 710 // we do not want any difference in data so disable revisions temporarily.
@@ -816,15 +712,10 @@
816 712
817 713 wp_update_post( $this->_chart->to_array() );
818 714 }
819 715 // save meta data only when it is NOT being canceled.
820 - if ( ! $is_canceled ) {
821 - $post_settings = $_POST;
822 - $existing = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
823 - if ( isset( $existing['colors'] ) && is_array( $existing['colors'] ) && ! isset( $post_settings['colors'] ) ) {
824 - $post_settings['colors'] = $existing['colors'];
825 - }
826 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $post_settings );
716 + if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
717 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
827 718
828 719 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
829 720 // this will help in searching with the chart id.
830 721 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -838,14 +729,8 @@
838 729 if ( empty( $title ) ) {
839 730 $title = $this->_chart->ID;
840 731 }
841 732 $settings['internal_title'] = $title;
842 - $settings_label = isset( $settings['pieResidueSliceLabel'] ) ? $settings['pieResidueSliceLabel'] : '';
843 - if ( empty( $settings_label ) ) {
844 - $settings['pieResidueSliceLabel'] = esc_html__( 'Other', 'visualizer' );
845 - } else {
846 - $settings['pieResidueSliceLabel'] = $settings_label;
847 - }
848 733 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
849 734 }
850 735 $render = new Visualizer_Render_Page_Send();
851 736 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
@@ -871,9 +756,8 @@
871 756 wp_enqueue_style( 'visualizer-frame' );
872 757 wp_enqueue_script( 'visualizer-preview' );
873 758 wp_enqueue_script( 'visualizer-chosen' );
874 759 wp_enqueue_script( 'visualizer-render' );
875 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
876 760
877 761 if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
878 762 wp_enqueue_script( 'visualizer-editor-simple' );
879 763 wp_localize_script(
@@ -881,10 +765,12 @@
881 765 'visualizer1',
882 766 array(
883 767 'ajax' => array(
884 768 'url' => admin_url( 'admin-ajax.php' ),
885 - 'nonces' => array(),
886 - 'actions' => array(),
769 + 'nonces' => array(
770 + ),
771 + 'actions' => array(
772 + ),
887 773 ),
888 774 )
889 775 );
890 776 }
@@ -895,15 +781,13 @@
895 781 'visualizer-render',
896 782 'visualizer',
897 783 array(
898 784 'l10n' => array(
899 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
900 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
901 - 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
902 - 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
903 - 'save_settings' => __( 'You have modified the chart\'s settings. To modify the source/data again, you must save this chart and reopen it for editing. If you continue without saving the chart, you may lose your changes.', 'visualizer' ),
904 - 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
905 - 'invalid_format' => esc_html__( 'This format pattern is not supported in the series settings field. Use the Manual Configuration option instead.', 'visualizer' ),
785 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
786 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
787 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
788 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
789 + 'save_settings' => __( 'You have modified the chart\'s settings. To modify the source/data again, you must save this chart and reopen it for editing. If you continue without saving the chart, you may lose your changes.', 'visualizer' ),
906 790 ),
907 791 'charts' => array(
908 792 'canvas' => $data,
909 793 'id' => $this->_chart->ID,
@@ -934,9 +818,8 @@
934 818 'page_type' => 'chart',
935 819 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
936 820 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
937 821 'is_front' => false,
938 - 'rest_base' => get_rest_url( null, 'wc/v3/reports/' ),
939 822 )
940 823 );
941 824
942 825 $render = new Visualizer_Render_Page_Data();
@@ -947,10 +830,11 @@
947 830 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
948 831 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
949 832 ? esc_html__( 'Save Chart', 'visualizer' )
950 833 : esc_html__( 'Create Chart', 'visualizer' );
951 -
952 - $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
834 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
835 + $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
836 + }
953 837 } else {
954 838 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
955 839 }
956 840
@@ -973,12 +857,12 @@
973 857 * @access private
974 858 */
975 859 private function _handleTypesPage() {
976 860 // process post request
977 - if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ), 'visualizer-upload-data' ) ) {
861 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
978 862 $type = filter_input( INPUT_POST, 'type' );
979 863 $library = filter_input( INPUT_POST, 'chart-library' );
980 - if ( Visualizer_Module_Admin::checkChartStatus( $type ) ) {
864 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
981 865 if ( empty( $library ) ) {
982 866 // library cannot be empty.
983 867 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
984 868 return;
@@ -999,9 +883,9 @@
999 883 Visualizer_Module_Utility::set_defaults( $this->_chart );
1000 884
1001 885 // redirect to next tab
1002 886 // changed by Ash/Upwork
1003 - wp_redirect( esc_url_raw( add_query_arg( 'tab', 'settings' ) ) );
887 + wp_redirect( add_query_arg( 'tab', 'settings' ) );
1004 888
1005 889 return;
1006 890 }
1007 891 }
@@ -1030,80 +914,8 @@
1030 914 * Processes the CSV that is sent in the request as a string.
1031 915 *
1032 916 * @since 3.2.0
1033 917 */
1034 - /**
1035 - * Determines whether a remote URL serves an XLSX file.
1036 - *
1037 - * Used as a fallback when the URL path has no recognisable file extension
1038 - * (e.g. SharePoint, signed S3 URLs, or "download?id=…" endpoints).
1039 - *
1040 - * Uses wp_safe_remote_get() to block requests to private/loopback addresses,
1041 - * and streams the response to a temp file so no body data is held in memory
1042 - * regardless of whether the server honours the Range header.
1043 - *
1044 - * The check relies on the ZIP magic number (PK\x03\x04) that every XLSX
1045 - * file begins with, making it immune to misleading Content-Type headers
1046 - * such as application/octet-stream. Content-Type is used as a last-resort
1047 - * fallback only when the temp file is empty (e.g. a HEAD-only server).
1048 - *
1049 - * @access private
1050 - * @param string $url The remote URL to probe.
1051 - * @return bool TRUE if the file appears to be XLSX, FALSE otherwise.
1052 - */
1053 - private static function _url_is_xlsx( $url ) {
1054 - $tmpfile = wp_tempnam( 'visualizer_xlsx_probe' );
1055 - if ( ! $tmpfile ) {
1056 - return false;
1057 - }
1058 -
1059 - $response = wp_safe_remote_get(
1060 - $url,
1061 - array(
1062 - 'timeout' => 10,
1063 - 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ),
1064 - 'headers' => array( 'Range' => 'bytes=0-3' ),
1065 - 'stream' => true,
1066 - 'filename' => $tmpfile,
1067 - )
1068 - );
1069 -
1070 - if ( is_wp_error( $response ) ) {
1071 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1072 - return false;
1073 - }
1074 -
1075 - $magic = '';
1076 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
1077 - $fh = @fopen( $tmpfile, 'rb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1078 - if ( $fh ) {
1079 - $magic = fread( $fh, 4 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread
1080 - fclose( $fh ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1081 - }
1082 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1083 -
1084 - if ( strlen( $magic ) >= 4 ) {
1085 - // XLSX (and all ZIP-based Office formats) start with PK\x03\x04.
1086 - return $magic === "PK\x03\x04";
1087 - }
1088 -
1089 - // Last resort: server returned an empty body (e.g. ignored Range and
1090 - // returned only headers). Check Content-Type from the same response.
1091 - // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
1092 - return false !== strpos(
1093 - wp_remote_retrieve_header( $response, 'content-type' ),
1094 - 'spreadsheetml'
1095 - );
1096 - }
1097 -
1098 - /**
1099 - * Parses a raw CSV string or editor payload and returns a source object.
1100 - *
1101 - * @access private
1102 - * @param string $data The raw CSV data string.
1103 - * @param string $editor_type The editor type ('text' or 'tabular').
1104 - * @return Visualizer_Source|null The populated source object, or null on failure.
1105 - */
1106 918 private function handleCSVasString( $data, $editor_type ) {
1107 919 $source = null;
1108 920
1109 921 switch ( $editor_type ) {
@@ -1118,9 +930,9 @@
1118 930 continue;
1119 931 }
1120 932 $row = explode( ',', $row );
1121 933 $row = array_map(
1122 - function ( $r ) {
934 + function( $r ) {
1123 935 return '' === $r ? ' ' : $r;
1124 936 },
1125 937 $row
1126 938 );
@@ -1169,9 +981,9 @@
1169 981 foreach ( $types as $type ) {
1170 982 if ( empty( $type ) ) {
1171 983 $exclude[] = $index;
1172 984 }
1173 - ++$index;
985 + $index++;
1174 986 }
1175 987
1176 988 // when N headers are being renamed, the number of headers increases by N
1177 989 // because of the way datatable duplicates header information
@@ -1231,13 +1043,9 @@
1231 1043 // otherwise, assume this is a normal web request.
1232 1044 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
1233 1045
1234 1046 // validate nonce
1235 - if (
1236 - ! isset( $_GET['nonce'] ) ||
1237 - ! wp_verify_nonce( $_GET['nonce'], 'visualizer-upload-data' ) ||
1238 - ! current_user_can( 'edit_posts' )
1239 - ) {
1047 + if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
1240 1048 if ( ! $can_die ) {
1241 1049 return;
1242 1050 }
1243 1051 status_header( 403 );
@@ -1246,15 +1054,9 @@
1246 1054
1247 1055 // check chart, if chart exists
1248 1056 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1249 1057 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1250 - $chart = $chart_id ? get_post( $chart_id ) : null;
1251 - if (
1252 - ! $chart_id ||
1253 - ! $chart ||
1254 - $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ||
1255 - ! current_user_can( 'edit_post', $chart_id )
1256 - ) {
1058 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
1257 1059 if ( ! $can_die ) {
1258 1060 return;
1259 1061 }
1260 1062 status_header( 400 );
@@ -1295,30 +1097,16 @@
1295 1097 delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1296 1098
1297 1099 $source = null;
1298 1100 $render = new Visualizer_Render_Page_Update();
1299 -
1300 - $remote_data = false;
1301 - if ( isset( $_POST['remote_data'] ) && function_exists( 'wp_http_validate_url' ) ) {
1302 - $remote_data = wp_http_validate_url( $_POST['remote_data'] );
1303 - }
1304 - if ( false !== $remote_data ) {
1305 - $remote_ext = strtolower( pathinfo( parse_url( $remote_data, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
1306 - if ( 'xlsx' === $remote_ext || ( 'csv' !== $remote_ext && self::_url_is_xlsx( $remote_data ) ) ) {
1307 - $source = new Visualizer_Source_Xlsx_Remote( $remote_data );
1308 - } else {
1309 - $source = new Visualizer_Source_Csv_Remote( $remote_data );
1310 - }
1101 + if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
1102 + $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
1311 1103 if ( isset( $_POST['vz-import-time'] ) ) {
1312 - apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $remote_data, $_POST['vz-import-time'] );
1104 + apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
1313 1105 }
1314 - } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] === 0 ) {
1315 - $local_ext = strtolower( pathinfo( isset( $_FILES['local_data']['name'] ) ? $_FILES['local_data']['name'] : '', PATHINFO_EXTENSION ) );
1316 - if ( 'xlsx' === $local_ext ) {
1317 - $source = new Visualizer_Source_Xlsx( $_FILES['local_data']['tmp_name'] );
1318 - } else {
1319 - $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1320 - }
1106 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
1107 + } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
1108 + $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1321 1109 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1322 1110 $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1323 1111 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1324 1112 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
@@ -1325,10 +1113,10 @@
1325 1113 $source = $this->handleTabularData();
1326 1114 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1327 1115 } else {
1328 1116 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'CSV file with chart data was not uploaded for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
1329 - $render->message = esc_html__( 'No CSV file was received. Select a file and try uploading again.', 'visualizer' );
1330 - update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'No CSV file was received. Select a file and try uploading again.', 'visualizer' ) );
1117 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1118 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
1331 1119 }
1332 1120
1333 1121 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Uploaded data for chart %d with source %s', $chart_id, print_r( $source, true ) ), 'debug', __FILE__, __LINE__ );
1334 1122
@@ -1376,9 +1164,9 @@
1376 1164 $render->settings = json_encode( $settings );
1377 1165 } else {
1378 1166 $error = $source->get_error();
1379 1167 if ( empty( $error ) ) {
1380 - $error = esc_html__( 'The CSV file couldn\'t be read. Check that it\'s properly formatted and try again.', 'visualizer' );
1168 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1381 1169 }
1382 1170 $render->message = $error;
1383 1171 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1384 1172 update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
@@ -1389,9 +1177,9 @@
1389 1177 $render->render();
1390 1178 if ( ! $can_die ) {
1391 1179 return;
1392 1180 }
1393 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1181 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1394 1182 }
1395 1183
1396 1184 /**
1397 1185 * Clones the chart.
@@ -1430,26 +1218,23 @@
1430 1218 if ( strpos( $key, 'visualizer-' ) !== false ) {
1431 1219 add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1432 1220 }
1433 1221 }
1434 - $redirect = esc_url(
1435 - add_query_arg(
1436 - array(
1437 - 'page' => 'visualizer',
1438 - 'type' => filter_input( INPUT_GET, 'type' ),
1439 - 'vaction' => false,
1440 - ),
1441 - admin_url( 'admin.php' )
1222 + $redirect = add_query_arg(
1223 + array(
1224 + 'page' => 'visualizer',
1225 + 'type' => filter_input( INPUT_GET, 'type' ),
1226 + 'vaction' => false,
1442 1227 ),
1443 - null,
1444 - 'db'
1228 + admin_url( 'admin.php' )
1445 1229 );
1446 1230 }
1447 1231 }
1448 1232
1449 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1233 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1450 1234 wp_die();
1451 1235 }
1236 +
1452 1237 wp_redirect( $redirect );
1453 1238 exit;
1454 1239 }
1455 1240
@@ -1480,9 +1265,9 @@
1480 1265 }
1481 1266 }
1482 1267 }
1483 1268
1484 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1269 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1485 1270 }
1486 1271
1487 1272 /**
1488 1273 * Handles chart data page.
@@ -1506,11 +1291,10 @@
1506 1291 'visualizer-render',
1507 1292 'visualizer',
1508 1293 array(
1509 1294 'l10n' => array(
1510 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
1511 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1512 - 'invalid_format' => esc_html__( 'This format pattern is not supported in the series settings field. To display percentages, use the Manual Configuration option instead.', 'visualizer' ),
1295 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
1296 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1513 1297 ),
1514 1298 'charts' => array(
1515 1299 'canvas' => $data,
1516 1300 ),
@@ -1536,24 +1320,12 @@
1536 1320 */
1537 1321 public function getQueryData() {
1538 1322 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1539 1323
1540 - if ( ! current_user_can( 'administrator' ) ) {
1541 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1542 - }
1543 - if ( ! is_super_admin() ) {
1544 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1545 - }
1546 -
1547 - if ( ! Visualizer_Module::is_pro() ) {
1548 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1549 - }
1550 -
1551 1324 $params = wp_parse_args( $_POST['params'] );
1552 1325 $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1553 - $query = trim( $params['query'], ';' );
1554 1326
1555 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1327 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1556 1328 $html = $source->fetch( true );
1557 1329 $error = $source->get_error();
1558 1330 if ( ! empty( $error ) ) {
1559 1331 wp_send_json_error( array( 'msg' => $error ) );
@@ -1568,19 +1340,8 @@
1568 1340 */
1569 1341 public function saveQuery() {
1570 1342 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1571 1343
1572 - if ( ! current_user_can( 'administrator' ) ) {
1573 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1574 - }
1575 - if ( ! is_super_admin() ) {
1576 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1577 - }
1578 -
1579 - if ( ! Visualizer_Module::is_pro() ) {
1580 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1581 - }
1582 -
1583 1344 $chart_id = filter_input(
1584 1345 INPUT_GET,
1585 1346 'chart',
1586 1347 FILTER_VALIDATE_INT,
@@ -1609,14 +1370,13 @@
1609 1370
1610 1371 $render = new Visualizer_Render_Page_Update();
1611 1372 if ( $chart_id ) {
1612 1373 $params = wp_parse_args( $_POST['params'] );
1613 - $query = trim( $params['query'], ';' );
1614 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1374 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1615 1375 $source->fetch( false );
1616 1376 $error = $source->get_error();
1617 1377 if ( empty( $error ) ) {
1618 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $query ) );
1378 + update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
1619 1379 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1620 1380 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1621 1381 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1622 1382 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
@@ -1645,9 +1405,9 @@
1645 1405 }
1646 1406 }
1647 1407 $render->render();
1648 1408 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1649 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1409 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1650 1410 }
1651 1411 }
1652 1412
1653 1413
@@ -1672,9 +1432,9 @@
1672 1432
1673 1433 $hours = filter_input(
1674 1434 INPUT_POST,
1675 1435 'refresh',
1676 - FILTER_VALIDATE_FLOAT,
1436 + FILTER_VALIDATE_INT,
1677 1437 array(
1678 1438 'options' => array(
1679 1439 'min_range' => -1,
1680 1440 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1681,9 +1441,9 @@
1681 1441 ),
1682 1442 )
1683 1443 );
1684 1444
1685 - if ( ! is_numeric( $hours ) ) {
1445 + if ( 0 !== $hours && empty( $hours ) ) {
1686 1446 $hours = -1;
1687 1447 }
1688 1448
1689 1449 do_action( 'visualizer_save_filter', $chart_id, $hours );
@@ -1688,9 +1448,9 @@
1688 1448
1689 1449 do_action( 'visualizer_save_filter', $chart_id, $hours );
1690 1450
1691 1451 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1692 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1452 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1693 1453 }
1694 1454 }
1695 1455
1696 1456 /**
@@ -1726,12 +1486,8 @@
1726 1486 // Save the image in the uploads directory.
1727 1487 require_once ABSPATH . '/wp-admin/includes/file.php';
1728 1488 \WP_Filesystem();
1729 1489 global $wp_filesystem;
1730 - if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base' ) ) {
1731 - $creds = request_filesystem_credentials( site_url() );
1732 - wp_filesystem( $creds );
1733 - }
1734 1490 $upload_file = $wp_filesystem->put_contents( $upload_path . $hashed_filename, $decoded );
1735 1491
1736 1492 // Insert new chart image.
1737 1493 $attachment = array(