← All changes
|
includes/admin/settings/class-ph-settings-general.php
+96
-43
2.2.3
→
2.3.1
View file →
| @@ -1,5 +1,8 @@ | ||
| 1 | 1 | <?php |
| 2 | +// phpcs:set WordPress.Security.ValidatedSanitizedInput customSanitizingFunctions[] ph_clean | |
| 3 | +// ph_clean() recursively sanitizes text; presence, shape and unslashing checks remain separate. | |
| 4 | + | |
| 2 | 5 | /** |
| 3 | 6 | * PropertyHive General Settings |
| 4 | 7 | * |
| 5 | 8 | * @author PropertyHive |
| @@ -16,8 +19,9 @@ | ||
| 16 | 19 | |
| 17 | 20 | /** |
| 18 | 21 | * PH_Settings_General |
| 19 | 22 | */ |
| 23 | +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Legacy public global class PH_Settings_General; preserving the existing PH_* class name is required for plugin and extension compatibility. | |
| 20 | 24 | class PH_Settings_General extends PH_Settings_Page { |
| 21 | 25 | |
| 22 | 26 | /** |
| 23 | 27 | * Constructor. |
| @@ -351,9 +355,9 @@ | ||
| 351 | 355 | $settings[] = array( |
| 352 | 356 | 'type' => 'html', |
| 353 | 357 | 'html' => '<script> |
| 354 | 358 | |
| 355 | - var countries = '. json_encode( $countries ) . '; | |
| 359 | + var countries = '. wp_json_encode( $countries, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . '; | |
| 356 | 360 | |
| 357 | 361 | </script>' |
| 358 | 362 | ); |
| 359 | 363 | |
| @@ -559,9 +563,9 @@ | ||
| 559 | 563 | '' => __( 'None', 'propertyhive' ), |
| 560 | 564 | 'recaptcha' => __( 'Google reCaptcha v2', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)', |
| 561 | 565 | 'recaptcha-v3' => __( 'Google reCaptcha v3', 'propertyhive' ) . ' (<a href="https://www.google.com/recaptcha/admin/create" target="_blank">register</a>)', |
| 562 | 566 | 'hCaptcha' => __( 'hCaptcha', 'propertyhive' ) . ' (<a href="https://www.hcaptcha.com/" target="_blank">register</a>)', |
| 563 | - 'turnstile' => __( 'Cloudflare Turnstile', 'propertyhive' ) . ' (<a href="https://www.cloudflare.com/en-gb/application-services/products/turnstile/" target="_blank">register</a>)', | |
| 567 | + 'turnstile' => __( 'Cloudflare Turnstile', 'propertyhive' ) . ' (<a href="https://www.cloudflare.com/en-gb/application-services/products/turnstile/" target="_blank">register</a>)', // phpcs:ignore PluginCheck.CodeAnalysis.Offloading.OffloadedContent -- Registration hyperlink for the optional CAPTCHA provider. | |
| 564 | 568 | ), |
| 565 | 569 | ), |
| 566 | 570 | |
| 567 | 571 | array( |
| @@ -655,12 +659,11 @@ | ||
| 655 | 659 | } |
| 656 | 660 | |
| 657 | 661 | $settings[] = array( |
| 658 | 662 | 'type' => 'html', |
| 663 | + 'full_width' => true, | |
| 659 | 664 | 'html' => ' |
| 660 | 665 | |
| 661 | - <style type="text/css">.form-table .titledesc { display:none; }</style> | |
| 662 | - | |
| 663 | 666 | <table class="widefat striped" style="max-width:520px;" > |
| 664 | 667 | <thead> |
| 665 | 668 | <tr> |
| 666 | 669 | <th style="padding:8px 10px;" scope="col">Text To Replace</th> |
| @@ -919,8 +922,12 @@ | ||
| 919 | 922 | /** |
| 920 | 923 | * Save settings |
| 921 | 924 | */ |
| 922 | 925 | public function save() { |
| 926 | + if ( ! current_user_can( 'manage_options' ) || ! isset( $_REQUEST['_wpnonce'] ) || ! is_string( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'propertyhive-settings' ) ) { | |
| 927 | + return; | |
| 928 | + } | |
| 929 | + | |
| 923 | 930 | global $current_section; |
| 924 | 931 | |
| 925 | 932 | if ( $current_section != '' ) |
| 926 | 933 | { |
| @@ -932,36 +939,48 @@ | ||
| 932 | 939 | |
| 933 | 940 | PH_Admin_Settings::save_fields( $settings ); |
| 934 | 941 | break; |
| 935 | 942 | } |
| 936 | - case 'international': | |
| 937 | - { | |
| 938 | - if (!isset($_POST['propertyhive_countries']) || (isset($_POST['propertyhive_countries']) && empty($_POST['propertyhive_countries']))) | |
| 939 | - { | |
| 940 | - // If we haven't selected which countries we operate in | |
| 941 | - update_option( 'propertyhive_countries', array( ph_clean($_POST['propertyhive_default_country']) ) ); | |
| 942 | - } | |
| 943 | - else | |
| 944 | - { | |
| 945 | - // We have default country and countries set | |
| 946 | - // Make sure default country is in list of countries selected | |
| 947 | - if ( !in_array(ph_clean($_POST['propertyhive_default_country']), ph_clean($_POST['propertyhive_countries'])) ) { | |
| 948 | - $_POST['propertyhive_default_country'] = $_POST['propertyhive_countries'][0]; | |
| 949 | - } | |
| 950 | - | |
| 951 | - update_option( 'propertyhive_default_country', ph_clean($_POST['propertyhive_default_country']) ); | |
| 952 | - update_option( 'propertyhive_countries', ph_clean($_POST['propertyhive_countries']) ); | |
| 953 | - } | |
| 954 | - | |
| 955 | - update_option( 'propertyhive_price_thousand_separator', ph_clean($_POST['propertyhive_price_thousand_separator']) ); | |
| 956 | - update_option( 'propertyhive_price_decimal_separator', ph_clean($_POST['propertyhive_price_decimal_separator']) ); | |
| 957 | - | |
| 958 | - update_option( 'propertyhive_search_form_currency', ph_clean($_POST['propertyhive_search_form_currency']) ); | |
| 959 | - | |
| 960 | - do_action( 'propertyhive_update_currency_exchange_rates' ); | |
| 961 | - | |
| 962 | - break; | |
| 963 | - } | |
| 943 | + case 'international': | |
| 944 | + { | |
| 945 | + $international = array(); | |
| 946 | + foreach ( array( 'propertyhive_default_country', 'propertyhive_price_thousand_separator', 'propertyhive_price_decimal_separator', 'propertyhive_search_form_currency' ) as $input_key ) { | |
| 947 | + if ( ! isset( $_POST[$input_key] ) || ! is_string( $_POST[$input_key] ) ) { | |
| 948 | + return; | |
| 949 | + } | |
| 950 | + $international[$input_key] = sanitize_text_field( wp_unslash( $_POST[$input_key] ) ); | |
| 951 | + } | |
| 952 | + if ( isset( $_POST['propertyhive_countries'] ) && ! is_array( $_POST['propertyhive_countries'] ) ) { | |
| 953 | + return; | |
| 954 | + } | |
| 955 | + $countries = array(); | |
| 956 | + if ( isset( $_POST['propertyhive_countries'] ) ) { | |
| 957 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Each country is validated as a string, unslashed and sanitized in the loop before use. | |
| 958 | + foreach ( $_POST['propertyhive_countries'] as $country ) { | |
| 959 | + if ( ! is_string( $country ) ) { | |
| 960 | + return; | |
| 961 | + } | |
| 962 | + $countries[] = sanitize_text_field( wp_unslash( $country ) ); | |
| 963 | + } | |
| 964 | + } | |
| 965 | + if ( empty( $countries ) ) { | |
| 966 | + // Preserve the existing default-country fallback when no list is selected. | |
| 967 | + update_option( 'propertyhive_countries', array( $international['propertyhive_default_country'] ) ); | |
| 968 | + } else { | |
| 969 | + if ( ! in_array( $international['propertyhive_default_country'], $countries, true ) ) { | |
| 970 | + $international['propertyhive_default_country'] = $countries[0]; | |
| 971 | + // Keep the normalized selection available to existing save-hook consumers. | |
| 972 | + $_POST['propertyhive_default_country'] = wp_slash( $countries[0] ); | |
| 973 | + } | |
| 974 | + update_option( 'propertyhive_default_country', $international['propertyhive_default_country'] ); | |
| 975 | + update_option( 'propertyhive_countries', $countries ); | |
| 976 | + } | |
| 977 | + update_option( 'propertyhive_price_thousand_separator', $international['propertyhive_price_thousand_separator'] ); | |
| 978 | + update_option( 'propertyhive_price_decimal_separator', $international['propertyhive_price_decimal_separator'] ); | |
| 979 | + update_option( 'propertyhive_search_form_currency', $international['propertyhive_search_form_currency'] ); | |
| 980 | + do_action( 'propertyhive_update_currency_exchange_rates' ); | |
| 981 | + break; | |
| 982 | + } | |
| 964 | 983 | case 'map': |
| 965 | 984 | { |
| 966 | 985 | $settings = $this->get_general_map_setting(); |
| 967 | 986 | |
| @@ -992,18 +1011,32 @@ | ||
| 992 | 1011 | case 'text-substitution': |
| 993 | 1012 | { |
| 994 | 1013 | $current_settings = get_option( 'propertyhive_template_assistant', array() ); |
| 995 | 1014 | |
| 1015 | + if ( ! is_array( $current_settings ) ) { | |
| 1016 | + $current_settings = array(); | |
| 1017 | + } | |
| 1018 | + foreach ( array( 'search', 'replace' ) as $field ) { | |
| 1019 | + if ( isset( $_POST[ $field ] ) && ! is_array( $_POST[ $field ] ) ) { | |
| 1020 | + return; | |
| 1021 | + } | |
| 1022 | + } | |
| 996 | 1023 | $text_translations = array(); |
| 997 | 1024 | if ( isset($_POST['search']) && is_array($_POST['search']) && !empty($_POST['search']) && isset($_POST['replace']) && is_array($_POST['replace']) && !empty($_POST['replace']) ) |
| 998 | 1025 | { |
| 1026 | + // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Search members and paired replacement strings are shape-checked, unslashed and sanitized below. | |
| 999 | 1027 | foreach ( $_POST['search'] as $i => $search ) |
| 1000 | 1028 | { |
| 1001 | - if ( trim($search) != '' && trim($_POST['replace'][$i]) != '' ) | |
| 1029 | + if ( ! is_string( $search ) || ! isset( $_POST['replace'][$i] ) || ! is_string( $_POST['replace'][$i] ) ) { | |
| 1030 | + return; | |
| 1031 | + } | |
| 1032 | + $search = sanitize_text_field( wp_unslash( $search ) ); | |
| 1033 | + $replace = sanitize_text_field( wp_unslash( $_POST['replace'][$i] ) ); | |
| 1034 | + if ( trim( $search ) !== '' && trim( $replace ) !== '' ) | |
| 1002 | 1035 | { |
| 1003 | 1036 | $text_translations[] = array( |
| 1004 | - 'search' => sanitize_text_field(wp_unslash($search)), | |
| 1005 | - 'replace' => sanitize_text_field(wp_unslash($_POST['replace'][$i])), | |
| 1037 | + 'search' => $search, | |
| 1038 | + 'replace' => $replace, | |
| 1006 | 1039 | ); |
| 1007 | 1040 | } |
| 1008 | 1041 | } |
| 1009 | 1042 | } |
| @@ -1028,8 +1061,28 @@ | ||
| 1028 | 1061 | } |
| 1029 | 1062 | } |
| 1030 | 1063 | else |
| 1031 | 1064 | { |
| 1065 | + // Validate the complete custom-department form before any options are changed. | |
| 1066 | + $department_lists = array(); | |
| 1067 | + foreach ( array( 'propertyhive_custom_departments', 'propertyhive_custom_departments_original' ) as $field ) { | |
| 1068 | + if ( isset( $_POST[ $field ] ) && ! is_string( $_POST[ $field ] ) ) { | |
| 1069 | + return; | |
| 1070 | + } | |
| 1071 | + $raw_list = isset( $_POST[ $field ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field ] ) ) : ''; | |
| 1072 | + $department_lists[ $field ] = array_filter( explode( ',', $raw_list ) ); | |
| 1073 | + } | |
| 1074 | + $department_details = array(); | |
| 1075 | + foreach ( $department_lists['propertyhive_custom_departments'] as $department_id ) { | |
| 1076 | + foreach ( array( 'name', 'based_on' ) as $detail ) { | |
| 1077 | + $field = 'propertyhive_active_departments_' . $detail . '_' . $department_id; | |
| 1078 | + if ( ! isset( $_POST[ $field ] ) || ! is_string( $_POST[ $field ] ) ) { | |
| 1079 | + return; | |
| 1080 | + } | |
| 1081 | + $department_details[ $department_id ][ $detail ] = sanitize_text_field( wp_unslash( $_POST[ $field ] ) ); | |
| 1082 | + } | |
| 1083 | + } | |
| 1084 | + | |
| 1032 | 1085 | $settings = $this->get_settings(); |
| 1033 | 1086 | |
| 1034 | 1087 | PH_Admin_Settings::save_fields( $settings ); |
| 1035 | 1088 | |
| @@ -1057,11 +1110,11 @@ | ||
| 1057 | 1110 | update_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key), $option_value ); |
| 1058 | 1111 | } |
| 1059 | 1112 | |
| 1060 | 1113 | $custom_departments = array(); |
| 1061 | - if ( isset($_POST['propertyhive_custom_departments']) && !empty($_POST['propertyhive_custom_departments']) ) | |
| 1114 | + if ( ! empty( $department_lists['propertyhive_custom_departments'] ) ) | |
| 1062 | 1115 | { |
| 1063 | - $submitted_custom_departments = explode(",", $_POST['propertyhive_custom_departments']); | |
| 1116 | + $submitted_custom_departments = $department_lists['propertyhive_custom_departments']; | |
| 1064 | 1117 | $submitted_custom_departments = array_filter($submitted_custom_departments); |
| 1065 | 1118 | if ( !empty($submitted_custom_departments) ) |
| 1066 | 1119 | { |
| 1067 | 1120 | foreach ( $submitted_custom_departments as $submitted_custom_department ) |
| @@ -1079,14 +1132,14 @@ | ||
| 1079 | 1132 | |
| 1080 | 1133 | $key = $submitted_custom_department; |
| 1081 | 1134 | if ( substr($submitted_custom_department, 0, 6) == 'phnew-' ) |
| 1082 | 1135 | { |
| 1083 | - $key = sanitize_title($_POST['propertyhive_active_departments_name_' . $submitted_custom_department]); | |
| 1136 | + $key = sanitize_title( $department_details[ $submitted_custom_department ]['name'] ); | |
| 1084 | 1137 | } |
| 1085 | 1138 | |
| 1086 | 1139 | $custom_departments[$key] = array( |
| 1087 | - 'name' => ph_clean($_POST['propertyhive_active_departments_name_' . $submitted_custom_department ]), | |
| 1088 | - 'based_on' => ph_clean($_POST['propertyhive_active_departments_based_on_' . $submitted_custom_department ]) | |
| 1140 | + 'name' => $department_details[ $submitted_custom_department ]['name'], | |
| 1141 | + 'based_on' => $department_details[ $submitted_custom_department ]['based_on'] | |
| 1089 | 1142 | ); |
| 1090 | 1143 | |
| 1091 | 1144 | update_option( 'propertyhive_active_departments_' . $key, $option_value ); |
| 1092 | 1145 | } |
| @@ -1095,15 +1148,15 @@ | ||
| 1095 | 1148 | |
| 1096 | 1149 | update_option( 'propertyhive_custom_departments', $custom_departments ); |
| 1097 | 1150 | |
| 1098 | 1151 | // TO DO: Cater for deleted departments |
| 1099 | - if ( isset($_POST['propertyhive_custom_departments_original']) && !empty($_POST['propertyhive_custom_departments_original']) ) | |
| 1152 | + if ( ! empty( $department_lists['propertyhive_custom_departments_original'] ) ) | |
| 1100 | 1153 | { |
| 1101 | - $original_custom_departments = explode(",", $_POST['propertyhive_custom_departments_original']); | |
| 1154 | + $original_custom_departments = $department_lists['propertyhive_custom_departments_original']; | |
| 1102 | 1155 | $original_custom_departments = array_filter($original_custom_departments); |
| 1103 | 1156 | if ( !empty($original_custom_departments) ) |
| 1104 | 1157 | { |
| 1105 | - $submitted_custom_departments = explode(",", $_POST['propertyhive_custom_departments']); | |
| 1158 | + $submitted_custom_departments = $department_lists['propertyhive_custom_departments']; | |
| 1106 | 1159 | $submitted_custom_departments = array_filter($submitted_custom_departments); |
| 1107 | 1160 | |
| 1108 | 1161 | foreach ( $original_custom_departments as $original_custom_department ) |
| 1109 | 1162 | { |