PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.15
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.15
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 +38 -140 4.0.53.11.15 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.
@@ -169,12 +170,8 @@
169 170 */
170 171 public function getJsonRoots() {
171 172 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
172 173
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 174 $params = wp_parse_args( $_POST['params'] );
178 175
179 176 $source = new Visualizer_Source_Json( $params );
180 177
@@ -195,12 +192,8 @@
195 192 */
196 193 public function getJsonData() {
197 194 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
198 195
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 196 $params = wp_parse_args( $_POST['params'] );
204 197
205 198 $chart_id = $params['chart'];
206 199
@@ -303,9 +296,9 @@
303 296 $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
304 297 $render->series = json_encode( $source->getSeries() );
305 298 $render->render();
306 299
307 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
300 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
308 301 }
309 302
310 303
311 304 /**
@@ -409,13 +402,8 @@
409 402 }
410 403
411 404 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
412 405
413 - $code = '';
414 - if ( 'd3' === $library ) {
415 - $code = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
416 - }
417 -
418 406 return array(
419 407 'type' => $type,
420 408 'series' => $series,
421 409 'settings' => $settings,
@@ -420,9 +408,8 @@
420 408 'series' => $series,
421 409 'settings' => $settings,
422 410 'data' => $data,
423 411 'library' => $library,
424 - 'code' => $code,
425 412 'css' => $css,
426 413 'date_formats' => $date_formats,
427 414 );
428 415 }
@@ -439,9 +426,9 @@
439 426 public static function _sendResponse( $results ) {
440 427 header( 'Content-type: application/json' );
441 428 nocache_headers();
442 429 echo json_encode( $results );
443 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
430 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
444 431 }
445 432
446 433 /**
447 434 * Deletes a chart from database.
@@ -551,10 +538,9 @@
551 538 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
552 539 if ( ! empty( $_POST ) ) {
553 540 $_POST = map_deep( $_POST, 'wp_strip_all_tags' );
554 541 }
555 - $chart = $chart_id ? get_post( $chart_id ) : null;
556 - if ( ! $chart_id || ! $chart || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
542 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
557 543 if ( empty( $_GET['lang'] ) || empty( $_GET['parent_chart_id'] ) ) {
558 544 $this->deleteOldCharts();
559 545 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
560 546 $chart_status = Visualizer_Module_Admin::checkChartStatus( $default_type );
@@ -588,9 +574,9 @@
588 574
589 575 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
590 576 }
591 577 } else {
592 - $parent_chart_id = filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT );
578 + $parent_chart_id = isset( $_GET['parent_chart_id'] ) ? filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT ) : '';
593 579 $success = false;
594 580 if ( $parent_chart_id ) {
595 581 $parent_chart = get_post( $parent_chart_id );
596 582 $success = $parent_chart && $parent_chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
@@ -621,9 +607,9 @@
621 607 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
622 608 }
623 609 wp_redirect( esc_url_raw( add_query_arg( 'chart', (int) $chart_id ) ) );
624 610
625 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
611 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
626 612 wp_die();
627 613 }
628 614 exit();
629 615 }
@@ -719,9 +705,9 @@
719 705 default:
720 706 // this should never happen.
721 707 break;
722 708 }
723 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
709 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
724 710 }
725 711
726 712 /**
727 713 * Load code editor assets.
@@ -751,9 +737,9 @@
751 737 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
752 738 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
753 739 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
754 740 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 );
741 + 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 742 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
757 743 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
758 744
759 745 wp_enqueue_script( 'visualizer-codemirror-hint' );
@@ -817,14 +803,9 @@
817 803 wp_update_post( $this->_chart->to_array() );
818 804 }
819 805 // save meta data only when it is NOT being canceled.
820 806 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 );
807 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
827 808
828 809 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
829 810 // this will help in searching with the chart id.
830 811 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
@@ -871,9 +852,8 @@
871 852 wp_enqueue_style( 'visualizer-frame' );
872 853 wp_enqueue_script( 'visualizer-preview' );
873 854 wp_enqueue_script( 'visualizer-chosen' );
874 855 wp_enqueue_script( 'visualizer-render' );
875 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
876 856
877 857 if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
878 858 wp_enqueue_script( 'visualizer-editor-simple' );
879 859 wp_localize_script(
@@ -881,10 +861,12 @@
881 861 'visualizer1',
882 862 array(
883 863 'ajax' => array(
884 864 'url' => admin_url( 'admin-ajax.php' ),
885 - 'nonces' => array(),
886 - 'actions' => array(),
865 + 'nonces' => array(
866 + ),
867 + 'actions' => array(
868 + ),
887 869 ),
888 870 )
889 871 );
890 872 }
@@ -895,15 +877,14 @@
895 877 'visualizer-render',
896 878 'visualizer',
897 879 array(
898 880 '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' ),
881 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
882 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
883 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
884 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
885 + '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' ),
886 + 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
906 887 ),
907 888 'charts' => array(
908 889 'canvas' => $data,
909 890 'id' => $this->_chart->ID,
@@ -1030,80 +1011,8 @@
1030 1011 * Processes the CSV that is sent in the request as a string.
1031 1012 *
1032 1013 * @since 3.2.0
1033 1014 */
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 1015 private function handleCSVasString( $data, $editor_type ) {
1107 1016 $source = null;
1108 1017
1109 1018 switch ( $editor_type ) {
@@ -1118,9 +1027,9 @@
1118 1027 continue;
1119 1028 }
1120 1029 $row = explode( ',', $row );
1121 1030 $row = array_map(
1122 - function ( $r ) {
1031 + function( $r ) {
1123 1032 return '' === $r ? ' ' : $r;
1124 1033 },
1125 1034 $row
1126 1035 );
@@ -1169,9 +1078,9 @@
1169 1078 foreach ( $types as $type ) {
1170 1079 if ( empty( $type ) ) {
1171 1080 $exclude[] = $index;
1172 1081 }
1173 - ++$index;
1082 + $index++;
1174 1083 }
1175 1084
1176 1085 // when N headers are being renamed, the number of headers increases by N
1177 1086 // because of the way datatable duplicates header information
@@ -1246,12 +1155,11 @@
1246 1155
1247 1156 // check chart, if chart exists
1248 1157 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1249 1158 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1250 - $chart = $chart_id ? get_post( $chart_id ) : null;
1251 1159 if (
1252 1160 ! $chart_id ||
1253 - ! $chart ||
1161 + ! ( $chart = get_post( $chart_id ) ) ||
1254 1162 $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ||
1255 1163 ! current_user_can( 'edit_post', $chart_id )
1256 1164 ) {
1257 1165 if ( ! $can_die ) {
@@ -1301,24 +1209,15 @@
1301 1209 if ( isset( $_POST['remote_data'] ) && function_exists( 'wp_http_validate_url' ) ) {
1302 1210 $remote_data = wp_http_validate_url( $_POST['remote_data'] );
1303 1211 }
1304 1212 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 - }
1213 + $source = new Visualizer_Source_Csv_Remote( $remote_data );
1311 1214 if ( isset( $_POST['vz-import-time'] ) ) {
1312 1215 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $remote_data, $_POST['vz-import-time'] );
1313 1216 }
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 - }
1217 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
1218 + } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
1219 + $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1321 1220 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1322 1221 $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1323 1222 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1324 1223 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
@@ -1325,10 +1224,10 @@
1325 1224 $source = $this->handleTabularData();
1326 1225 update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1327 1226 } else {
1328 1227 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' ) );
1228 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1229 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
1331 1230 }
1332 1231
1333 1232 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 1233
@@ -1376,9 +1275,9 @@
1376 1275 $render->settings = json_encode( $settings );
1377 1276 } else {
1378 1277 $error = $source->get_error();
1379 1278 if ( empty( $error ) ) {
1380 - $error = esc_html__( 'The CSV file couldn\'t be read. Check that it\'s properly formatted and try again.', 'visualizer' );
1279 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1381 1280 }
1382 1281 $render->message = $error;
1383 1282 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1384 1283 update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
@@ -1389,9 +1288,9 @@
1389 1288 $render->render();
1390 1289 if ( ! $can_die ) {
1391 1290 return;
1392 1291 }
1393 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1292 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1394 1293 }
1395 1294
1396 1295 /**
1397 1296 * Clones the chart.
@@ -1445,9 +1344,9 @@
1445 1344 );
1446 1345 }
1447 1346 }
1448 1347
1449 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1348 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1450 1349 wp_die();
1451 1350 }
1452 1351 wp_redirect( $redirect );
1453 1352 exit;
@@ -1480,9 +1379,9 @@
1480 1379 }
1481 1380 }
1482 1381 }
1483 1382
1484 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1383 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1485 1384 }
1486 1385
1487 1386 /**
1488 1387 * Handles chart data page.
@@ -1506,11 +1405,10 @@
1506 1405 'visualizer-render',
1507 1406 'visualizer',
1508 1407 array(
1509 1408 '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' ),
1409 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
1410 + 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1513 1411 ),
1514 1412 'charts' => array(
1515 1413 'canvas' => $data,
1516 1414 ),
@@ -1645,9 +1543,9 @@
1645 1543 }
1646 1544 }
1647 1545 $render->render();
1648 1546 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1649 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1547 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1650 1548 }
1651 1549 }
1652 1550
1653 1551
@@ -1672,9 +1570,9 @@
1672 1570
1673 1571 $hours = filter_input(
1674 1572 INPUT_POST,
1675 1573 'refresh',
1676 - FILTER_VALIDATE_FLOAT,
1574 + FILTER_VALIDATE_INT,
1677 1575 array(
1678 1576 'options' => array(
1679 1577 'min_range' => -1,
1680 1578 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
@@ -1681,9 +1579,9 @@
1681 1579 ),
1682 1580 )
1683 1581 );
1684 1582
1685 - if ( ! is_numeric( $hours ) ) {
1583 + if ( 0 !== $hours && empty( $hours ) ) {
1686 1584 $hours = -1;
1687 1585 }
1688 1586
1689 1587 do_action( 'visualizer_save_filter', $chart_id, $hours );
@@ -1688,9 +1586,9 @@
1688 1586
1689 1587 do_action( 'visualizer_save_filter', $chart_id, $hours );
1690 1588
1691 1589 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1692 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1590 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1693 1591 }
1694 1592 }
1695 1593
1696 1594 /**