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/ph-form-functions.php +158 -84 2.2.22.3.1 View file →
@@ -1,5 +1,13 @@
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 +
5 +
6 +if ( ! defined( 'ABSPATH' ) ) {
7 + exit;
8 +}
9 +
2 10 /**
3 11 * PropertyHive Form Functions
4 12 *
5 13 * Functions related to drawing forms on the frontend.
@@ -16,8 +24,9 @@
16 24 *
17 25 * @param string $id
18 26 * @return void
19 27 */
28 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_get_search_form; the established callable name is part of the plugin/extension API and must remain stable.
20 29 function ph_get_search_form( $id = 'default' ) {
21 30
22 31 $form_controls = ph_get_search_form_fields();
23 32
@@ -34,8 +43,9 @@
34 43 $form_controls['department'] = $original_department;
35 44 }
36 45
37 46 // append hidden order and view fields so these are maintained should a new search be performed
47 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
38 48 foreach ( $_REQUEST as $key => $value )
39 49 {
40 50 if ( isset($form_controls[$key]) )
41 51 continue;
@@ -78,8 +88,9 @@
78 88 * Get default fields to be shown on search forms
79 89 *
80 90 * @return array
81 91 */
92 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_get_search_form_fields; the established callable name is part of the plugin/extension API and must remain stable.
82 93 function ph_get_search_form_fields()
83 94 {
84 95 $fields = array();
85 96
@@ -316,9 +327,9 @@
316 327 }
317 328
318 329 if ( get_option( 'propertyhive_property_enquiry_form_disclaimer', '' ) != '' )
319 330 {
320 - $disclaimer = get_option( 'propertyhive_property_enquiry_form_disclaimer', '' );
331 + $disclaimer = wp_kses_post( get_option( 'propertyhive_property_enquiry_form_disclaimer', '' ) );
321 332
322 333 $form_controls['disclaimer'] = array(
323 334 'type' => 'checkbox',
324 335 'label' => $disclaimer,
@@ -334,8 +345,9 @@
334 345 * Get default fields to be shown on search forms
335 346 *
336 347 * @return array
337 348 */
349 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_get_property_enquiry_form_fields; the established callable name is part of the plugin/extension API and must remain stable.
338 350 function ph_get_property_enquiry_form_fields( $property_id = '' )
339 351 {
340 352 global $post;
341 353
@@ -392,8 +404,9 @@
392 404 * Get default fields to be shown on applicant registration forms
393 405 *
394 406 * @return array
395 407 */
408 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_get_user_details_form_fields; the established callable name is part of the plugin/extension API and must remain stable.
396 409 function ph_get_user_details_form_fields()
397 410 {
398 411 global $post;
399 412
@@ -461,8 +474,9 @@
461 474 * Get default fields to be shown on applicant registration forms
462 475 *
463 476 * @return array
464 477 */
478 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_get_applicant_requirements_form_fields; the established callable name is part of the plugin/extension API and must remain stable.
465 479 function ph_get_applicant_requirements_form_fields($applicant_profile = false)
466 480 {
467 481 global $post;
468 482
@@ -592,9 +606,9 @@
592 606 $args = array(
593 607 'hide_empty' => false,
594 608 'parent' => 0
595 609 );
596 - $terms = get_terms( 'property_type', $args );
610 + $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'property_type' ) ) );
597 611
598 612 $options = array();
599 613
600 614 $selected_value = '';
@@ -609,9 +623,9 @@
609 623 $args = array(
610 624 'hide_empty' => false,
611 625 'parent' => $term->term_id
612 626 );
613 - $subterms = get_terms( 'property_type', $args );
627 + $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'property_type' ) ) );
614 628
615 629 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
616 630 {
617 631 foreach ($subterms as $term)
@@ -691,9 +705,9 @@
691 705 $args = array(
692 706 'hide_empty' => false,
693 707 'parent' => 0
694 708 );
695 - $terms = get_terms( 'commercial_property_type', $args );
709 + $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'commercial_property_type' ) ) );
696 710
697 711 $options = array();
698 712
699 713 $selected_value = '';
@@ -708,9 +722,9 @@
708 722 $args = array(
709 723 'hide_empty' => false,
710 724 'parent' => $term->term_id
711 725 );
712 - $subterms = get_terms( 'commercial_property_type', $args );
726 + $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'commercial_property_type' ) ) );
713 727
714 728 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
715 729 {
716 730 foreach ($subterms as $term)
@@ -744,9 +758,9 @@
744 758 $args = array(
745 759 'hide_empty' => false,
746 760 'parent' => 0
747 761 );
748 - $terms = get_terms( 'location', $args );
762 + $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'location' ) ) );
749 763
750 764 if ( !empty( $terms ) && !is_wp_error( $terms ) )
751 765 {
752 766 $fields['location'] = array(
@@ -794,8 +808,9 @@
794 808 * Output individual field
795 809 *
796 810 * @return void
797 811 */
812 +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_form_field; the established callable name is part of the plugin/extension API and must remain stable.
798 813 function ph_form_field( $key, $field )
799 814 {
800 815 global $post;
801 816
@@ -810,9 +825,9 @@
810 825 case "password":
811 826 {
812 827 $field['id'] = isset( $field['id'] ) ? $field['id'] : $key;
813 828 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
814 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
829 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
815 830 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
816 831 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
817 832 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
818 833 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : ( ( $field['type'] == 'date' ) ? 'dd/mm/yyyy' : '' );
@@ -819,10 +834,12 @@
819 834 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
820 835 $field['style'] = isset( $field['style'] ) ? $field['style'] : '';
821 836
822 837 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
838 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
823 839 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
824 840 {
841 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
825 842 $field['value'] = sanitize_text_field( wp_unslash( $_GET[$key] ) );
826 843 }
827 844 else
828 845 {
@@ -865,9 +882,9 @@
865 882 }
866 883 case "textarea":
867 884 {
868 885 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
869 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
886 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
870 887 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
871 888 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
872 889 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
873 890 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
@@ -873,10 +890,12 @@
873 890 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
874 891 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
875 892
876 893 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
894 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
877 895 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
878 896 {
897 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
879 898 $field['value'] = sanitize_textarea_field( wp_unslash( $_GET[$key] ) );
880 899 }
881 900 else
882 901 {
@@ -907,9 +926,9 @@
907 926 id="' . esc_attr( $key ) . '"
908 927 placeholder="' . esc_attr( $field['placeholder'] ) . '"
909 928 class="' . esc_attr( $field['class'] ) . '"
910 929 ' . ( ($field['required']) ? 'required' : '' ) . '
911 - >' . esc_attr( $field['value'] ) . '</textarea>';
930 + >' . esc_textarea( $field['value'] ) . '</textarea>';
912 931
913 932 $output .= $field['after'];
914 933
915 934 break;
@@ -916,9 +935,9 @@
916 935 }
917 936 case "checkbox":
918 937 {
919 938 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
920 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
939 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
921 940 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
922 941 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
923 942 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
924 943 $field['label_style'] = isset( $field['label_style'] ) ? $field['label_style'] : '';
@@ -923,8 +942,9 @@
923 942 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
924 943 $field['label_style'] = isset( $field['label_style'] ) ? $field['label_style'] : '';
925 944 $field['value'] = isset( $field['value'] ) ? $field['value'] : 'yes';
926 945 $field['checked'] = isset( $field['checked'] ) ? $field['checked'] : false;
946 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
927 947 if ( isset( $_GET[$key] ) && sanitize_text_field(wp_unslash($_GET[$key])) == $field['value'] )
928 948 {
929 949 $field['checked'] = true;
930 950 }
@@ -961,9 +981,9 @@
961 981 }
962 982 case "radio":
963 983 {
964 984 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
965 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
985 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
966 986 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
967 987 $field['before_option'] = isset( $field['before_option'] ) ? $field['before_option'] : '<label>';
968 988 $field['after_option'] = isset( $field['after_option'] ) ? $field['after_option'] : '</label>';
969 989 $field['before_input'] = isset( $field['before_input'] ) ? $field['before_input'] : '';
@@ -972,10 +992,12 @@
972 992 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
973 993 $field['options'] = ( isset( $field['options'] ) && is_array( $field['options'] ) ) ? $field['options'] : array();
974 994
975 995 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
996 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
976 997 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
977 998 {
999 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
978 1000 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
979 1001 }
980 1002
981 1003 $output .= $field['before'];
@@ -1015,9 +1037,9 @@
1015 1037 }
1016 1038 case "select":
1017 1039 {
1018 1040 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1019 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1041 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1020 1042 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1021 1043 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1022 1044 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1023 1045 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
@@ -1029,10 +1051,12 @@
1029 1051 wp_enqueue_script( 'multiselect' );
1030 1052 }
1031 1053
1032 1054 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1055 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1033 1056 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1034 1057 {
1058 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1035 1059 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1036 1060 }
1037 1061 else
1038 1062 {
@@ -1092,10 +1116,12 @@
1092 1116 }
1093 1117 else
1094 1118 {
1095 1119 if (
1120 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1096 1121 ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($option_key, $_REQUEST[$key]) )
1097 1122 ||
1123 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1098 1124 ( !isset($_REQUEST[$key]) && is_array($field['value']) && in_array($option_key, $field['value']) )
1099 1125 )
1100 1126 {
1101 1127 $output .= ' selected';
@@ -1100,9 +1126,9 @@
1100 1126 {
1101 1127 $output .= ' selected';
1102 1128 }
1103 1129 }
1104 - $output .= '>' . esc_html( __( $value, 'propertyhive' ) ) . '</option>';
1130 + $output .= '>' . esc_html( $value ) . '</option>';
1105 1131 }
1106 1132
1107 1133 $output .= '</select>';
1108 1134
@@ -1114,13 +1140,13 @@
1114 1140 {
1115 1141 $key = 'officeID';
1116 1142
1117 1143 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1118 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1144 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1119 1145 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1120 1146 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1121 1147 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1122 - $field['blank_option'] = isset( $field['blank_option'] ) ? __( $field['blank_option'], 'propertyhive' ) : __( 'No preference', 'propertyhive' );
1148 + $field['blank_option'] = isset( $field['blank_option'] ) ? $field['blank_option'] : __( 'No preference', 'propertyhive' );
1123 1149 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
1124 1150
1125 1151 if ( $field['multiselect'] )
1126 1152 {
@@ -1127,10 +1153,12 @@
1127 1153 wp_enqueue_script( 'multiselect' );
1128 1154 }
1129 1155
1130 1156 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1157 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1131 1158 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1132 1159 {
1160 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1133 1161 $field['value'] = (int)$_GET[$key];
1134 1162 }
1135 1163
1136 1164 $output .= $field['before'];
@@ -1177,8 +1205,9 @@
1177 1205 $output .= selected( esc_attr( $field['value'] ), esc_attr( $post->ID ), false );
1178 1206 }
1179 1207 else
1180 1208 {
1209 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1181 1210 if ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($post->ID, $_REQUEST[$key]) )
1182 1211 {
1183 1212 $output .= ' selected';
1184 1213 }
@@ -1197,16 +1226,18 @@
1197 1226 }
1198 1227 case "country":
1199 1228 {
1200 1229 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1201 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1230 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1202 1231 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1203 1232 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1204 1233 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1205 1234
1206 1235 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1236 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1207 1237 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1208 1238 {
1239 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1209 1240 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1210 1241 }
1211 1242
1212 1243 $output .= $field['before'];
@@ -1256,12 +1287,12 @@
1256 1287 {
1257 1288 wp_enqueue_script('jquery');
1258 1289 wp_enqueue_script('jquery-ui-core');
1259 1290 wp_enqueue_script('jquery-ui-slider');
1260 - wp_enqueue_script('jquery-ui-touch-punch', PH()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery.ui.touch-punch.min.js', array('jquery'), '0.2.3', true);
1291 + wp_enqueue_script( 'jquery-touch-punch' );
1261 1292 wp_enqueue_style( 'jquery-ui-style', PH()->plugin_url() . '/assets/css/jquery-ui/jquery-ui.css', array(), PH_VERSION );
1262 1293
1263 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1294 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1264 1295 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1265 1296 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1266 1297 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1267 1298 $field['min'] = isset( $field['min'] ) ? $field['min'] : '';
@@ -1272,17 +1303,22 @@
1272 1303
1273 1304 if ($field['show_label'])
1274 1305 {
1275 1306 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'];
1276 - $output .= ' - <span id="search-form-slider-value-' . $key . '" class="search-form-slider-value search-form-slider-value-' . $key . '"></span>';
1307 + $output .= ' - <span id="search-form-slider-value-' . esc_attr( $key ) . '" class="search-form-slider-value search-form-slider-value-' . esc_attr( $key ) . '"></span>';
1277 1308 $output .= '</label>';
1278 1309 }
1279 1310
1280 - $output .= '<div id="search-form-slider-' . $key . '" class="search-form-slider search-form-slider-' . $key . '" style="min-width:150px;"></div>';
1311 + $output .= '<div id="search-form-slider-' . esc_attr( $key ) . '" class="search-form-slider search-form-slider-' . esc_attr( $key ) . '" style="min-width:150px;"></div>';
1281 1312
1282 1313 $field_name = str_replace("_slider", "", $key);
1283 - $output .= '<input type="hidden" name="minimum_' . $field_name . '" class="min_slider_value-' . $key . '" id="min_slider_value-' . $key . '" value="' . ( isset($_GET['minimum_' . $field_name]) ? ph_clean($_GET['minimum_' . $field_name]) : '' ) . '">';
1284 - $output .= '<input type="hidden" name="maximum_' . $field_name . '" class="max_slider_value-' . $key . '" id="max_slider_value-' . $key . '" value="' . ( isset($_GET['maximum_' . $field_name]) ? ph_clean($_GET['maximum_' . $field_name]) : '' ) . '">';
1314 + // Read-only search preferences do not require a nonce.
1315 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1316 + $minimum = isset( $_GET['minimum_' . $field_name] ) && is_string( $_GET['minimum_' . $field_name] ) ? sanitize_text_field( wp_unslash( $_GET['minimum_' . $field_name] ) ) : '';
1317 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1318 + $maximum = isset( $_GET['maximum_' . $field_name] ) && is_string( $_GET['maximum_' . $field_name] ) ? sanitize_text_field( wp_unslash( $_GET['maximum_' . $field_name] ) ) : '';
1319 + $output .= '<input type="hidden" name="minimum_' . esc_attr( $field_name ) . '" class="min_slider_value-' . esc_attr( $key ) . '" id="min_slider_value-' . esc_attr( $key ) . '" value="' . esc_attr( $minimum ) . '">';
1320 + $output .= '<input type="hidden" name="maximum_' . esc_attr( $field_name ) . '" class="max_slider_value-' . esc_attr( $key ) . '" id="max_slider_value-' . esc_attr( $key ) . '" value="' . esc_attr( $maximum ) . '">';
1285 1321
1286 1322 $output .= $field['after'];
1287 1323
1288 1324 $value = '';
@@ -1288,9 +1324,14 @@
1288 1324 $value = '';
1289 1325 $prefix = '';
1290 1326 $suffix = '';
1291 1327
1292 - if ( $key == 'price_slider' || $key == 'rent_slider' )
1328 + $slider_keys = apply_filters('propertyhive_search_form_currency_slider_keys', [
1329 + 'price_slider',
1330 + 'rent_slider',
1331 + ]);
1332 +
1333 + if ( in_array($key, $slider_keys, true) )
1293 1334 {
1294 1335 $prefix = '£';
1295 1336
1296 1337 $search_form_currency = get_option( 'propertyhive_search_form_currency', 'GBP' );
@@ -1316,35 +1357,53 @@
1316 1357 }
1317 1358 }
1318 1359 }
1319 1360
1361 + $js_key = wp_json_encode( sanitize_html_class( $key ) );
1362 + $js_prefix = wp_json_encode( html_entity_decode( $prefix, ENT_QUOTES, 'UTF-8' ) );
1363 + $js_suffix = wp_json_encode( html_entity_decode( $suffix, ENT_QUOTES, 'UTF-8' ) );
1364 +
1320 1365 if ( $field['min'] != '' && $field['max'] != '' )
1321 1366 {
1322 - $value = 'values: [ ' . ( isset($_GET['minimum_' . $field_name]) && $_GET['minimum_' . $field_name] != '' ? ph_clean($_GET['minimum_' . $field_name]) : $field['min'] ) . ', ' . ( isset($_GET['maximum_' . $field_name]) && $_GET['maximum_' . $field_name] != '' ? ph_clean($_GET['maximum_' . $field_name]) : $field['max'] ) . ' ],';
1367 + $value = 'values: [ ' . ( $minimum !== '' ? (float) $minimum : (float)$field['min'] ) . ', ' . ( $maximum !== '' ? (float) $maximum : (float)$field['max'] ) . ' ],';
1323 1368 }
1324 1369
1325 1370 $output .= '<script>
1326 1371 jQuery(document).ready(function()
1327 1372 {
1328 - jQuery( ".search-form-slider-' . $key . '" ).each(function(index)
1373 + var key = ' . $js_key . ';
1374 + var prefix = ' . $js_prefix . ';
1375 + var suffix = ' . $js_suffix . ';
1376 +
1377 + jQuery(".search-form-slider-" + key).each(function(index)
1329 1378 {
1330 - jQuery(this).slider({
1379 + var $slider = jQuery(this);
1380 +
1381 + $slider.slider({
1331 1382 range: ' . ( ( $field['min'] != '' && $field['max'] != '' ) ? 'true' : 'false' ) . ',
1332 - step: ' . $field['step'] . ',
1333 - ' . ( $field['min'] != '' ? 'min: ' . $field['min'] . ',' : '' ) . '
1334 - ' . ( $field['max'] != '' ? 'max: ' . $field['max'] . ',' : '' ) . '
1383 + step: ' . (float) $field['step'] . ',
1384 + ' . ( $field['min'] != '' ? 'min: ' . (float) $field['min'] . ',' : '' ) . '
1385 + ' . ( $field['max'] != '' ? 'max: ' . (float) $field['max'] . ',' : '' ) . '
1335 1386 ' . $value . '
1336 1387 slide: function( event, ui ) {
1337 - //jQuery( "#search-form-slider-value-' . $key . '" ).html( "' . $prefix . '" + ui.values[ 0 ].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" + " - ' . $prefix . '" + ui.values[ 1 ].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" );
1338 - //jQuery( "#min_slider_value-' . $key . '" ).val( ui.values[0] );
1339 - //jQuery( "#max_slider_value-' . $key . '" ).val( ui.values[1] );
1388 + var min = ui.values[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
1389 + var max = ui.values[1].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
1340 1390
1341 - jQuery(this).closest("form").find(".search-form-slider-value-' . $key . '").html( "' . $prefix . '" + ui.values[ 0 ].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" + " - ' . $prefix . '" + ui.values[ 1 ].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" );
1342 - jQuery(this).closest("form").find(".min_slider_value-' . $key . '").val( ui.values[0] );
1343 - jQuery(this).closest("form").find(".max_slider_value-' . $key . '").val( ui.values[1] );
1391 + $slider.closest("form").find(".search-form-slider-value-" + key).text(
1392 + prefix + min + suffix + " - " + prefix + max + suffix
1393 + );
1394 +
1395 + $slider.closest("form").find(".min_slider_value-" + key).val(ui.values[0]);
1396 + $slider.closest("form").find(".max_slider_value-" + key).val(ui.values[1]);
1344 1397 }
1345 1398 });
1346 - jQuery(this).closest("form").find(".search-form-slider-value-' . $key . '").html( "' . $prefix . '" + jQuery( "#search-form-slider-' . $key . '" ).slider( "values", 0 ).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" + " - ' . $prefix . '" + jQuery( "#search-form-slider-' . $key . '" ).slider( "values", 1 ).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,") + "' . $suffix . '" );
1399 +
1400 + var initialMin = $slider.slider("values", 0).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
1401 + var initialMax = $slider.slider("values", 1).toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, "$1,");
1402 +
1403 + $slider.closest("form").find(".search-form-slider-value-" + key).text(
1404 + prefix + initialMin + suffix + " - " + prefix + initialMax + suffix
1405 + );
1347 1406 });
1348 1407 });
1349 1408 </script>';
1350 1409
@@ -1353,10 +1412,12 @@
1353 1412 case "hidden":
1354 1413 {
1355 1414 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1356 1415 $field['name'] = isset( $field['name'] ) ? $field['name'] : $key;
1416 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1357 1417 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1358 1418 {
1419 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1359 1420 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1360 1421 }
1361 1422
1362 1423 $output .= '<input type="hidden" name="' . esc_attr( $field['name'] ) . '" value="' . esc_attr($field['value']) . '">';
@@ -1364,9 +1425,9 @@
1364 1425 }
1365 1426 case "html":
1366 1427 {
1367 1428 $field['html'] = isset( $field['html'] ) ? $field['html'] : '';
1368 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1429 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1369 1430 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1370 1431
1371 1432 $output .= $field['before'];
1372 1433 $output .= $field['html'];
@@ -1375,57 +1436,46 @@
1375 1436 break;
1376 1437 }
1377 1438 case "recaptcha":
1378 1439 {
1379 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1380 -
1381 - $output .= '<script src="https://www.google.com/recaptcha/api.js"></script>
1382 - <div class="g-recaptcha" data-sitekey="' . esc_attr($field['site_key']) . '"></div>';
1440 + $site_key = isset( $field['site_key'] ) && is_string( $field['site_key'] ) ? $field['site_key'] : '';
1441 + // phpcs:ignore PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent, WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Provider maintains this API endpoint without a plugin version. Required by the configured Google reCAPTCHA service.
1442 + wp_enqueue_script( 'propertyhive-recaptcha', 'https://www.google.com/recaptcha/api.js', array(), null, true );
1443 + $output .= '<div class="g-recaptcha" data-sitekey="' . esc_attr( $site_key ) . '"></div>';
1383 1444 break;
1384 1445 }
1385 1446 case "recaptcha-v3":
1386 1447 {
1387 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1388 -
1389 - $output .= '
1390 - <script src="https://www.google.com/recaptcha/api.js?render=' . $field['site_key'] . '"></script>
1391 - <script>
1392 - grecaptcha.ready(function() {
1393 - grecaptcha.execute("' . $field['site_key'] . '", {action:\'submit\'})
1394 - .then(function(token) {
1395 - // add token value to form
1396 - document.querySelectorAll("#g-recaptcha-response").forEach(
1397 - elem => (elem.value = token)
1398 - );
1399 - });
1400 - });
1401 - </script>
1402 - <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
1403 - ';
1448 + $site_key = isset( $field['site_key'] ) && is_string( $field['site_key'] ) ? $field['site_key'] : '';
1449 + // phpcs:ignore PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent, WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Provider maintains this API endpoint without a plugin version. Required by the configured Google reCAPTCHA service.
1450 + wp_enqueue_script( 'propertyhive-recaptcha-v3', add_query_arg( 'render', $site_key, 'https://www.google.com/recaptcha/api.js' ), array(), null, true );
1451 + wp_add_inline_script( 'propertyhive-recaptcha-v3',
1452 + 'grecaptcha.ready(function() { grecaptcha.execute(' . wp_json_encode( $site_key, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ) . ', {action:"submit"}).then(function(token) { document.querySelectorAll("[name=g-recaptcha-response]").forEach(function(elem) { elem.value = token; }); }); });'
1453 + );
1454 + $output .= '<input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">';
1404 1455 break;
1405 1456 }
1406 1457 case "hCaptcha":
1407 1458 {
1408 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1409 -
1410 - $output .= '<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
1411 - <div class="h-captcha" data-sitekey="' . $field['site_key'] . '"></div>';
1459 + $site_key = isset( $field['site_key'] ) && is_string( $field['site_key'] ) ? $field['site_key'] : '';
1460 + // phpcs:ignore PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent, WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Provider maintains this API endpoint without a plugin version. Required by the configured hCaptcha service.
1461 + wp_enqueue_script( 'propertyhive-hcaptcha', 'https://js.hcaptcha.com/1/api.js', array(), null, true );
1462 + $output .= '<div class="h-captcha" data-sitekey="' . esc_attr( $site_key ) . '"></div>';
1412 1463 break;
1413 1464 }
1414 1465 case "turnstile":
1415 1466 {
1416 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1417 -
1418 - $output .= '<div class="turnstile" data-sitekey="' . $field['site_key'] . '"></div>';
1467 + $site_key = isset( $field['site_key'] ) && is_string( $field['site_key'] ) ? $field['site_key'] : '';
1468 + $output .= '<div class="turnstile" data-sitekey="' . esc_attr( $site_key ) . '"></div>';
1419 1469 break;
1420 1470 }
1421 1471 case "daterange":
1422 1472 {
1423 - wp_enqueue_script( 'moment.js', '//cdn.jsdelivr.net/momentjs/latest/moment.min.js' );
1424 - wp_enqueue_script( 'daterangepicker.js', '//cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js' );
1425 - wp_enqueue_style( 'daterangepicker.css', '//cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css' );
1473 + wp_enqueue_script( 'moment' );
1474 + wp_enqueue_script( 'daterangepicker.js', PH()->plugin_url() . '/assets/js/daterangepicker/daterangepicker.js', array( 'jquery', 'moment' ), '3.1.0', true );
1475 + wp_enqueue_style( 'daterangepicker.css', PH()->plugin_url() . '/assets/js/daterangepicker/daterangepicker.css', array(), '3.1.0' );
1426 1476
1427 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1477 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1428 1478 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1429 1479
1430 1480 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1431 1481 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
@@ -1434,10 +1484,12 @@
1434 1484 $field['style'] = isset( $field['style'] ) ? $field['style'] : '';
1435 1485 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1436 1486 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
1437 1487
1488 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1438 1489 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1439 1490 {
1491 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1440 1492 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1441 1493 }
1442 1494
1443 1495 $output .= $field['before'];
@@ -1463,13 +1515,13 @@
1463 1515 {
1464 1516 if ( taxonomy_exists($field['type']) )
1465 1517 {
1466 1518 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1467 - $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . $key . '">';
1519 + $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1468 1520 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1469 1521 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1470 1522 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1471 - $field['blank_option'] = isset( $field['blank_option'] ) ? __( $field['blank_option'], 'propertyhive' ) : __( 'No preference', 'propertyhive' );
1523 + $field['blank_option'] = isset( $field['blank_option'] ) ? $field['blank_option'] : __( 'No preference', 'propertyhive' );
1472 1524 $field['parent_terms_only'] = isset( $field['parent_terms_only'] ) ? $field['parent_terms_only'] : false;
1473 1525 $field['hide_empty'] = isset( $field['hide_empty'] ) ? $field['hide_empty'] : false;
1474 1526 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
1475 1527 $field['dynamic_population'] = ( isset( $field['dynamic_population'] ) && $field['type'] == 'location' && $field['parent_terms_only'] === false && $field['multiselect'] === false ) ? $field['dynamic_population'] : false; // only applies to location
@@ -1489,9 +1541,9 @@
1489 1541 'hide_empty' => $field['hide_empty'],
1490 1542 'parent' => 0
1491 1543 );
1492 1544 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1493 - $terms = get_terms( $field['type'], $args );
1545 + $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1494 1546
1495 1547 $levels_of_taxonomy = 1;
1496 1548 if ( !empty( $terms ) && !is_wp_error( $terms ) )
1497 1549 {
@@ -1500,8 +1552,12 @@
1500 1552 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1501 1553 {
1502 1554 $empty_check_args = array(
1503 1555 'post_type' => 'property',
1556 + 'posts_per_page' => 1,
1557 + 'fields' => 'ids',
1558 + 'no_found_rows' => true,
1559 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1504 1560 'meta_query' => array(
1505 1561 array(
1506 1562 'key' => '_on_market',
1507 1563 'value' => 'yes',
@@ -1506,8 +1562,9 @@
1506 1562 'key' => '_on_market',
1507 1563 'value' => 'yes',
1508 1564 ),
1509 1565 ),
1566 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1510 1567 'tax_query' => array(
1511 1568 array(
1512 1569 'taxonomy' => $field['type'],
1513 1570 'field' => 'term_id',
@@ -1526,9 +1583,9 @@
1526 1583 }
1527 1584 }
1528 1585
1529 1586 $options[(int)$term->term_id] = array(
1530 - 'label' => __( $term->name, 'propertyhive' ),
1587 + 'label' => $term->name,
1531 1588 'parent' => 0
1532 1589 );
1533 1590
1534 1591 if ($field['dynamic_population'])
@@ -1548,9 +1605,9 @@
1548 1605 'parent' => $term->term_id,
1549 1606 );
1550 1607 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1551 1608 $args = apply_filters( 'propertyhive_form_taxonomy_subterms_args', $args, $field );
1552 - $subterms = get_terms( $field['type'], $args );
1609 + $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1553 1610
1554 1611 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
1555 1612 {
1556 1613 foreach ($subterms as $subterm)
@@ -1558,8 +1615,12 @@
1558 1615 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1559 1616 {
1560 1617 $empty_check_args = array(
1561 1618 'post_type' => 'property',
1619 + 'posts_per_page' => 1,
1620 + 'fields' => 'ids',
1621 + 'no_found_rows' => true,
1622 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1562 1623 'meta_query' => array(
1563 1624 array(
1564 1625 'key' => '_on_market',
1565 1626 'value' => 'yes',
@@ -1564,8 +1625,9 @@
1564 1625 'key' => '_on_market',
1565 1626 'value' => 'yes',
1566 1627 ),
1567 1628 ),
1629 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1568 1630 'tax_query' => array(
1569 1631 array(
1570 1632 'taxonomy' => $field['type'],
1571 1633 'field' => 'term_id',
@@ -1584,9 +1646,9 @@
1584 1646 }
1585 1647 }
1586 1648
1587 1649 $options[(int)$subterm->term_id] = array(
1588 - 'label' => ( !$field['dynamic_population'] ? '- ' : '' ) . __( $subterm->name, 'propertyhive' ),
1650 + 'label' => ( !$field['dynamic_population'] ? '- ' : '' ) . $subterm->name,
1589 1651 'parent' => (int)$term->term_id,
1590 1652 );
1591 1653
1592 1654 if ($field['dynamic_population'])
@@ -1597,9 +1659,9 @@
1597 1659 'parent' => (int)$subterm->term_id
1598 1660 );
1599 1661 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1600 1662 $args = apply_filters( 'propertyhive_form_taxonomy_subsubterms_args', $args, $field );
1601 - $subsubterms = get_terms( $field['type'], $args );
1663 + $subsubterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1602 1664
1603 1665 if ( !empty( $subsubterms ) && !is_wp_error( $subsubterms ) )
1604 1666 {
1605 1667 foreach ($subsubterms as $subsubterm)
@@ -1607,8 +1669,12 @@
1607 1669 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1608 1670 {
1609 1671 $empty_check_args = array(
1610 1672 'post_type' => 'property',
1673 + 'posts_per_page' => 1,
1674 + 'fields' => 'ids',
1675 + 'no_found_rows' => true,
1676 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1611 1677 'meta_query' => array(
1612 1678 array(
1613 1679 'key' => '_on_market',
1614 1680 'value' => 'yes',
@@ -1613,8 +1679,9 @@
1613 1679 'key' => '_on_market',
1614 1680 'value' => 'yes',
1615 1681 ),
1616 1682 ),
1683 + // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- Existence-only published-property check for one taxonomy term and on-market meta; fetches one ID without row counts, with existing extension query filter retained.
1617 1684 'tax_query' => array(
1618 1685 array(
1619 1686 'taxonomy' => $field['type'],
1620 1687 'field' => 'term_id',
@@ -1633,9 +1700,9 @@
1633 1700 }
1634 1701 }
1635 1702
1636 1703 $options[(int)$subsubterm->term_id] = array(
1637 - 'label' => ( !$field['dynamic_population'] ? '- - ' : '' ) . __( $subsubterm->name, 'propertyhive' ),
1704 + 'label' => ( !$field['dynamic_population'] ? '- - ' : '' ) . $subsubterm->name,
1638 1705 'parent' => (int)$subterm->term_id,
1639 1706 );
1640 1707
1641 1708 if ($field['dynamic_population'])
@@ -1652,10 +1719,12 @@
1652 1719 {
1653 1720 wp_localize_script( 'propertyhive_dynamic_population', 'propertyhive_dynamic_population_params', array(
1654 1721 'options' => $options,
1655 1722 'levels_of_taxonomy' => $levels_of_taxonomy,
1656 - 'value' => isset($_GET[$field['type']]) ? ph_clean($_GET[$field['type']]) : '',
1657 - 'other_values' => ( isset($_GET['other_' . $field['type']]) && is_array($_GET['other_' . $field['type']]) && !empty($_GET['other_' . $field['type']]) ) ? ph_clean(array_filter($_GET['other_' . $field['type']])) : array(),
1723 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1724 + 'value' => isset($_GET[$field['type']]) ? ph_clean( wp_unslash( $_GET[$field['type']] ) ) : '',
1725 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1726 + 'other_values' => ( isset($_GET['other_' . $field['type']]) && is_array($_GET['other_' . $field['type']]) && !empty($_GET['other_' . $field['type']]) ) ? array_filter( array_filter( ph_clean( wp_unslash( $_GET['other_' . $field['type']] ) ) ), 'is_scalar' ) : array(),
1658 1727 'taxonomy' => $field['type'],
1659 1728 ) );
1660 1729 wp_enqueue_script( 'propertyhive_dynamic_population' );
1661 1730 }
@@ -1660,10 +1729,12 @@
1660 1729 wp_enqueue_script( 'propertyhive_dynamic_population' );
1661 1730 }
1662 1731
1663 1732 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1733 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1664 1734 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1665 1735 {
1736 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1666 1737 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1667 1738 }
1668 1739
1669 1740 for ( $level_i = 1; $level_i <= $levels_of_taxonomy; ++$level_i )
@@ -1707,8 +1778,9 @@
1707 1778 $output .= selected( esc_attr( $field['value'] ), esc_attr( $option_key ), false );
1708 1779 }
1709 1780 else
1710 1781 {
1782 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1711 1783 if ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($option_key, $_REQUEST[$key]) )
1712 1784 {
1713 1785 $output .= ' selected';
1714 1786 }
@@ -1733,12 +1805,13 @@
1733 1805 if ( !empty($availability_departments) )
1734 1806 {
1735 1807 ?>
1736 1808 <script>
1737 -var selected_availability = '<?php echo ( isset($_REQUEST[$key]) && $_REQUEST[$key] != '' ? (int)$_REQUEST[$key] : '' ); ?>';
1738 -var availability_departments = <?php echo json_encode($availability_departments); ?>;
1739 -var availabilities = <?php echo json_encode($options); ?>;
1740 -var availabilities_order = <?php echo json_encode(array_keys($options)); ?>;
1809 +<?php // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only initial availability selection, reduced to an integer before JavaScript output. ?>
1810 +var selected_availability = '<?php echo ( isset($_REQUEST[$key]) && is_scalar( $_REQUEST[$key] ) && $_REQUEST[$key] != '' ? (int)$_REQUEST[$key] : '' ); ?>';
1811 +var availability_departments = <?php echo wp_json_encode( $availability_departments , JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>;
1812 +var availabilities = <?php echo wp_json_encode( $options , JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>;
1813 +var availabilities_order = <?php echo wp_json_encode( array_keys($options) , JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT ); ?>;
1741 1814 </script>
1742 1815 <?php
1743 1816 }
1744 1817 }
@@ -1746,6 +1819,7 @@
1746 1819 }
1747 1820 }
1748 1821 }
1749 1822
1823 + // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Control values and attributes are escaped while assembling the markup above; labels/wrappers and the HTML control are trusted PHP presentation arguments (saved frontend labels are sanitized before extension filters).
1750 1824 echo $output;
1751 -}
1825 +}