PluginProbe
Property Hive / 2.3.1
Property Hive v2.3.1
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
← All changes | includes/admin/settings/class-ph-settings-general.php +96 -43 2.2.42.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 {