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 -407 4.0.43.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 );
@@ -258,16 +245,8 @@
258 245 if ( ! empty( $params['paging'] ) ) {
259 246 add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
260 247 }
261 248
262 - if ( Visualizer_Module::is_pro() ) {
263 - if ( ! empty( $params['vz_woo_source'] ) ) {
264 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE, $params['vz_woo_source'] );
265 - } else {
266 - delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE );
267 - }
268 - }
269 -
270 249 $time = filter_input(
271 250 INPUT_POST,
272 251 'time',
273 252 FILTER_VALIDATE_INT,
@@ -295,9 +274,9 @@
295 274 $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
296 275 $render->series = json_encode( $source->getSeries() );
297 276 $render->render();
298 277
299 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
278 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
300 279 }
301 280
302 281
303 282 /**
@@ -373,13 +352,13 @@
373 352 * @since 1.0.0
374 353 *
375 354 * @access private
376 355 *
377 - * @param WP_Post|null $chart The chart object.
356 + * @param WP_Post $chart The chart object.
378 357 *
379 358 * @return array The array of chart data.
380 359 */
381 - private function _getChartArray( $chart = null ) {
360 + private function _getChartArray( WP_Post $chart = null ) {
382 361 if ( is_null( $chart ) ) {
383 362 $chart = $this->_chart;
384 363 }
385 364 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
@@ -401,13 +380,8 @@
401 380 }
402 381
403 382 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
404 383
405 - $code = '';
406 - if ( 'd3' === $library ) {
407 - $code = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
408 - }
409 -
410 384 return array(
411 385 'type' => $type,
412 386 'series' => $series,
413 387 'settings' => $settings,
@@ -412,9 +386,8 @@
412 386 'series' => $series,
413 387 'settings' => $settings,
414 388 'data' => $data,
415 389 'library' => $library,
416 - 'code' => $code,
417 390 'css' => $css,
418 391 'date_formats' => $date_formats,
419 392 );
420 393 }
@@ -431,9 +404,9 @@
431 404 public static function _sendResponse( $results ) {
432 405 header( 'Content-type: application/json' );
433 406 nocache_headers();
434 407 echo json_encode( $results );
435 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
408 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
436 409 }
437 410
438 411 /**
439 412 * Deletes a chart from database.
@@ -465,22 +438,9 @@
465 438 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
466 439 }
467 440 }
468 441 if ( $success ) {
469 - global $sitepress;
470 - if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
471 - $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
472 - $translations = $sitepress->get_element_translations( $trid );
473 - if ( ! empty( $translations ) ) {
474 - foreach ( $translations as $translated_post ) {
475 - wp_delete_post( $translated_post->element_id, true );
476 - }
477 - } else {
478 - wp_delete_post( $chart_id, true );
479 - }
480 - } else {
481 - wp_delete_post( $chart_id, true );
482 - }
442 + wp_delete_post( $chart_id, true );
483 443 }
484 444 if ( $is_post ) {
485 445 self::_sendResponse(
486 446 array(
@@ -528,108 +488,46 @@
528 488 *
529 489 * @access public
530 490 */
531 491 public function renderChartPages() {
532 - if ( ! current_user_can( 'edit_posts' ) ) {
533 - wp_die( __( 'You do not have permission to access this page.', 'visualizer' ) );
534 - }
535 -
536 492 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
537 - if ( ! defined( 'ET_BUILDER_PRODUCT_VERSION' ) && function_exists( 'et_get_theme_version' ) ) {
538 - define( 'ET_BUILDER_PRODUCT_VERSION', et_get_theme_version() );
539 - }
540 493 // Set current screen for the render chart.
541 494 set_current_screen( 'visualizer_render_chart' );
542 495 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
543 496 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
544 - if ( ! empty( $_POST ) ) {
545 - $_POST = map_deep( $_POST, 'wp_strip_all_tags' );
546 - }
547 - $chart = $chart_id ? get_post( $chart_id ) : null;
548 - if ( ! $chart_id || ! $chart || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
549 - if ( empty( $_GET['lang'] ) || empty( $_GET['parent_chart_id'] ) ) {
550 - $this->deleteOldCharts();
551 - $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
552 - $chart_status = Visualizer_Module_Admin::checkChartStatus( $default_type );
553 - if ( ! $chart_status ) {
554 - $default_type = 'line';
555 - }
556 - $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
557 - $source->fetch();
558 - $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,
559 520 array(
560 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
561 - 'post_title' => 'Visualization',
562 - 'post_author' => get_current_user_id(),
563 - 'post_status' => 'auto-draft',
564 - 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
521 + 'focusTarget' => 'datum',
565 522 )
566 523 );
567 - if ( $chart_id && ! is_wp_error( $chart_id ) ) {
568 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
569 - add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
570 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
571 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
572 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
573 - add_post_meta(
574 - $chart_id,
575 - Visualizer_Plugin::CF_SETTINGS,
576 - array(
577 - 'focusTarget' => 'datum',
578 - )
579 - );
580 -
581 - do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
582 - }
583 - } else {
584 - $parent_chart_id = filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT );
585 - $success = false;
586 - if ( $parent_chart_id ) {
587 - $parent_chart = get_post( $parent_chart_id );
588 - $success = $parent_chart && $parent_chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
589 - }
590 - if ( $success ) {
591 - $new_chart_id = wp_insert_post(
592 - array(
593 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
594 - 'post_title' => 'Visualization',
595 - 'post_author' => get_current_user_id(),
596 - 'post_status' => $parent_chart->post_status,
597 - 'post_content' => $parent_chart->post_content,
598 - )
599 - );
600 -
601 - if ( is_wp_error( $new_chart_id ) ) {
602 - 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__ );
603 - } else {
604 - $post_meta = get_post_meta( $parent_chart_id );
605 - $chart_id = $new_chart_id;
606 - foreach ( $post_meta as $key => $value ) {
607 - if ( strpos( $key, 'visualizer-' ) !== false ) {
608 - add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
609 - }
610 - }
611 - }
612 - }
613 524 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
614 525 }
615 - wp_redirect( esc_url_raw( add_query_arg( 'chart', (int) $chart_id ) ) );
616 -
617 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
618 - wp_die();
619 - }
620 - exit();
526 + wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
527 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
621 528 }
622 529
623 - $_POST['save_chart_image'] = isset( $_POST['save_chart_image'] ) && 'yes' === $_POST['save_chart_image'] ? true : false;
624 - $_POST['lazy_load_chart'] = isset( $_POST['lazy_load_chart'] ) && 'yes' === $_POST['lazy_load_chart'] ? true : false;
625 -
626 - if ( isset( $_POST['chart-img'] ) && ! empty( $_POST['chart-img'] ) ) {
627 - $attachment_id = $this->save_chart_image( $_POST['chart-img'], $chart_id, $_POST['save_chart_image'] );
628 - if ( $attachment_id ) {
629 - update_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, $attachment_id );
630 - }
631 - }
632 530 $lib = $this->load_chart_type( $chart_id );
633 531
634 532 // the alpha color picker (RGBA) is not supported by google.
635 533 $color_picker_dep = 'wp-color-picker';
@@ -691,16 +589,8 @@
691 589 // if the edit button is clicked.
692 590 $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
693 591 }
694 592
695 - // Clear existing chart cache.
696 - if ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
697 - $cache_key = Visualizer_Plugin::CF_CHART_CACHE . '_' . $chart_id;
698 - if ( get_transient( $cache_key ) ) {
699 - delete_transient( $cache_key );
700 - }
701 - }
702 -
703 593 switch ( $tab ) {
704 594 case 'settings':
705 595 $this->_handleDataAndSettingsPage();
706 596 break;
@@ -711,9 +601,9 @@
711 601 default:
712 602 // this should never happen.
713 603 break;
714 604 }
715 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
605 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
716 606 }
717 607
718 608 /**
719 609 * Load code editor assets.
@@ -725,9 +615,9 @@
725 615
726 616 // data tables assets.
727 617 wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
728 618 wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
729 - 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 );
730 620 wp_enqueue_script( 'visualizer-datatables' );
731 621 wp_enqueue_style( 'visualizer-jquery-ui' );
732 622
733 623 if ( ! Visualizer_Module::is_pro() ) {
@@ -743,9 +633,9 @@
743 633 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
744 634 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
745 635 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
746 636 wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
747 - 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 );
748 638 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
749 639 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
750 640
751 641 wp_enqueue_script( 'visualizer-codemirror-hint' );
@@ -759,9 +649,9 @@
759 649 'lineWrapping' => true,
760 650 'dragDrop' => false,
761 651 'matchBrackets' => true,
762 652 'autoCloseBrackets' => true,
763 - 'extraKeys' => array( 'Shift-Space' => 'autocomplete' ),
653 + 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
764 654 'hintOptions' => array( 'tables' => $table_col_mapping ),
765 655 ),
766 656 )
767 657 );
@@ -795,12 +685,9 @@
795 685 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
796 686 }
797 687
798 688 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
799 - $is_canceled = isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] );
800 - $is_newly_created = $this->_chart->post_status === 'auto-draft';
801 -
802 - if ( $is_newly_created && ! $is_canceled ) {
689 + if ( $this->_chart->post_status === 'auto-draft' ) {
803 690 $this->_chart->post_status = 'publish';
804 691
805 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.
806 693 // we do not want any difference in data so disable revisions temporarily.
@@ -808,15 +695,10 @@
808 695
809 696 wp_update_post( $this->_chart->to_array() );
810 697 }
811 698 // save meta data only when it is NOT being canceled.
812 - if ( ! $is_canceled ) {
813 - $post_settings = $_POST;
814 - $existing = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
815 - if ( isset( $existing['colors'] ) && is_array( $existing['colors'] ) && ! isset( $post_settings['colors'] ) ) {
816 - $post_settings['colors'] = $existing['colors'];
817 - }
818 - 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 );
819 701
820 702 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
821 703 // this will help in searching with the chart id.
822 704 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -830,14 +712,8 @@
830 712 if ( empty( $title ) ) {
831 713 $title = $this->_chart->ID;
832 714 }
833 715 $settings['internal_title'] = $title;
834 - $settings_label = isset( $settings['pieResidueSliceLabel'] ) ? $settings['pieResidueSliceLabel'] : '';
835 - if ( empty( $settings_label ) ) {
836 - $settings['pieResidueSliceLabel'] = esc_html__( 'Other', 'visualizer' );
837 - } else {
838 - $settings['pieResidueSliceLabel'] = $settings_label;
839 - }
840 716 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
841 717 }
842 718 $render = new Visualizer_Render_Page_Send();
843 719 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
@@ -863,9 +739,8 @@
863 739 wp_enqueue_style( 'visualizer-frame' );
864 740 wp_enqueue_script( 'visualizer-preview' );
865 741 wp_enqueue_script( 'visualizer-chosen' );
866 742 wp_enqueue_script( 'visualizer-render' );
867 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
868 743
869 744 if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
870 745 wp_enqueue_script( 'visualizer-editor-simple' );
871 746 wp_localize_script(
@@ -873,10 +748,12 @@
873 748 'visualizer1',
874 749 array(
875 750 'ajax' => array(
876 751 'url' => admin_url( 'admin-ajax.php' ),
877 - 'nonces' => array(),
878 - 'actions' => array(),
752 + 'nonces' => array(
753 + ),
754 + 'actions' => array(
755 + ),
879 756 ),
880 757 )
881 758 );
882 759 }
@@ -887,15 +764,13 @@
887 764 'visualizer-render',
888 765 'visualizer',
889 766 array(
890 767 'l10n' => array(
891 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
892 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
893 - 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
894 - 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
895 - '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' ),
896 - 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
897 - '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' ),
898 773 ),
899 774 'charts' => array(
900 775 'canvas' => $data,
901 776 'id' => $this->_chart->ID,
@@ -926,9 +801,8 @@
926 801 'page_type' => 'chart',
927 802 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
928 803 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
929 804 'is_front' => false,
930 - 'rest_base' => get_rest_url( null, 'wc/v3/reports/' ),
931 805 )
932 806 );
933 807
934 808 $render = new Visualizer_Render_Page_Data();
@@ -939,10 +813,11 @@
939 813 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
940 814 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
941 815 ? esc_html__( 'Save Chart', 'visualizer' )
942 816 : esc_html__( 'Create Chart', 'visualizer' );
943 -
944 - $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 + }
945 820 } else {
946 821 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
947 822 }
948 823
@@ -965,12 +840,12 @@
965 840 * @access private
966 841 */
967 842 private function _handleTypesPage() {
968 843 // process post request
969 - 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' ) ) ) {
970 845 $type = filter_input( INPUT_POST, 'type' );
971 846 $library = filter_input( INPUT_POST, 'chart-library' );
972 - if ( Visualizer_Module_Admin::checkChartStatus( $type ) ) {
847 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
973 848 if ( empty( $library ) ) {
974 849 // library cannot be empty.
975 850 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
976 851 return;
@@ -991,9 +866,9 @@
991 866 Visualizer_Module_Utility::set_defaults( $this->_chart );
992 867
993 868 // redirect to next tab
994 869 // changed by Ash/Upwork
995 - wp_redirect( esc_url_raw( add_query_arg( 'tab', 'settings' ) ) );
870 + wp_redirect( add_query_arg( 'tab', 'settings' ) );
996 871
997 872 return;
998 873 }
999 874 }
@@ -1022,80 +897,8 @@
1022 897 * Processes the CSV that is sent in the request as a string.
1023 898 *
1024 899 * @since 3.2.0
1025 900 */
1026 - /**
1027 - * Determines whether a remote URL serves an XLSX file.
1028 - *
1029 - * Used as a fallback when the URL path has no recognisable file extension
1030 - * (e.g. SharePoint, signed S3 URLs, or "download?id=…" endpoints).
1031 - *
1032 - * Uses wp_safe_remote_get() to block requests to private/loopback addresses,
1033 - * and streams the response to a temp file so no body data is held in memory
1034 - * regardless of whether the server honours the Range header.
1035 - *
1036 - * The check relies on the ZIP magic number (PK\x03\x04) that every XLSX
1037 - * file begins with, making it immune to misleading Content-Type headers
1038 - * such as application/octet-stream. Content-Type is used as a last-resort
1039 - * fallback only when the temp file is empty (e.g. a HEAD-only server).
1040 - *
1041 - * @access private
1042 - * @param string $url The remote URL to probe.
1043 - * @return bool TRUE if the file appears to be XLSX, FALSE otherwise.
1044 - */
1045 - private static function _url_is_xlsx( $url ) {
1046 - $tmpfile = wp_tempnam( 'visualizer_xlsx_probe' );
1047 - if ( ! $tmpfile ) {
1048 - return false;
1049 - }
1050 -
1051 - $response = wp_safe_remote_get(
1052 - $url,
1053 - array(
1054 - 'timeout' => 10,
1055 - 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ),
1056 - 'headers' => array( 'Range' => 'bytes=0-3' ),
1057 - 'stream' => true,
1058 - 'filename' => $tmpfile,
1059 - )
1060 - );
1061 -
1062 - if ( is_wp_error( $response ) ) {
1063 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1064 - return false;
1065 - }
1066 -
1067 - $magic = '';
1068 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
1069 - $fh = @fopen( $tmpfile, 'rb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1070 - if ( $fh ) {
1071 - $magic = fread( $fh, 4 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread
1072 - fclose( $fh ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1073 - }
1074 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1075 -
1076 - if ( strlen( $magic ) >= 4 ) {
1077 - // XLSX (and all ZIP-based Office formats) start with PK\x03\x04.
1078 - return $magic === "PK\x03\x04";
1079 - }
1080 -
1081 - // Last resort: server returned an empty body (e.g. ignored Range and
1082 - // returned only headers). Check Content-Type from the same response.
1083 - // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
1084 - return false !== strpos(
1085 - wp_remote_retrieve_header( $response, 'content-type' ),
1086 - 'spreadsheetml'
1087 - );
1088 - }
1089 -
1090 - /**
1091 - * Parses a raw CSV string or editor payload and returns a source object.
1092 - *
1093 - * @access private
1094 - * @param string $data The raw CSV data string.
1095 - * @param string $editor_type The editor type ('text' or 'tabular').
1096 - * @return Visualizer_Source|null The populated source object, or null on failure.
1097 - */
1098 901 private function handleCSVasString( $data, $editor_type ) {
1099 902 $source = null;
1100 903
1101 904 switch ( $editor_type ) {
@@ -1108,16 +911,8 @@
1108 911 foreach ( $values as $row ) {
1109 912 if ( empty( $row ) ) {
1110 913 continue;
1111 914 }
1112 - $row = explode( ',', $row );
1113 - $row = array_map(
1114 - function ( $r ) {
1115 - return '' === $r ? ' ' : $r;
1116 - },
1117 - $row
1118 - );
1119 - $row = implode( ',', $row );
1120 915 // don't use fpucsv here because we need to just dump the data
1121 916 // minus the empty rows
1122 917 // because fputcsv needs to tokenize
1123 918 // we can standardize the CSV enclosure here and replace all ' with "
@@ -1161,9 +956,9 @@
1161 956 foreach ( $types as $type ) {
1162 957 if ( empty( $type ) ) {
1163 958 $exclude[] = $index;
1164 959 }
1165 - ++$index;
960 + $index++;
1166 961 }
1167 962
1168 963 // when N headers are being renamed, the number of headers increases by N
1169 964 // because of the way datatable duplicates header information
@@ -1223,13 +1018,9 @@
1223 1018 // otherwise, assume this is a normal web request.
1224 1019 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
1225 1020
1226 1021 // validate nonce
1227 - if (
1228 - ! isset( $_GET['nonce'] ) ||
1229 - ! wp_verify_nonce( $_GET['nonce'], 'visualizer-upload-data' ) ||
1230 - ! current_user_can( 'edit_posts' )
1231 - ) {
1022 + if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
1232 1023 if ( ! $can_die ) {
1233 1024 return;
1234 1025 }
1235 1026 status_header( 403 );
@@ -1238,15 +1029,9 @@
1238 1029
1239 1030 // check chart, if chart exists
1240 1031 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1241 1032 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1242 - $chart = $chart_id ? get_post( $chart_id ) : null;
1243 - if (
1244 - ! $chart_id ||
1245 - ! $chart ||
1246 - $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ||
1247 - ! current_user_can( 'edit_post', $chart_id )
1248 - ) {
1033 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
1249 1034 if ( ! $can_die ) {
1250 1035 return;
1251 1036 }
1252 1037 status_header( 400 );
@@ -1287,30 +1072,16 @@
1287 1072 delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1288 1073
1289 1074 $source = null;
1290 1075 $render = new Visualizer_Render_Page_Update();
1291 -
1292 - $remote_data = false;
1293 - if ( isset( $_POST['remote_data'] ) && function_exists( 'wp_http_validate_url' ) ) {
1294 - $remote_data = wp_http_validate_url( $_POST['remote_data'] );
1295 - }
1296 - if ( false !== $remote_data ) {
1297 - $remote_ext = strtolower( pathinfo( parse_url( $remote_data, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
1298 - if ( 'xlsx' === $remote_ext || ( 'csv' !== $remote_ext && self::_url_is_xlsx( $remote_data ) ) ) {
1299 - $source = new Visualizer_Source_Xlsx_Remote( $remote_data );
1300 - } else {
1301 - $source = new Visualizer_Source_Csv_Remote( $remote_data );
1302 - }
1076 + if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
1077 + $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
1303 1078 if ( isset( $_POST['vz-import-time'] ) ) {
1304 - 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'] );
1305 1080 }
1306 - } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] === 0 ) {
1307 - $local_ext = strtolower( pathinfo( isset( $_FILES['local_data']['name'] ) ? $_FILES['local_data']['name'] : '', PATHINFO_EXTENSION ) );
1308 - if ( 'xlsx' === $local_ext ) {
1309 - $source = new Visualizer_Source_Xlsx( $_FILES['local_data']['tmp_name'] );
1310 - } else {
1311 - $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1312 - }
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'] );
1313 1084 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1314 1085 $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1315 1086 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1316 1087 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
@@ -1317,10 +1088,10 @@
1317 1088 $source = $this->handleTabularData();
1318 1089 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1319 1090 } else {
1320 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__ );
1321 - $render->message = esc_html__( 'No CSV file was received. Select a file and try uploading again.', 'visualizer' );
1322 - 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' ) );
1323 1094 }
1324 1095
1325 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__ );
1326 1097
@@ -1341,9 +1112,8 @@
1341 1112 if ( $populate ) {
1342 1113 $chart->post_content = $content;
1343 1114 }
1344 1115 wp_update_post( $chart->to_array() );
1345 -
1346 1116 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1347 1117 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1348 1118 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1349 1119
@@ -1351,17 +1121,8 @@
1351 1121
1352 1122 Visualizer_Module_Utility::set_defaults( $chart, null );
1353 1123
1354 1124 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1355 - if ( isset( $settings['series'] ) && ! ( count( $settings['series'] ) - count( $source->getSeries() ) > 1 ) ) {
1356 - $diff_total_series = abs( count( $settings['series'] ) - count( $source->getSeries() ) );
1357 - if ( $diff_total_series ) {
1358 - foreach ( range( 1, $diff_total_series ) as $k => $diff_series ) {
1359 - $settings['series'][] = end( $settings['series'] );
1360 - }
1361 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
1362 - }
1363 - }
1364 1125
1365 1126 $render->id = $chart->ID;
1366 1127 $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
1367 1128 $render->series = json_encode( $source->getSeries() );
@@ -1368,9 +1129,9 @@
1368 1129 $render->settings = json_encode( $settings );
1369 1130 } else {
1370 1131 $error = $source->get_error();
1371 1132 if ( empty( $error ) ) {
1372 - $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' );
1373 1134 }
1374 1135 $render->message = $error;
1375 1136 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1376 1137 update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
@@ -1381,9 +1142,9 @@
1381 1142 $render->render();
1382 1143 if ( ! $can_die ) {
1383 1144 return;
1384 1145 }
1385 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1146 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1386 1147 }
1387 1148
1388 1149 /**
1389 1150 * Clones the chart.
@@ -1422,26 +1183,23 @@
1422 1183 if ( strpos( $key, 'visualizer-' ) !== false ) {
1423 1184 add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1424 1185 }
1425 1186 }
1426 - $redirect = esc_url(
1427 - add_query_arg(
1428 - array(
1429 - 'page' => 'visualizer',
1430 - 'type' => filter_input( INPUT_GET, 'type' ),
1431 - 'vaction' => false,
1432 - ),
1433 - admin_url( 'admin.php' )
1187 + $redirect = add_query_arg(
1188 + array(
1189 + 'page' => 'visualizer',
1190 + 'type' => filter_input( INPUT_GET, 'type' ),
1191 + 'vaction' => false,
1434 1192 ),
1435 - null,
1436 - 'db'
1193 + admin_url( 'admin.php' )
1437 1194 );
1438 1195 }
1439 1196 }
1440 1197
1441 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1198 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1442 1199 wp_die();
1443 1200 }
1201 +
1444 1202 wp_redirect( $redirect );
1445 1203 exit;
1446 1204 }
1447 1205
@@ -1472,9 +1230,9 @@
1472 1230 }
1473 1231 }
1474 1232 }
1475 1233
1476 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1234 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1477 1235 }
1478 1236
1479 1237 /**
1480 1238 * Handles chart data page.
@@ -1498,11 +1256,10 @@
1498 1256 'visualizer-render',
1499 1257 'visualizer',
1500 1258 array(
1501 1259 'l10n' => array(
1502 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
1503 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1504 - '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' ),
1505 1262 ),
1506 1263 'charts' => array(
1507 1264 'canvas' => $data,
1508 1265 ),
@@ -1528,24 +1285,12 @@
1528 1285 */
1529 1286 public function getQueryData() {
1530 1287 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1531 1288
1532 - if ( ! current_user_can( 'administrator' ) ) {
1533 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1534 - }
1535 - if ( ! is_super_admin() ) {
1536 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1537 - }
1538 -
1539 - if ( ! Visualizer_Module::is_pro() ) {
1540 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1541 - }
1542 -
1543 1289 $params = wp_parse_args( $_POST['params'] );
1544 1290 $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1545 - $query = trim( $params['query'], ';' );
1546 1291
1547 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1292 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1548 1293 $html = $source->fetch( true );
1549 1294 $error = $source->get_error();
1550 1295 if ( ! empty( $error ) ) {
1551 1296 wp_send_json_error( array( 'msg' => $error ) );
@@ -1560,19 +1305,8 @@
1560 1305 */
1561 1306 public function saveQuery() {
1562 1307 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1563 1308
1564 - if ( ! current_user_can( 'administrator' ) ) {
1565 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1566 - }
1567 - if ( ! is_super_admin() ) {
1568 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1569 - }
1570 -
1571 - if ( ! Visualizer_Module::is_pro() ) {
1572 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1573 - }
1574 -
1575 1309 $chart_id = filter_input(
1576 1310 INPUT_GET,
1577 1311 'chart',
1578 1312 FILTER_VALIDATE_INT,
@@ -1585,9 +1319,9 @@
1585 1319
1586 1320 $hours = filter_input(
1587 1321 INPUT_POST,
1588 1322 'refresh',
1589 - FILTER_VALIDATE_FLOAT,
1323 + FILTER_VALIDATE_INT,
1590 1324 array(
1591 1325 'options' => array(
1592 1326 'min_range' => -1,
1593 1327 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1594,9 +1328,9 @@
1594 1328 ),
1595 1329 )
1596 1330 );
1597 1331
1598 - if ( ! is_numeric( $hours ) ) {
1332 + if ( ! is_int( $hours ) ) {
1599 1333 $hours = -1;
1600 1334 }
1601 1335
1602 1336 $render = new Visualizer_Render_Page_Update();
@@ -1601,14 +1335,13 @@
1601 1335
1602 1336 $render = new Visualizer_Render_Page_Update();
1603 1337 if ( $chart_id ) {
1604 1338 $params = wp_parse_args( $_POST['params'] );
1605 - $query = trim( $params['query'], ';' );
1606 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1339 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1607 1340 $source->fetch( false );
1608 1341 $error = $source->get_error();
1609 1342 if ( empty( $error ) ) {
1610 - 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'] ) );
1611 1344 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1612 1345 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1613 1346 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1614 1347 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
@@ -1637,9 +1370,9 @@
1637 1370 }
1638 1371 }
1639 1372 $render->render();
1640 1373 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1641 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1374 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1642 1375 }
1643 1376 }
1644 1377
1645 1378
@@ -1664,9 +1397,9 @@
1664 1397
1665 1398 $hours = filter_input(
1666 1399 INPUT_POST,
1667 1400 'refresh',
1668 - FILTER_VALIDATE_FLOAT,
1401 + FILTER_VALIDATE_INT,
1669 1402 array(
1670 1403 'options' => array(
1671 1404 'min_range' => -1,
1672 1405 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1673,9 +1406,9 @@
1673 1406 ),
1674 1407 )
1675 1408 );
1676 1409
1677 - if ( ! is_numeric( $hours ) ) {
1410 + if ( 0 !== $hours && empty( $hours ) ) {
1678 1411 $hours = -1;
1679 1412 }
1680 1413
1681 1414 do_action( 'visualizer_save_filter', $chart_id, $hours );
@@ -1680,61 +1413,8 @@
1680 1413
1681 1414 do_action( 'visualizer_save_filter', $chart_id, $hours );
1682 1415
1683 1416 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1684 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1417 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1685 1418 }
1686 - }
1687 -
1688 - /**
1689 - * Save chart image.
1690 - *
1691 - * @param string $base64_img Chart image.
1692 - * @param int $chart_id Chart ID.
1693 - * @param bool $save_attachment Save attachment.
1694 - * @return attachment ID
1695 - */
1696 - public function save_chart_image( $base64_img, $chart_id, $save_attachment = true ) {
1697 - // Delete old chart image.
1698 - $old_attachment_id = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, true );
1699 - if ( $old_attachment_id ) {
1700 - wp_delete_attachment( $old_attachment_id, true );
1701 - }
1702 -
1703 - if ( ! $save_attachment ) {
1704 - return 0;
1705 - }
1706 -
1707 - // Upload dir.
1708 - $upload_dir = wp_upload_dir();
1709 - $upload_path = str_replace( '/', DIRECTORY_SEPARATOR, $upload_dir['path'] ) . DIRECTORY_SEPARATOR;
1710 -
1711 - $img = str_replace( 'data:image/png;base64,', '', $base64_img );
1712 - $img = str_replace( ' ', '+', $img );
1713 - $decoded = base64_decode( $img );
1714 - $filename = 'visualization-' . $chart_id . '.png';
1715 - $file_type = 'image/png';
1716 - $hashed_filename = $filename;
1717 -
1718 - // Save the image in the uploads directory.
1719 - require_once ABSPATH . '/wp-admin/includes/file.php';
1720 - \WP_Filesystem();
1721 - global $wp_filesystem;
1722 - if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base' ) ) {
1723 - $creds = request_filesystem_credentials( site_url() );
1724 - wp_filesystem( $creds );
1725 - }
1726 - $upload_file = $wp_filesystem->put_contents( $upload_path . $hashed_filename, $decoded );
1727 -
1728 - // Insert new chart image.
1729 - $attachment = array(
1730 - 'post_mime_type' => $file_type,
1731 - 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $hashed_filename ) ),
1732 - 'post_content' => '',
1733 - 'post_status' => 'inherit',
1734 - 'guid' => $upload_dir['url'] . '/' . basename( $hashed_filename ),
1735 - );
1736 -
1737 - $attach_id = wp_insert_attachment( $attachment, $upload_dir['path'] . '/' . $hashed_filename );
1738 - return $attach_id;
1739 1419 }
1740 1420 }