PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.9.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.9.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 +76 -219 4.0.33.9.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.
@@ -295,9 +296,9 @@
295 296 $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
296 297 $render->series = json_encode( $source->getSeries() );
297 298 $render->render();
298 299
299 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
300 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
300 301 }
301 302
302 303
303 304 /**
@@ -373,13 +374,13 @@
373 374 * @since 1.0.0
374 375 *
375 376 * @access private
376 377 *
377 - * @param WP_Post|null $chart The chart object.
378 + * @param WP_Post $chart The chart object.
378 379 *
379 380 * @return array The array of chart data.
380 381 */
381 - private function _getChartArray( $chart = null ) {
382 + private function _getChartArray( WP_Post $chart = null ) {
382 383 if ( is_null( $chart ) ) {
383 384 $chart = $this->_chart;
384 385 }
385 386 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
@@ -401,13 +402,8 @@
401 402 }
402 403
403 404 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
404 405
405 - $code = '';
406 - if ( 'd3' === $library ) {
407 - $code = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
408 - }
409 -
410 406 return array(
411 407 'type' => $type,
412 408 'series' => $series,
413 409 'settings' => $settings,
@@ -412,9 +408,8 @@
412 408 'series' => $series,
413 409 'settings' => $settings,
414 410 'data' => $data,
415 411 'library' => $library,
416 - 'code' => $code,
417 412 'css' => $css,
418 413 'date_formats' => $date_formats,
419 414 );
420 415 }
@@ -431,9 +426,9 @@
431 426 public static function _sendResponse( $results ) {
432 427 header( 'Content-type: application/json' );
433 428 nocache_headers();
434 429 echo json_encode( $results );
435 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
430 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
436 431 }
437 432
438 433 /**
439 434 * Deletes a chart from database.
@@ -528,12 +523,8 @@
528 523 *
529 524 * @access public
530 525 */
531 526 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 527 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
537 528 if ( ! defined( 'ET_BUILDER_PRODUCT_VERSION' ) && function_exists( 'et_get_theme_version' ) ) {
538 529 define( 'ET_BUILDER_PRODUCT_VERSION', et_get_theme_version() );
539 530 }
@@ -540,20 +531,12 @@
540 531 // Set current screen for the render chart.
541 532 set_current_screen( 'visualizer_render_chart' );
542 533 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
543 534 $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 ) {
535 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
549 536 if ( empty( $_GET['lang'] ) || empty( $_GET['parent_chart_id'] ) ) {
550 537 $this->deleteOldCharts();
551 538 $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 539 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
557 540 $source->fetch();
558 541 $chart_id = wp_insert_post(
559 542 array(
@@ -580,33 +563,35 @@
580 563
581 564 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
582 565 }
583 566 } 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 - );
567 + if ( current_user_can( 'edit_posts' ) ) {
568 + $parent_chart_id = isset( $_GET['parent_chart_id'] ) ? filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT ) : '';
569 + $success = false;
570 + if ( $parent_chart_id ) {
571 + $parent_chart = get_post( $parent_chart_id );
572 + $success = $parent_chart && $parent_chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
573 + }
574 + if ( $success ) {
575 + $new_chart_id = wp_insert_post(
576 + array(
577 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
578 + 'post_title' => 'Visualization',
579 + 'post_author' => get_current_user_id(),
580 + 'post_status' => $parent_chart->post_status,
581 + 'post_content' => $parent_chart->post_content,
582 + )
583 + );
600 584
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] ) );
585 + if ( is_wp_error( $new_chart_id ) ) {
586 + 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__ );
587 + } else {
588 + $post_meta = get_post_meta( $parent_chart_id );
589 + $chart_id = $new_chart_id;
590 + foreach ( $post_meta as $key => $value ) {
591 + if ( strpos( $key, 'visualizer-' ) !== false ) {
592 + add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
593 + }
609 594 }
610 595 }
611 596 }
612 597 }
@@ -613,9 +598,9 @@
613 598 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
614 599 }
615 600 wp_redirect( esc_url_raw( add_query_arg( 'chart', (int) $chart_id ) ) );
616 601
617 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
602 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
618 603 wp_die();
619 604 }
620 605 exit();
621 606 }
@@ -711,9 +696,9 @@
711 696 default:
712 697 // this should never happen.
713 698 break;
714 699 }
715 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
700 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
716 701 }
717 702
718 703 /**
719 704 * Load code editor assets.
@@ -743,9 +728,9 @@
743 728 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
744 729 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
745 730 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
746 731 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 );
732 + 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 733 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
749 734 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
750 735
751 736 wp_enqueue_script( 'visualizer-codemirror-hint' );
@@ -759,9 +744,9 @@
759 744 'lineWrapping' => true,
760 745 'dragDrop' => false,
761 746 'matchBrackets' => true,
762 747 'autoCloseBrackets' => true,
763 - 'extraKeys' => array( 'Shift-Space' => 'autocomplete' ),
748 + 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
764 749 'hintOptions' => array( 'tables' => $table_col_mapping ),
765 750 ),
766 751 )
767 752 );
@@ -795,12 +780,9 @@
795 780 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
796 781 }
797 782
798 783 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 ) {
784 + if ( $this->_chart->post_status === 'auto-draft' ) {
803 785 $this->_chart->post_status = 'publish';
804 786
805 787 // 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 788 // we do not want any difference in data so disable revisions temporarily.
@@ -808,15 +790,10 @@
808 790
809 791 wp_update_post( $this->_chart->to_array() );
810 792 }
811 793 // 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 );
794 + if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
795 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
819 796
820 797 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
821 798 // this will help in searching with the chart id.
822 799 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -863,9 +840,8 @@
863 840 wp_enqueue_style( 'visualizer-frame' );
864 841 wp_enqueue_script( 'visualizer-preview' );
865 842 wp_enqueue_script( 'visualizer-chosen' );
866 843 wp_enqueue_script( 'visualizer-render' );
867 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
868 844
869 845 if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
870 846 wp_enqueue_script( 'visualizer-editor-simple' );
871 847 wp_localize_script(
@@ -873,10 +849,12 @@
873 849 'visualizer1',
874 850 array(
875 851 'ajax' => array(
876 852 'url' => admin_url( 'admin-ajax.php' ),
877 - 'nonces' => array(),
878 - 'actions' => array(),
853 + 'nonces' => array(
854 + ),
855 + 'actions' => array(
856 + ),
879 857 ),
880 858 )
881 859 );
882 860 }
@@ -887,15 +865,13 @@
887 865 'visualizer-render',
888 866 'visualizer',
889 867 array(
890 868 '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' ),
869 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
870 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
871 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
872 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
873 + '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 874 ),
899 875 'charts' => array(
900 876 'canvas' => $data,
901 877 'id' => $this->_chart->ID,
@@ -939,10 +915,11 @@
939 915 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
940 916 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
941 917 ? esc_html__( 'Save Chart', 'visualizer' )
942 918 : esc_html__( 'Create Chart', 'visualizer' );
943 -
944 - $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
919 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
920 + $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
921 + }
945 922 } else {
946 923 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
947 924 }
948 925
@@ -965,12 +942,12 @@
965 942 * @access private
966 943 */
967 944 private function _handleTypesPage() {
968 945 // process post request
969 - if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ), 'visualizer-upload-data' ) ) {
946 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
970 947 $type = filter_input( INPUT_POST, 'type' );
971 948 $library = filter_input( INPUT_POST, 'chart-library' );
972 - if ( Visualizer_Module_Admin::checkChartStatus( $type ) ) {
949 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
973 950 if ( empty( $library ) ) {
974 951 // library cannot be empty.
975 952 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
976 953 return;
@@ -1022,80 +999,8 @@
1022 999 * Processes the CSV that is sent in the request as a string.
1023 1000 *
1024 1001 * @since 3.2.0
1025 1002 */
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 1003 private function handleCSVasString( $data, $editor_type ) {
1099 1004 $source = null;
1100 1005
1101 1006 switch ( $editor_type ) {
@@ -1110,9 +1015,9 @@
1110 1015 continue;
1111 1016 }
1112 1017 $row = explode( ',', $row );
1113 1018 $row = array_map(
1114 - function ( $r ) {
1019 + function( $r ) {
1115 1020 return '' === $r ? ' ' : $r;
1116 1021 },
1117 1022 $row
1118 1023 );
@@ -1161,9 +1066,9 @@
1161 1066 foreach ( $types as $type ) {
1162 1067 if ( empty( $type ) ) {
1163 1068 $exclude[] = $index;
1164 1069 }
1165 - ++$index;
1070 + $index++;
1166 1071 }
1167 1072
1168 1073 // when N headers are being renamed, the number of headers increases by N
1169 1074 // because of the way datatable duplicates header information
@@ -1223,13 +1128,9 @@
1223 1128 // otherwise, assume this is a normal web request.
1224 1129 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
1225 1130
1226 1131 // validate nonce
1227 - if (
1228 - ! isset( $_GET['nonce'] ) ||
1229 - ! wp_verify_nonce( $_GET['nonce'], 'visualizer-upload-data' ) ||
1230 - ! current_user_can( 'edit_posts' )
1231 - ) {
1132 + if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
1232 1133 if ( ! $can_die ) {
1233 1134 return;
1234 1135 }
1235 1136 status_header( 403 );
@@ -1238,15 +1139,9 @@
1238 1139
1239 1140 // check chart, if chart exists
1240 1141 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1241 1142 $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 - ) {
1143 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
1249 1144 if ( ! $can_die ) {
1250 1145 return;
1251 1146 }
1252 1147 status_header( 400 );
@@ -1293,24 +1188,15 @@
1293 1188 if ( isset( $_POST['remote_data'] ) && function_exists( 'wp_http_validate_url' ) ) {
1294 1189 $remote_data = wp_http_validate_url( $_POST['remote_data'] );
1295 1190 }
1296 1191 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 - }
1192 + $source = new Visualizer_Source_Csv_Remote( $remote_data );
1303 1193 if ( isset( $_POST['vz-import-time'] ) ) {
1304 1194 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $remote_data, $_POST['vz-import-time'] );
1305 1195 }
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 - }
1196 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
1197 + } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
1198 + $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1313 1199 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1314 1200 $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1315 1201 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1316 1202 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
@@ -1317,10 +1203,10 @@
1317 1203 $source = $this->handleTabularData();
1318 1204 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1319 1205 } else {
1320 1206 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' ) );
1207 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1208 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
1323 1209 }
1324 1210
1325 1211 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 1212
@@ -1368,9 +1254,9 @@
1368 1254 $render->settings = json_encode( $settings );
1369 1255 } else {
1370 1256 $error = $source->get_error();
1371 1257 if ( empty( $error ) ) {
1372 - $error = esc_html__( 'The CSV file couldn\'t be read. Check that it\'s properly formatted and try again.', 'visualizer' );
1258 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1373 1259 }
1374 1260 $render->message = $error;
1375 1261 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1376 1262 update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
@@ -1381,9 +1267,9 @@
1381 1267 $render->render();
1382 1268 if ( ! $can_die ) {
1383 1269 return;
1384 1270 }
1385 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1271 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1386 1272 }
1387 1273
1388 1274 /**
1389 1275 * Clones the chart.
@@ -1437,9 +1323,9 @@
1437 1323 );
1438 1324 }
1439 1325 }
1440 1326
1441 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1327 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1442 1328 wp_die();
1443 1329 }
1444 1330 wp_redirect( $redirect );
1445 1331 exit;
@@ -1472,9 +1358,9 @@
1472 1358 }
1473 1359 }
1474 1360 }
1475 1361
1476 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1362 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1477 1363 }
1478 1364
1479 1365 /**
1480 1366 * Handles chart data page.
@@ -1498,11 +1384,10 @@
1498 1384 'visualizer-render',
1499 1385 'visualizer',
1500 1386 array(
1501 1387 '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' ),
1388 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
1389 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1505 1390 ),
1506 1391 'charts' => array(
1507 1392 'canvas' => $data,
1508 1393 ),
@@ -1528,24 +1413,12 @@
1528 1413 */
1529 1414 public function getQueryData() {
1530 1415 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1531 1416
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 1417 $params = wp_parse_args( $_POST['params'] );
1544 1418 $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1545 - $query = trim( $params['query'], ';' );
1546 1419
1547 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1420 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1548 1421 $html = $source->fetch( true );
1549 1422 $error = $source->get_error();
1550 1423 if ( ! empty( $error ) ) {
1551 1424 wp_send_json_error( array( 'msg' => $error ) );
@@ -1560,19 +1433,8 @@
1560 1433 */
1561 1434 public function saveQuery() {
1562 1435 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1563 1436
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 1437 $chart_id = filter_input(
1576 1438 INPUT_GET,
1577 1439 'chart',
1578 1440 FILTER_VALIDATE_INT,
@@ -1601,14 +1463,13 @@
1601 1463
1602 1464 $render = new Visualizer_Render_Page_Update();
1603 1465 if ( $chart_id ) {
1604 1466 $params = wp_parse_args( $_POST['params'] );
1605 - $query = trim( $params['query'], ';' );
1606 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1467 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
1607 1468 $source->fetch( false );
1608 1469 $error = $source->get_error();
1609 1470 if ( empty( $error ) ) {
1610 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $query ) );
1471 + update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
1611 1472 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1612 1473 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1613 1474 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1614 1475 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
@@ -1637,9 +1498,9 @@
1637 1498 }
1638 1499 }
1639 1500 $render->render();
1640 1501 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1641 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1502 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1642 1503 }
1643 1504 }
1644 1505
1645 1506
@@ -1664,9 +1525,9 @@
1664 1525
1665 1526 $hours = filter_input(
1666 1527 INPUT_POST,
1667 1528 'refresh',
1668 - FILTER_VALIDATE_FLOAT,
1529 + FILTER_VALIDATE_INT,
1669 1530 array(
1670 1531 'options' => array(
1671 1532 'min_range' => -1,
1672 1533 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1673,9 +1534,9 @@
1673 1534 ),
1674 1535 )
1675 1536 );
1676 1537
1677 - if ( ! is_numeric( $hours ) ) {
1538 + if ( 0 !== $hours && empty( $hours ) ) {
1678 1539 $hours = -1;
1679 1540 }
1680 1541
1681 1542 do_action( 'visualizer_save_filter', $chart_id, $hours );
@@ -1680,9 +1541,9 @@
1680 1541
1681 1542 do_action( 'visualizer_save_filter', $chart_id, $hours );
1682 1543
1683 1544 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1684 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1545 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1685 1546 }
1686 1547 }
1687 1548
1688 1549 /**
@@ -1718,12 +1579,8 @@
1718 1579 // Save the image in the uploads directory.
1719 1580 require_once ABSPATH . '/wp-admin/includes/file.php';
1720 1581 \WP_Filesystem();
1721 1582 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 1583 $upload_file = $wp_filesystem->put_contents( $upload_path . $hashed_filename, $decoded );
1727 1584
1728 1585 // Insert new chart image.
1729 1586 $attachment = array(