PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.1
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 +87 -415 4.0.53.5.1 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,108 +488,46 @@
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 - $_POST['save_chart_image'] = isset( $_POST['save_chart_image'] ) && 'yes' === $_POST['save_chart_image'] ? true : false;
632 - $_POST['lazy_load_chart'] = isset( $_POST['lazy_load_chart'] ) && 'yes' === $_POST['lazy_load_chart'] ? true : false;
633 -
634 - if ( isset( $_POST['chart-img'] ) && ! empty( $_POST['chart-img'] ) ) {
635 - $attachment_id = $this->save_chart_image( $_POST['chart-img'], $chart_id, $_POST['save_chart_image'] );
636 - if ( $attachment_id ) {
637 - update_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, $attachment_id );
638 - }
639 - }
640 530 $lib = $this->load_chart_type( $chart_id );
641 531
642 532 // the alpha color picker (RGBA) is not supported by google.
643 533 $color_picker_dep = 'wp-color-picker';
@@ -699,16 +589,8 @@
699 589 // if the edit button is clicked.
700 590 $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
701 591 }
702 592
703 - // Clear existing chart cache.
704 - if ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
705 - $cache_key = Visualizer_Plugin::CF_CHART_CACHE . '_' . $chart_id;
706 - if ( get_transient( $cache_key ) ) {
707 - delete_transient( $cache_key );
708 - }
709 - }
710 -
711 593 switch ( $tab ) {
712 594 case 'settings':
713 595 $this->_handleDataAndSettingsPage();
714 596 break;
@@ -719,9 +601,9 @@
719 601 default:
720 602 // this should never happen.
721 603 break;
722 604 }
723 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
605 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
724 606 }
725 607
726 608 /**
727 609 * Load code editor assets.
@@ -733,9 +615,9 @@
733 615
734 616 // data tables assets.
735 617 wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
736 618 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 );
619 + 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 620 wp_enqueue_script( 'visualizer-datatables' );
739 621 wp_enqueue_style( 'visualizer-jquery-ui' );
740 622
741 623 if ( ! Visualizer_Module::is_pro() ) {
@@ -751,9 +633,9 @@
751 633 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
752 634 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
753 635 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
754 636 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 );
637 + 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 638 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
757 639 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
758 640
759 641 wp_enqueue_script( 'visualizer-codemirror-hint' );
@@ -767,9 +649,9 @@
767 649 'lineWrapping' => true,
768 650 'dragDrop' => false,
769 651 'matchBrackets' => true,
770 652 'autoCloseBrackets' => true,
771 - 'extraKeys' => array( 'Shift-Space' => 'autocomplete' ),
653 + 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
772 654 'hintOptions' => array( 'tables' => $table_col_mapping ),
773 655 ),
774 656 )
775 657 );
@@ -803,12 +685,9 @@
803 685 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
804 686 }
805 687
806 688 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 ) {
689 + if ( $this->_chart->post_status === 'auto-draft' ) {
811 690 $this->_chart->post_status = 'publish';
812 691
813 692 // 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 693 // we do not want any difference in data so disable revisions temporarily.
@@ -816,15 +695,10 @@
816 695
817 696 wp_update_post( $this->_chart->to_array() );
818 697 }
819 698 // 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 );
699 + if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
700 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
827 701
828 702 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
829 703 // this will help in searching with the chart id.
830 704 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -838,14 +712,8 @@
838 712 if ( empty( $title ) ) {
839 713 $title = $this->_chart->ID;
840 714 }
841 715 $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 716 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
849 717 }
850 718 $render = new Visualizer_Render_Page_Send();
851 719 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
@@ -871,9 +739,8 @@
871 739 wp_enqueue_style( 'visualizer-frame' );
872 740 wp_enqueue_script( 'visualizer-preview' );
873 741 wp_enqueue_script( 'visualizer-chosen' );
874 742 wp_enqueue_script( 'visualizer-render' );
875 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
876 743
877 744 if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
878 745 wp_enqueue_script( 'visualizer-editor-simple' );
879 746 wp_localize_script(
@@ -881,10 +748,12 @@
881 748 'visualizer1',
882 749 array(
883 750 'ajax' => array(
884 751 'url' => admin_url( 'admin-ajax.php' ),
885 - 'nonces' => array(),
886 - 'actions' => array(),
752 + 'nonces' => array(
753 + ),
754 + 'actions' => array(
755 + ),
887 756 ),
888 757 )
889 758 );
890 759 }
@@ -895,15 +764,13 @@
895 764 'visualizer-render',
896 765 'visualizer',
897 766 array(
898 767 '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' ),
768 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
769 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
770 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
771 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
772 + '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 773 ),
907 774 'charts' => array(
908 775 'canvas' => $data,
909 776 'id' => $this->_chart->ID,
@@ -934,9 +801,8 @@
934 801 'page_type' => 'chart',
935 802 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
936 803 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
937 804 'is_front' => false,
938 - 'rest_base' => get_rest_url( null, 'wc/v3/reports/' ),
939 805 )
940 806 );
941 807
942 808 $render = new Visualizer_Render_Page_Data();
@@ -947,10 +813,11 @@
947 813 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
948 814 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
949 815 ? esc_html__( 'Save Chart', 'visualizer' )
950 816 : esc_html__( 'Create Chart', 'visualizer' );
951 -
952 - $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
817 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
818 + $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
819 + }
953 820 } else {
954 821 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
955 822 }
956 823
@@ -973,12 +840,12 @@
973 840 * @access private
974 841 */
975 842 private function _handleTypesPage() {
976 843 // process post request
977 - if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ), 'visualizer-upload-data' ) ) {
844 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
978 845 $type = filter_input( INPUT_POST, 'type' );
979 846 $library = filter_input( INPUT_POST, 'chart-library' );
980 - if ( Visualizer_Module_Admin::checkChartStatus( $type ) ) {
847 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
981 848 if ( empty( $library ) ) {
982 849 // library cannot be empty.
983 850 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
984 851 return;
@@ -999,9 +866,9 @@
999 866 Visualizer_Module_Utility::set_defaults( $this->_chart );
1000 867
1001 868 // redirect to next tab
1002 869 // changed by Ash/Upwork
1003 - wp_redirect( esc_url_raw( add_query_arg( 'tab', 'settings' ) ) );
870 + wp_redirect( add_query_arg( 'tab', 'settings' ) );
1004 871
1005 872 return;
1006 873 }
1007 874 }
@@ -1030,80 +897,8 @@
1030 897 * Processes the CSV that is sent in the request as a string.
1031 898 *
1032 899 * @since 3.2.0
1033 900 */
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 901 private function handleCSVasString( $data, $editor_type ) {
1107 902 $source = null;
1108 903
1109 904 switch ( $editor_type ) {
@@ -1116,16 +911,8 @@
1116 911 foreach ( $values as $row ) {
1117 912 if ( empty( $row ) ) {
1118 913 continue;
1119 914 }
1120 - $row = explode( ',', $row );
1121 - $row = array_map(
1122 - function ( $r ) {
1123 - return '' === $r ? ' ' : $r;
1124 - },
1125 - $row
1126 - );
1127 - $row = implode( ',', $row );
1128 915 // don't use fpucsv here because we need to just dump the data
1129 916 // minus the empty rows
1130 917 // because fputcsv needs to tokenize
1131 918 // we can standardize the CSV enclosure here and replace all ' with "
@@ -1169,9 +956,9 @@
1169 956 foreach ( $types as $type ) {
1170 957 if ( empty( $type ) ) {
1171 958 $exclude[] = $index;
1172 959 }
1173 - ++$index;
960 + $index++;
1174 961 }
1175 962
1176 963 // when N headers are being renamed, the number of headers increases by N
1177 964 // because of the way datatable duplicates header information
@@ -1231,13 +1018,9 @@
1231 1018 // otherwise, assume this is a normal web request.
1232 1019 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
1233 1020
1234 1021 // validate nonce
1235 - if (
1236 - ! isset( $_GET['nonce'] ) ||
1237 - ! wp_verify_nonce( $_GET['nonce'], 'visualizer-upload-data' ) ||
1238 - ! current_user_can( 'edit_posts' )
1239 - ) {
1022 + if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
1240 1023 if ( ! $can_die ) {
1241 1024 return;
1242 1025 }
1243 1026 status_header( 403 );
@@ -1246,15 +1029,9 @@
1246 1029
1247 1030 // check chart, if chart exists
1248 1031 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1249 1032 $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 - ) {
1033 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
1257 1034 if ( ! $can_die ) {
1258 1035 return;
1259 1036 }
1260 1037 status_header( 400 );
@@ -1295,30 +1072,16 @@
1295 1072 delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1296 1073
1297 1074 $source = null;
1298 1075 $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 - }
1076 + if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
1077 + $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
1311 1078 if ( isset( $_POST['vz-import-time'] ) ) {
1312 - apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $remote_data, $_POST['vz-import-time'] );
1079 + apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
1313 1080 }
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 - }
1081 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
1082 + } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
1083 + $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1321 1084 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1322 1085 $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1323 1086 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1324 1087 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
@@ -1325,10 +1088,10 @@
1325 1088 $source = $this->handleTabularData();
1326 1089 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1327 1090 } else {
1328 1091 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' ) );
1092 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1093 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
1331 1094 }
1332 1095
1333 1096 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 1097
@@ -1349,9 +1112,8 @@
1349 1112 if ( $populate ) {
1350 1113 $chart->post_content = $content;
1351 1114 }
1352 1115 wp_update_post( $chart->to_array() );
1353 -
1354 1116 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1355 1117 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1356 1118 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1357 1119
@@ -1359,17 +1121,8 @@
1359 1121
1360 1122 Visualizer_Module_Utility::set_defaults( $chart, null );
1361 1123
1362 1124 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1363 - if ( isset( $settings['series'] ) && ! ( count( $settings['series'] ) - count( $source->getSeries() ) > 1 ) ) {
1364 - $diff_total_series = abs( count( $settings['series'] ) - count( $source->getSeries() ) );
1365 - if ( $diff_total_series ) {
1366 - foreach ( range( 1, $diff_total_series ) as $k => $diff_series ) {
1367 - $settings['series'][] = end( $settings['series'] );
1368 - }
1369 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
1370 - }
1371 - }
1372 1125
1373 1126 $render->id = $chart->ID;
1374 1127 $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
1375 1128 $render->series = json_encode( $source->getSeries() );
@@ -1376,9 +1129,9 @@
1376 1129 $render->settings = json_encode( $settings );
1377 1130 } else {
1378 1131 $error = $source->get_error();
1379 1132 if ( empty( $error ) ) {
1380 - $error = esc_html__( 'The CSV file couldn\'t be read. Check that it\'s properly formatted and try again.', 'visualizer' );
1133 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1381 1134 }
1382 1135 $render->message = $error;
1383 1136 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1384 1137 update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
@@ -1389,9 +1142,9 @@
1389 1142 $render->render();
1390 1143 if ( ! $can_die ) {
1391 1144 return;
1392 1145 }
1393 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1146 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1394 1147 }
1395 1148
1396 1149 /**
1397 1150 * Clones the chart.
@@ -1430,26 +1183,23 @@
1430 1183 if ( strpos( $key, 'visualizer-' ) !== false ) {
1431 1184 add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1432 1185 }
1433 1186 }
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' )
1187 + $redirect = add_query_arg(
1188 + array(
1189 + 'page' => 'visualizer',
1190 + 'type' => filter_input( INPUT_GET, 'type' ),
1191 + 'vaction' => false,
1442 1192 ),
1443 - null,
1444 - 'db'
1193 + admin_url( 'admin.php' )
1445 1194 );
1446 1195 }
1447 1196 }
1448 1197
1449 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1198 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1450 1199 wp_die();
1451 1200 }
1201 +
1452 1202 wp_redirect( $redirect );
1453 1203 exit;
1454 1204 }
1455 1205
@@ -1480,9 +1230,9 @@
1480 1230 }
1481 1231 }
1482 1232 }
1483 1233
1484 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1234 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1485 1235 }
1486 1236
1487 1237 /**
1488 1238 * Handles chart data page.
@@ -1506,11 +1256,10 @@
1506 1256 'visualizer-render',
1507 1257 'visualizer',
1508 1258 array(
1509 1259 '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' ),
1260 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
1261 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1513 1262 ),
1514 1263 'charts' => array(
1515 1264 'canvas' => $data,
1516 1265 ),
@@ -1536,24 +1285,12 @@
1536 1285 */
1537 1286 public function getQueryData() {
1538 1287 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1539 1288
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 1289 $params = wp_parse_args( $_POST['params'] );
1552 1290 $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1553 - $query = trim( $params['query'], ';' );
1554 1291
1555 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1292 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1556 1293 $html = $source->fetch( true );
1557 1294 $error = $source->get_error();
1558 1295 if ( ! empty( $error ) ) {
1559 1296 wp_send_json_error( array( 'msg' => $error ) );
@@ -1568,19 +1305,8 @@
1568 1305 */
1569 1306 public function saveQuery() {
1570 1307 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1571 1308
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 1309 $chart_id = filter_input(
1584 1310 INPUT_GET,
1585 1311 'chart',
1586 1312 FILTER_VALIDATE_INT,
@@ -1593,9 +1319,9 @@
1593 1319
1594 1320 $hours = filter_input(
1595 1321 INPUT_POST,
1596 1322 'refresh',
1597 - FILTER_VALIDATE_FLOAT,
1323 + FILTER_VALIDATE_INT,
1598 1324 array(
1599 1325 'options' => array(
1600 1326 'min_range' => -1,
1601 1327 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1602,9 +1328,9 @@
1602 1328 ),
1603 1329 )
1604 1330 );
1605 1331
1606 - if ( ! is_numeric( $hours ) ) {
1332 + if ( ! is_int( $hours ) ) {
1607 1333 $hours = -1;
1608 1334 }
1609 1335
1610 1336 $render = new Visualizer_Render_Page_Update();
@@ -1609,14 +1335,13 @@
1609 1335
1610 1336 $render = new Visualizer_Render_Page_Update();
1611 1337 if ( $chart_id ) {
1612 1338 $params = wp_parse_args( $_POST['params'] );
1613 - $query = trim( $params['query'], ';' );
1614 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1339 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1615 1340 $source->fetch( false );
1616 1341 $error = $source->get_error();
1617 1342 if ( empty( $error ) ) {
1618 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $query ) );
1343 + update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
1619 1344 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1620 1345 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1621 1346 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1622 1347 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
@@ -1645,9 +1370,9 @@
1645 1370 }
1646 1371 }
1647 1372 $render->render();
1648 1373 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1649 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1374 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1650 1375 }
1651 1376 }
1652 1377
1653 1378
@@ -1672,9 +1397,9 @@
1672 1397
1673 1398 $hours = filter_input(
1674 1399 INPUT_POST,
1675 1400 'refresh',
1676 - FILTER_VALIDATE_FLOAT,
1401 + FILTER_VALIDATE_INT,
1677 1402 array(
1678 1403 'options' => array(
1679 1404 'min_range' => -1,
1680 1405 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1681,9 +1406,9 @@
1681 1406 ),
1682 1407 )
1683 1408 );
1684 1409
1685 - if ( ! is_numeric( $hours ) ) {
1410 + if ( 0 !== $hours && empty( $hours ) ) {
1686 1411 $hours = -1;
1687 1412 }
1688 1413
1689 1414 do_action( 'visualizer_save_filter', $chart_id, $hours );
@@ -1688,61 +1413,8 @@
1688 1413
1689 1414 do_action( 'visualizer_save_filter', $chart_id, $hours );
1690 1415
1691 1416 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1692 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1417 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1693 1418 }
1694 - }
1695 -
1696 - /**
1697 - * Save chart image.
1698 - *
1699 - * @param string $base64_img Chart image.
1700 - * @param int $chart_id Chart ID.
1701 - * @param bool $save_attachment Save attachment.
1702 - * @return attachment ID
1703 - */
1704 - public function save_chart_image( $base64_img, $chart_id, $save_attachment = true ) {
1705 - // Delete old chart image.
1706 - $old_attachment_id = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, true );
1707 - if ( $old_attachment_id ) {
1708 - wp_delete_attachment( $old_attachment_id, true );
1709 - }
1710 -
1711 - if ( ! $save_attachment ) {
1712 - return 0;
1713 - }
1714 -
1715 - // Upload dir.
1716 - $upload_dir = wp_upload_dir();
1717 - $upload_path = str_replace( '/', DIRECTORY_SEPARATOR, $upload_dir['path'] ) . DIRECTORY_SEPARATOR;
1718 -
1719 - $img = str_replace( 'data:image/png;base64,', '', $base64_img );
1720 - $img = str_replace( ' ', '+', $img );
1721 - $decoded = base64_decode( $img );
1722 - $filename = 'visualization-' . $chart_id . '.png';
1723 - $file_type = 'image/png';
1724 - $hashed_filename = $filename;
1725 -
1726 - // Save the image in the uploads directory.
1727 - require_once ABSPATH . '/wp-admin/includes/file.php';
1728 - \WP_Filesystem();
1729 - 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 - $upload_file = $wp_filesystem->put_contents( $upload_path . $hashed_filename, $decoded );
1735 -
1736 - // Insert new chart image.
1737 - $attachment = array(
1738 - 'post_mime_type' => $file_type,
1739 - 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $hashed_filename ) ),
1740 - 'post_content' => '',
1741 - 'post_status' => 'inherit',
1742 - 'guid' => $upload_dir['url'] . '/' . basename( $hashed_filename ),
1743 - );
1744 -
1745 - $attach_id = wp_insert_attachment( $attachment, $upload_dir['path'] . '/' . $hashed_filename );
1746 - return $attach_id;
1747 1419 }
1748 1420 }