PluginProbe
Property Hive / 2.3.0
Property Hive v2.3.0
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 1.4.62 All 260 releases
← All changes | includes/ph-form-functions.php +128 -72 2.2.62.3.0 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' );
@@ -1322,9 +1363,9 @@
1322 1363 $js_suffix = wp_json_encode( html_entity_decode( $suffix, ENT_QUOTES, 'UTF-8' ) );
1323 1364
1324 1365 if ( $field['min'] != '' && $field['max'] != '' )
1325 1366 {
1326 - $value = 'values: [ ' . ( isset($_GET['minimum_' . $field_name]) && $_GET['minimum_' . $field_name] != '' ? (float)wp_unslash($_GET['minimum_' . $field_name]) : (float)$field['min'] ) . ', ' . ( isset($_GET['maximum_' . $field_name]) && $_GET['maximum_' . $field_name] != '' ? (float)wp_unslash($_GET['maximum_' . $field_name]) : (float)$field['max'] ) . ' ],';
1367 + $value = 'values: [ ' . ( $minimum !== '' ? (float) $minimum : (float)$field['min'] ) . ', ' . ( $maximum !== '' ? (float) $maximum : (float)$field['max'] ) . ' ],';
1327 1368 }
1328 1369
1329 1370 $output .= '<script>
1330 1371 jQuery(document).ready(function()
@@ -1371,10 +1412,12 @@
1371 1412 case "hidden":
1372 1413 {
1373 1414 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1374 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.
1375 1417 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1376 1418 {
1419 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1377 1420 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1378 1421 }
1379 1422
1380 1423 $output .= '<input type="hidden" name="' . esc_attr( $field['name'] ) . '" value="' . esc_attr($field['value']) . '">';
@@ -1382,9 +1425,9 @@
1382 1425 }
1383 1426 case "html":
1384 1427 {
1385 1428 $field['html'] = isset( $field['html'] ) ? $field['html'] : '';
1386 - $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 ) . '">';
1387 1430 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1388 1431
1389 1432 $output .= $field['before'];
1390 1433 $output .= $field['html'];
@@ -1393,57 +1436,46 @@
1393 1436 break;
1394 1437 }
1395 1438 case "recaptcha":
1396 1439 {
1397 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1398 -
1399 - $output .= '<script src="https://www.google.com/recaptcha/api.js"></script>
1400 - <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>';
1401 1444 break;
1402 1445 }
1403 1446 case "recaptcha-v3":
1404 1447 {
1405 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1406 -
1407 - $output .= '
1408 - <script src="https://www.google.com/recaptcha/api.js?render=' . $field['site_key'] . '"></script>
1409 - <script>
1410 - grecaptcha.ready(function() {
1411 - grecaptcha.execute("' . $field['site_key'] . '", {action:\'submit\'})
1412 - .then(function(token) {
1413 - // add token value to form
1414 - document.querySelectorAll("#g-recaptcha-response").forEach(
1415 - elem => (elem.value = token)
1416 - );
1417 - });
1418 - });
1419 - </script>
1420 - <input type="hidden" id="g-recaptcha-response" name="g-recaptcha-response">
1421 - ';
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">';
1422 1455 break;
1423 1456 }
1424 1457 case "hCaptcha":
1425 1458 {
1426 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1427 -
1428 - $output .= '<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
1429 - <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>';
1430 1463 break;
1431 1464 }
1432 1465 case "turnstile":
1433 1466 {
1434 - $field['site_key'] = isset( $field['site_key'] ) ? $field['site_key'] : '';
1435 -
1436 - $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>';
1437 1469 break;
1438 1470 }
1439 1471 case "daterange":
1440 1472 {
1441 - wp_enqueue_script( 'moment.js', '//cdn.jsdelivr.net/momentjs/latest/moment.min.js' );
1442 - wp_enqueue_script( 'daterangepicker.js', '//cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js' );
1443 - 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' );
1444 1476
1445 - $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 ) . '">';
1446 1478 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1447 1479
1448 1480 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1449 1481 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
@@ -1452,10 +1484,12 @@
1452 1484 $field['style'] = isset( $field['style'] ) ? $field['style'] : '';
1453 1485 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1454 1486 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
1455 1487
1488 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1456 1489 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1457 1490 {
1491 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1458 1492 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1459 1493 }
1460 1494
1461 1495 $output .= $field['before'];
@@ -1481,13 +1515,13 @@
1481 1515 {
1482 1516 if ( taxonomy_exists($field['type']) )
1483 1517 {
1484 1518 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1485 - $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 ) . '">';
1486 1520 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1487 1521 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1488 1522 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1489 - $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' );
1490 1524 $field['parent_terms_only'] = isset( $field['parent_terms_only'] ) ? $field['parent_terms_only'] : false;
1491 1525 $field['hide_empty'] = isset( $field['hide_empty'] ) ? $field['hide_empty'] : false;
1492 1526 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
1493 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
@@ -1507,9 +1541,9 @@
1507 1541 'hide_empty' => $field['hide_empty'],
1508 1542 'parent' => 0
1509 1543 );
1510 1544 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1511 - $terms = get_terms( $field['type'], $args );
1545 + $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1512 1546
1513 1547 $levels_of_taxonomy = 1;
1514 1548 if ( !empty( $terms ) && !is_wp_error( $terms ) )
1515 1549 {
@@ -1518,8 +1552,12 @@
1518 1552 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1519 1553 {
1520 1554 $empty_check_args = array(
1521 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.
1522 1560 'meta_query' => array(
1523 1561 array(
1524 1562 'key' => '_on_market',
1525 1563 'value' => 'yes',
@@ -1524,8 +1562,9 @@
1524 1562 'key' => '_on_market',
1525 1563 'value' => 'yes',
1526 1564 ),
1527 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.
1528 1567 'tax_query' => array(
1529 1568 array(
1530 1569 'taxonomy' => $field['type'],
1531 1570 'field' => 'term_id',
@@ -1544,9 +1583,9 @@
1544 1583 }
1545 1584 }
1546 1585
1547 1586 $options[(int)$term->term_id] = array(
1548 - 'label' => __( $term->name, 'propertyhive' ),
1587 + 'label' => $term->name,
1549 1588 'parent' => 0
1550 1589 );
1551 1590
1552 1591 if ($field['dynamic_population'])
@@ -1566,9 +1605,9 @@
1566 1605 'parent' => $term->term_id,
1567 1606 );
1568 1607 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1569 1608 $args = apply_filters( 'propertyhive_form_taxonomy_subterms_args', $args, $field );
1570 - $subterms = get_terms( $field['type'], $args );
1609 + $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1571 1610
1572 1611 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
1573 1612 {
1574 1613 foreach ($subterms as $subterm)
@@ -1576,8 +1615,12 @@
1576 1615 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1577 1616 {
1578 1617 $empty_check_args = array(
1579 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.
1580 1623 'meta_query' => array(
1581 1624 array(
1582 1625 'key' => '_on_market',
1583 1626 'value' => 'yes',
@@ -1582,8 +1625,9 @@
1582 1625 'key' => '_on_market',
1583 1626 'value' => 'yes',
1584 1627 ),
1585 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.
1586 1630 'tax_query' => array(
1587 1631 array(
1588 1632 'taxonomy' => $field['type'],
1589 1633 'field' => 'term_id',
@@ -1602,9 +1646,9 @@
1602 1646 }
1603 1647 }
1604 1648
1605 1649 $options[(int)$subterm->term_id] = array(
1606 - 'label' => ( !$field['dynamic_population'] ? '- ' : '' ) . __( $subterm->name, 'propertyhive' ),
1650 + 'label' => ( !$field['dynamic_population'] ? '- ' : '' ) . $subterm->name,
1607 1651 'parent' => (int)$term->term_id,
1608 1652 );
1609 1653
1610 1654 if ($field['dynamic_population'])
@@ -1615,9 +1659,9 @@
1615 1659 'parent' => (int)$subterm->term_id
1616 1660 );
1617 1661 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1618 1662 $args = apply_filters( 'propertyhive_form_taxonomy_subsubterms_args', $args, $field );
1619 - $subsubterms = get_terms( $field['type'], $args );
1663 + $subsubterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1620 1664
1621 1665 if ( !empty( $subsubterms ) && !is_wp_error( $subsubterms ) )
1622 1666 {
1623 1667 foreach ($subsubterms as $subsubterm)
@@ -1625,8 +1669,12 @@
1625 1669 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1626 1670 {
1627 1671 $empty_check_args = array(
1628 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.
1629 1677 'meta_query' => array(
1630 1678 array(
1631 1679 'key' => '_on_market',
1632 1680 'value' => 'yes',
@@ -1631,8 +1679,9 @@
1631 1679 'key' => '_on_market',
1632 1680 'value' => 'yes',
1633 1681 ),
1634 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.
1635 1684 'tax_query' => array(
1636 1685 array(
1637 1686 'taxonomy' => $field['type'],
1638 1687 'field' => 'term_id',
@@ -1651,9 +1700,9 @@
1651 1700 }
1652 1701 }
1653 1702
1654 1703 $options[(int)$subsubterm->term_id] = array(
1655 - 'label' => ( !$field['dynamic_population'] ? '- - ' : '' ) . __( $subsubterm->name, 'propertyhive' ),
1704 + 'label' => ( !$field['dynamic_population'] ? '- - ' : '' ) . $subsubterm->name,
1656 1705 'parent' => (int)$subterm->term_id,
1657 1706 );
1658 1707
1659 1708 if ($field['dynamic_population'])
@@ -1670,10 +1719,12 @@
1670 1719 {
1671 1720 wp_localize_script( 'propertyhive_dynamic_population', 'propertyhive_dynamic_population_params', array(
1672 1721 'options' => $options,
1673 1722 'levels_of_taxonomy' => $levels_of_taxonomy,
1674 - 'value' => isset($_GET[$field['type']]) ? ph_clean($_GET[$field['type']]) : '',
1675 - '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(),
1676 1727 'taxonomy' => $field['type'],
1677 1728 ) );
1678 1729 wp_enqueue_script( 'propertyhive_dynamic_population' );
1679 1730 }
@@ -1678,10 +1729,12 @@
1678 1729 wp_enqueue_script( 'propertyhive_dynamic_population' );
1679 1730 }
1680 1731
1681 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.
1682 1734 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1683 1735 {
1736 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1684 1737 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1685 1738 }
1686 1739
1687 1740 for ( $level_i = 1; $level_i <= $levels_of_taxonomy; ++$level_i )
@@ -1725,8 +1778,9 @@
1725 1778 $output .= selected( esc_attr( $field['value'] ), esc_attr( $option_key ), false );
1726 1779 }
1727 1780 else
1728 1781 {
1782 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1729 1783 if ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($option_key, $_REQUEST[$key]) )
1730 1784 {
1731 1785 $output .= ' selected';
1732 1786 }
@@ -1751,12 +1805,13 @@
1751 1805 if ( !empty($availability_departments) )
1752 1806 {
1753 1807 ?>
1754 1808 <script>
1755 -var selected_availability = '<?php echo ( isset($_REQUEST[$key]) && $_REQUEST[$key] != '' ? (int)$_REQUEST[$key] : '' ); ?>';
1756 -var availability_departments = <?php echo json_encode($availability_departments); ?>;
1757 -var availabilities = <?php echo json_encode($options); ?>;
1758 -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 ); ?>;
1759 1814 </script>
1760 1815 <?php
1761 1816 }
1762 1817 }
@@ -1764,6 +1819,7 @@
1764 1819 }
1765 1820 }
1766 1821 }
1767 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).
1768 1824 echo $output;
1769 -}
1825 +}