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
propertyhive / includes / ph-form-functions.php

ph-form-functions.php in Property Hive 2.3.0, at includes/ph-form-functions.php

1,826 lines 81.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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
10 /**
11 * PropertyHive Form Functions
12 *
13 * Functions related to drawing forms on the frontend.
14 *
15 * @author PropertyHive
16 * @category Core
17 * @package PropertyHive/Functions
18 * @version 1.0.0
19 */
20
21 /**
22 * Main function for drawing entire property search form. We give the ability for an ID to be passed so differently formatted forms can be used
23 * (ie. a homepage search form might be different from a search form on search results)
24 *
25 * @param string $id
26 * @return void
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.
29 function ph_get_search_form( $id = 'default' ) {
30
31 $form_controls = ph_get_search_form_fields();
32
33 $form_controls = apply_filters( 'propertyhive_search_form_fields_' . $id, $form_controls );
34 $form_controls = apply_filters( 'propertyhive_search_form_fields', $form_controls );
35
36 // We 100% need department so make sure it exists. If it doesn't, set a hidden field
37 if ( !isset($form_controls['department']) )
38 {
39 $original_form_controls = ph_get_search_form_fields();
40 $original_department = $original_form_controls['department'];
41 $original_department['type'] = 'hidden';
42
43 $form_controls['department'] = $original_department;
44 }
45
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.
48 foreach ( $_REQUEST as $key => $value )
49 {
50 if ( isset($form_controls[$key]) )
51 continue;
52
53 if ( $key == 'officeID' && isset($form_controls['office']) )
54 continue;
55
56 if ( $key == 'paged' )
57 continue;
58
59 if (
60 ( $key == 'minimum_price' || $key == 'maximum_price' ) && array_key_exists('price_slider', $form_controls) ||
61 ( $key == 'minimum_rent' || $key == 'maximum_rent' ) && array_key_exists('rent_slider', $form_controls) ||
62 ( $key == 'minimum_bedrooms' || $key == 'maximum_bedrooms' ) && array_key_exists('bedrooms_slider', $form_controls)
63 )
64 continue;
65
66 // we've received a field that isn't a standard form control so let's store it in a hidden field so it's not lost
67 if ( is_array($value) )
68 {
69 foreach ( $value as $i => $val )
70 {
71 $form_controls[$key . '-' . $i] = array('type' => 'hidden', 'name' => $key . '[]', 'value' => stripslashes( ph_clean( $val) ));
72 }
73 }
74 else
75 {
76 $form_controls[$key] = array('type' => 'hidden', 'value' => stripslashes( ph_clean( $value) ));
77 }
78 }
79
80 $form_controls = apply_filters( 'propertyhive_search_form_fields_after_' . $id, $form_controls );
81 $form_controls = apply_filters( 'propertyhive_search_form_fields_after', $form_controls );
82
83 ph_get_template( 'global/search-form.php', array( 'form_controls' => $form_controls, 'id' => $id ) );
84
85 }
86
87 /**
88 * Get default fields to be shown on search forms
89 *
90 * @return array
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.
93 function ph_get_search_form_fields()
94 {
95 $fields = array();
96
97 $departments = ph_get_departments();
98
99 $department_options = array();
100 $default_value = '';
101
102 foreach ( $departments as $key => $value )
103 {
104 if ( get_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key) ) == 'yes' )
105 {
106 $department_options[$key] = $value;
107
108 if ($default_value == '' && get_option( 'propertyhive_primary_department' ) == $key )
109 {
110 $default_value = $key;
111 }
112 }
113 }
114
115 $sales_department_active = false;
116 if ( array_key_exists('residential-sales', $departments) )
117 {
118 $sales_department_active = true;
119 }
120 else
121 {
122 $custom_departments = ph_get_custom_departments();
123 if ( !empty($custom_departments) )
124 {
125 foreach ( $custom_departments as $key => $department )
126 {
127 if ( isset($department['based_on']) && $department['based_on'] == 'residential-sales' )
128 {
129 $sales_department_active = true;
130 }
131 }
132 }
133 }
134
135 $lettings_department_active = false;
136 if ( array_key_exists('residential-lettings', $departments) )
137 {
138 $lettings_department_active = true;
139 }
140 else
141 {
142 $custom_departments = ph_get_custom_departments();
143 if ( !empty($custom_departments) )
144 {
145 foreach ( $custom_departments as $key => $department )
146 {
147 if ( isset($department['based_on']) && $department['based_on'] == 'residential-lettings' )
148 {
149 $lettings_department_active = true;
150 }
151 }
152 }
153 }
154
155 $commercial_department_active = false;
156 if ( array_key_exists('commercial', $departments) )
157 {
158 $commercial_department_active = true;
159 }
160 else
161 {
162 $custom_departments = ph_get_custom_departments();
163 if ( !empty($custom_departments) )
164 {
165 foreach ( $custom_departments as $key => $department )
166 {
167 if ( isset($department['based_on']) && $department['based_on'] == 'commercial' )
168 {
169 $commercial_department_active = true;
170 }
171 }
172 }
173 }
174
175 $fields['department'] = array(
176 'type' => 'radio',
177 'options' => $department_options,
178 'value' => $default_value
179 );
180
181 if ( $sales_department_active || $lettings_department_active )
182 {
183 if ( $sales_department_active )
184 {
185 $prices = array(
186 '' => __( 'No preference', 'propertyhive' ),
187 '100000' => '&pound;100,000',
188 '150000' => '&pound;150,000',
189 '200000' => '&pound;200,000',
190 '250000' => '&pound;250,000',
191 '300000' => '&pound;300,000',
192 '500000' => '&pound;500,000',
193 '750000' => '&pound;750,000',
194 '1000000' => '&pound;1,000,000'
195 );
196
197 $fields['minimum_price'] = array(
198 'type' => 'select',
199 'show_label' => true,
200 'label' => __( 'Min Price', 'propertyhive' ),
201 'before' => '<div class="control control-minimum_price sales-only">',
202 'options' => $prices
203 );
204
205 $fields['maximum_price'] = array(
206 'type' => 'select',
207 'show_label' => true,
208 'label' => __( 'Max Price', 'propertyhive' ),
209 'before' => '<div class="control control-maximum_price sales-only">',
210 'options' => $prices
211 );
212 }
213
214 if ( $lettings_department_active )
215 {
216 $prices = array(
217 '' => __( 'No preference', 'propertyhive' ),
218 '500' => '&pound;500 PCM',
219 '600' => '&pound;600 PCM',
220 '750' => '&pound;750 PCM',
221 '1000' => '&pound;1000 PCM',
222 '1250' => '&pound;1250 PCM',
223 '1500' => '&pound;1500 PCM',
224 '2000' => '&pound;2000 PCM'
225 );
226
227 $fields['minimum_rent'] = array(
228 'type' => 'select',
229 'show_label' => true,
230 'label' => __( 'Min Rent', 'propertyhive' ),
231 'before' => '<div class="control control-minimum_rent lettings-only">',
232 'options' => $prices
233 );
234
235 $fields['maximum_rent'] = array(
236 'type' => 'select',
237 'show_label' => true,
238 'label' => __( 'Max Rent', 'propertyhive' ),
239 'before' => '<div class="control control-maximum_rent lettings-only">',
240 'options' => $prices
241 );
242 }
243
244 $fields['minimum_bedrooms'] = array(
245 'type' => 'select',
246 'show_label' => true,
247 'label' => __( 'Min Beds', 'propertyhive' ),
248 'before' => '<div class="control control-minimum_bedrooms residential-only">',
249 'options' => array( '' => __( 'No preference', 'propertyhive' ), 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5)
250 );
251
252 $fields['property_type'] = array(
253 'type' => 'property_type',
254 'show_label' => true,
255 'before' => '<div class="control control-property_type residential-only">',
256 'label' => __( 'Type', 'propertyhive' ),
257 );
258 }
259
260 if ( $commercial_department_active )
261 {
262 $sizes = array(
263 '' => __( 'No preference', 'propertyhive' ),
264 '250' => '250 sq ft',
265 '500' => '500 sq ft',
266 '1000' => '1,000 sq ft',
267 '2500' => '2,500 sq ft',
268 '5000' => '5,000 sq ft',
269 '10000' => '10,000 sq ft',
270 '25000' => '25,000 sq ft',
271 '50000' => '50,000 sq ft'
272 );
273
274 $fields['minimum_floor_area'] = array(
275 'type' => 'select',
276 'show_label' => true,
277 'label' => __( 'Min Floor Area', 'propertyhive' ),
278 'before' => '<div class="control control-minimum_floor_area commercial-only">',
279 'options' => $sizes
280 );
281
282 $fields['maximum_floor_area'] = array(
283 'type' => 'select',
284 'show_label' => true,
285 'label' => __( 'Max Floor Area', 'propertyhive' ),
286 'before' => '<div class="control control-maximum_floor_area commercial-only">',
287 'options' => $sizes
288 );
289
290 $fields['commercial_property_type'] = array(
291 'type' => 'commercial_property_type',
292 'show_label' => true,
293 'before' => '<div class="control control-commercial_property_type commercial-only">',
294 'label' => __( 'Type', 'propertyhive' ),
295 );
296 }
297
298 return $fields;
299 }
300
301 /**
302 * Main function for drawing property enquiry form.
303 *
304 * @param string $property_id
305 * @return void
306 */
307 function propertyhive_enquiry_form( $property_id = '' )
308 {
309 global $post;
310
311 $form_controls = ph_get_property_enquiry_form_fields( $property_id );
312
313 $form_controls = apply_filters( 'propertyhive_property_enquiry_form_fields', $form_controls, $property_id );
314
315 $form_controls['property_id'] = array(
316 'type' => 'hidden',
317 'value' => ( $property_id != '' ? $property_id : $post->ID )
318 );
319
320 $utm_fields = array( 'utm_source', 'utm_medium', 'utm_term', 'utm_content', 'utm_campaign', 'gclid', 'fbclid' );
321 foreach ( $utm_fields as $utm_field )
322 {
323 $form_controls[$utm_field] = array(
324 'type' => 'hidden',
325 'value' =>''
326 );
327 }
328
329 if ( get_option( 'propertyhive_property_enquiry_form_disclaimer', '' ) != '' )
330 {
331 $disclaimer = wp_kses_post( get_option( 'propertyhive_property_enquiry_form_disclaimer', '' ) );
332
333 $form_controls['disclaimer'] = array(
334 'type' => 'checkbox',
335 'label' => $disclaimer,
336 'label_style' => 'width:100%;',
337 'required' => true
338 );
339 }
340
341 ph_get_template( 'global/make-enquiry-form.php',array( 'form_controls' => $form_controls ) );
342 }
343
344 /**
345 * Get default fields to be shown on search forms
346 *
347 * @return array
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.
350 function ph_get_property_enquiry_form_fields( $property_id = '' )
351 {
352 global $post;
353
354 $fields = array();
355
356 $fields['name'] = array(
357 'type' => 'text',
358 'label' => __( 'Full Name', 'propertyhive' ),
359 'show_label' => true,
360 'before' => '<div class="control control-name">',
361 'required' => true
362 );
363 if ( is_user_logged_in() )
364 {
365 $current_user = wp_get_current_user();
366
367 $fields['name']['value'] = $current_user->display_name;
368 }
369
370 $fields['email_address'] = array(
371 'type' => 'email',
372 'label' => __( 'Email Address', 'propertyhive' ),
373 'show_label' => true,
374 'before' => '<div class="control control-email_address">',
375 'required' => true
376 );
377 if ( is_user_logged_in() )
378 {
379 $current_user = wp_get_current_user();
380
381 $fields['email_address']['value'] = $current_user->user_email;
382 }
383
384 $fields['telephone_number'] = array(
385 'type' => 'text',
386 'label' => __( 'Number', 'propertyhive' ),
387 'show_label' => true,
388 'before' => '<div class="control control-telephone_number">',
389 'required' => true
390 );
391
392 $fields['message'] = array(
393 'type' => 'textarea',
394 'label' => __( 'Message', 'propertyhive' ),
395 'show_label' => true,
396 'before' => '<div class="control control-message">',
397 'required' => true
398 );
399
400 return $fields;
401 }
402
403 /**
404 * Get default fields to be shown on applicant registration forms
405 *
406 * @return array
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.
409 function ph_get_user_details_form_fields()
410 {
411 global $post;
412
413 if ( is_user_logged_in() )
414 {
415 $current_user = wp_get_current_user();
416
417 if ( $current_user instanceof WP_User )
418 {
419 $contact = new PH_Contact( '', $current_user->ID );
420 }
421 }
422
423 $fields = array();
424
425 $fields['name'] = array(
426 'type' => 'text',
427 'label' => __( 'Full Name', 'propertyhive' ),
428 'required' => true
429 );
430 if ( is_user_logged_in() && $current_user instanceof WP_User )
431 {
432 $fields['name']['value'] = $current_user->display_name;
433 }
434
435 $fields['email_address'] = array(
436 'type' => 'email',
437 'label' => __( 'Email Address', 'propertyhive' ),
438 'required' => true
439 );
440 if ( is_user_logged_in() && $current_user instanceof WP_User )
441 {
442 $fields['email_address']['value'] = $current_user->user_email;
443 }
444
445 $fields['telephone_number'] = array(
446 'type' => 'text',
447 'label' => __( 'Telephone Number', 'propertyhive' ),
448 'required' => false
449 );
450 if ( is_user_logged_in() && $current_user instanceof WP_User )
451 {
452 $fields['telephone_number']['value'] = $contact->telephone_number;
453 }
454
455 if ( get_option( 'propertyhive_applicant_users', '' ) == 'yes' )
456 {
457 $fields['password'] = array(
458 'type' => 'password',
459 'label' => __( 'Password', 'propertyhive' ),
460 'required' => true
461 );
462
463 $fields['password2'] = array(
464 'type' => 'password',
465 'label' => __( 'Confirm Password', 'propertyhive' ),
466 'required' => true
467 );
468 }
469
470 return $fields;
471 }
472
473 /**
474 * Get default fields to be shown on applicant registration forms
475 *
476 * @return array
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.
479 function ph_get_applicant_requirements_form_fields($applicant_profile = false)
480 {
481 global $post;
482
483 $fields = array();
484
485 $offices = array();
486 $value = '';
487
488 $args = array(
489 'post_type' => 'office',
490 'nopaging' => true,
491 'orderby' => 'title',
492 'order' => 'ASC'
493 );
494
495 $office_query = new WP_Query( $args );
496
497 if ( $office_query->have_posts() )
498 {
499 while ( $office_query->have_posts() )
500 {
501 $office_query->the_post();
502
503 $offices[get_the_ID()] = get_the_title();
504
505 if ( get_post_meta(get_the_ID(), 'primary', TRUE) == 1 )
506 {
507 $value = get_the_ID();
508 }
509 }
510 }
511 wp_reset_postdata();
512
513 $fields['office_id'] = array(
514 'type' => ( (count($offices) <= 1) ? 'hidden' : 'select' ),
515 'label' => __( 'Office', 'propertyhive' ),
516 'required' => false,
517 'show_label' => true,
518 'value' => $value,
519 'options' => $offices
520 );
521
522 $value = '';
523
524 $ph_departments = ph_get_departments();
525 $departments = array();
526
527 $show_residential_fields = false;
528 $show_commercial_fields = false;
529 foreach ( $ph_departments as $key => $department )
530 {
531 if ( get_option( 'propertyhive_active_departments_' . str_replace("residential-", "", $key) ) == 'yes' )
532 {
533 $departments[$key] = $department;
534 if ($value == '' && (get_option( 'propertyhive_primary_department' ) == $key || get_option( 'propertyhive_primary_department' ) === FALSE) )
535 {
536 $value = $key;
537 }
538
539 if ( in_array($key, array('residential-sales', 'residential-lettings')) || in_array(ph_get_custom_department_based_on($key), array('residential-sales', 'residential-lettings')) )
540 {
541 $show_residential_fields = true;
542 }
543
544 if ( in_array($key, array('commercial')) || in_array(ph_get_custom_department_based_on($key), array('commercial')) )
545 {
546 $show_commercial_fields = true;
547 }
548 }
549 }
550
551 $fields['department'] = array(
552 'type' => 'radio',
553 'label' => __( 'Looking For', 'propertyhive' ),
554 'required' => true,
555 'show_label' => true,
556 'value' => $value,
557 'options' => $departments
558 );
559 if ( is_user_logged_in() && isset($applicant_profile['department']) )
560 {
561 $fields['department']['value'] = $applicant_profile['department'];
562 }
563 if ( count($departments) == 1 )
564 {
565 $fields['department']['type'] = 'hidden';
566 }
567
568 if ( $show_residential_fields )
569 {
570 $fields['maximum_price'] = array(
571 'type' => 'number',
572 'label' => __( 'Maximum Price', 'propertyhive' ),
573 'style' => 'max-width:150px;',
574 'before' => '<div class="control control-minimum_price sales-only">',
575 'required' => false
576 );
577 if ( is_user_logged_in() && isset($applicant_profile['max_price']) )
578 {
579 $fields['maximum_price']['value'] = $applicant_profile['max_price'];
580 }
581
582 $fields['maximum_rent'] = array(
583 'type' => 'number',
584 'label' => __( 'Maximum Rent', 'propertyhive' ) . ' (PCM)',
585 'style' => 'max-width:150px;',
586 'before' => '<div class="control control-minimum_price lettings-only">',
587 'required' => false
588 );
589 if ( is_user_logged_in() && isset($applicant_profile['max_rent']) )
590 {
591 $fields['maximum_rent']['value'] = $applicant_profile['max_rent'];
592 }
593
594 $fields['minimum_bedrooms'] = array(
595 'type' => 'number',
596 'label' => __( 'Minimum Bedrooms', 'propertyhive' ),
597 'style' => 'max-width:80px;',
598 'before' => '<div class="control control-minimum_bedrooms residential-only">',
599 'required' => false
600 );
601 if ( is_user_logged_in() && isset($applicant_profile['min_beds']) )
602 {
603 $fields['minimum_bedrooms']['value'] = $applicant_profile['min_beds'];
604 }
605
606 $args = array(
607 'hide_empty' => false,
608 'parent' => 0
609 );
610 $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'property_type' ) ) );
611
612 $options = array();
613
614 $selected_value = '';
615 if ( !empty( $terms ) && !is_wp_error( $terms ) )
616 {
617 $options = array( '' => __( 'All Property Types', 'propertyhive' ) );
618
619 foreach ($terms as $term)
620 {
621 $options[$term->term_id] = $term->name;
622
623 $args = array(
624 'hide_empty' => false,
625 'parent' => $term->term_id
626 );
627 $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'property_type' ) ) );
628
629 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
630 {
631 foreach ($subterms as $term)
632 {
633 $options[$term->term_id] = '- ' . $term->name;
634 }
635 }
636 }
637 }
638
639 if ( !empty($options) )
640 {
641 $fields['property_type'] = array(
642 'type' => 'select',
643 'label' => __( 'Property Type', 'propertyhive' ),
644 'before' => '<div class="control control-property_type residential-only">',
645 'required' => false,
646 'multiselect' => true,
647 'options' => $options,
648 );
649
650 if ( is_user_logged_in() && isset($applicant_profile['property_types']) && is_array($applicant_profile['property_types']) && !empty($applicant_profile['property_types']) )
651 {
652 $fields['property_type']['value'] = $applicant_profile['property_types'];
653 }
654 }
655 }
656
657 if ( $show_commercial_fields )
658 {
659 $fields['available_as_sale'] = array(
660 'type' => 'checkbox',
661 'label' => __( 'For Sale', 'propertyhive' ),
662 'before' => '<div class="control control-available_as_sale commercial-only">',
663 'required' => false,
664 );
665 if ( is_user_logged_in() && isset($applicant_profile['available_as']) && in_array('sale', $applicant_profile['available_as']) )
666 {
667 $fields['available_as_sale']['checked'] = true;
668 }
669
670 $fields['available_as_rent'] = array(
671 'type' => 'checkbox',
672 'label' => __( 'To Rent', 'propertyhive' ),
673 'before' => '<div class="control control-available_as_rent commercial-only">',
674 'required' => false,
675 );
676 if ( is_user_logged_in() && isset($applicant_profile['available_as']) && in_array('rent', $applicant_profile['available_as']) )
677 {
678 $fields['available_as_rent']['checked'] = true;
679 }
680
681 $fields['minimum_floor_area'] = array(
682 'type' => 'number',
683 'label' => __( 'Min Floor Area (Sq Ft)', 'propertyhive' ),
684 'style' => 'max-width:150px;',
685 'before' => '<div class="control control-minimum_floor_area commercial-only">',
686 'required' => false
687 );
688 if ( is_user_logged_in() && isset($applicant_profile['min_floor_area']) )
689 {
690 $fields['minimum_floor_area']['value'] = $applicant_profile['min_floor_area'];
691 }
692
693 $fields['maximum_floor_area'] = array(
694 'type' => 'number',
695 'label' => __( 'Max Floor Area (Sq Ft)', 'propertyhive' ),
696 'style' => 'max-width:150px;',
697 'before' => '<div class="control control-maximum_floor_area commercial-only">',
698 'required' => false
699 );
700 if ( is_user_logged_in() && isset($applicant_profile['max_floor_area']) )
701 {
702 $fields['maximum_floor_area']['value'] = $applicant_profile['max_floor_area'];
703 }
704
705 $args = array(
706 'hide_empty' => false,
707 'parent' => 0
708 );
709 $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'commercial_property_type' ) ) );
710
711 $options = array();
712
713 $selected_value = '';
714 if ( !empty( $terms ) && !is_wp_error( $terms ) )
715 {
716 $options = array( '' => __( 'All Property Types', 'propertyhive' ) );
717
718 foreach ($terms as $term)
719 {
720 $options[$term->term_id] = $term->name;
721
722 $args = array(
723 'hide_empty' => false,
724 'parent' => $term->term_id
725 );
726 $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'commercial_property_type' ) ) );
727
728 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
729 {
730 foreach ($subterms as $term)
731 {
732 $options[$term->term_id] = '- ' . $term->name;
733 }
734 }
735 }
736 }
737
738 if ( !empty($options) )
739 {
740 $fields['commercial_property_type'] = array(
741 'type' => 'select',
742 'label' => __( 'Property Type', 'propertyhive' ),
743 'before' => '<div class="control control-commercial_property_type commercial-only">',
744 'required' => false,
745 'multiselect' => true,
746 'options' => $options,
747 );
748
749 if ( is_user_logged_in() && isset($applicant_profile['commercial_property_types']) && is_array($applicant_profile['commercial_property_types']) && !empty($applicant_profile['commercial_property_types']) )
750 {
751 $fields['commercial_property_type']['value'] = $applicant_profile['commercial_property_types'];
752 }
753 }
754 }
755
756 if ( get_option('propertyhive_applicant_locations_type') != 'text' )
757 {
758 $args = array(
759 'hide_empty' => false,
760 'parent' => 0
761 );
762 $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'location' ) ) );
763
764 if ( !empty( $terms ) && !is_wp_error( $terms ) )
765 {
766 $fields['location'] = array(
767 'type' => 'location',
768 'label' => __( 'Location', 'propertyhive' ),
769 'blank_option' => __( 'All Locations', 'propertyhive' ),
770 'required' => false,
771 'multiselect' => true,
772 );
773
774 if ( is_user_logged_in() && isset($applicant_profile['locations']) && is_array($applicant_profile['locations']) && !empty($applicant_profile['locations']) )
775 {
776 $fields['location']['value'] = $applicant_profile['locations'];
777 }
778 }
779 }
780 else
781 {
782 $fields['location_text'] = array(
783 'type' => 'text',
784 'label' => __( 'Location', 'propertyhive' ),
785 'required' => false
786 );
787
788 if ( is_user_logged_in() && isset($applicant_profile['location_text']) && $applicant_profile['location_text'] != '' )
789 {
790 $fields['location_text']['value'] = $applicant_profile['location_text'];
791 }
792 }
793
794 $fields['additional_requirements'] = array(
795 'type' => 'textarea',
796 'label' => __( 'Additional Requirements', 'propertyhive' ),
797 'required' => false
798 );
799 if ( is_user_logged_in() && isset($applicant_profile['notes']) )
800 {
801 $fields['additional_requirements']['value'] = $applicant_profile['notes'];
802 }
803
804 return $fields;
805 }
806
807 /**
808 * Output individual field
809 *
810 * @return void
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.
813 function ph_form_field( $key, $field )
814 {
815 global $post;
816
817 $output = '';
818
819 switch ($field['type'])
820 {
821 case "text":
822 case "email":
823 case "date":
824 case "number":
825 case "password":
826 {
827 $field['id'] = isset( $field['id'] ) ? $field['id'] : $key;
828 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
829 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
830 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
831 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
832 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
833 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : ( ( $field['type'] == 'date' ) ? 'dd/mm/yyyy' : '' );
834 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
835 $field['style'] = isset( $field['style'] ) ? $field['style'] : '';
836
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.
839 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
840 {
841 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
842 $field['value'] = sanitize_text_field( wp_unslash( $_GET[$key] ) );
843 }
844 else
845 {
846 if ( !is_post_type_archive('property') && !is_singular('property') && isset($post->ID) )
847 {
848 $value = get_post_meta( $post->ID, '_' . $key, true );
849 if ( $value != '' )
850 {
851 $field['value'] = $value;
852 }
853 }
854 }
855
856 $output .= $field['before'];
857
858 if ($field['show_label'])
859 {
860 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'];
861 if ($field['required'])
862 {
863 $output .= '<span class="required"> *</span>';
864 }
865 $output .= '</label>';
866 }
867
868 $output .= '<input
869 type="' . esc_attr( $field['type'] ) . '"
870 name="' . esc_attr( $key ) . '"
871 id="' . esc_attr( $field['id'] ) . '"
872 value="' . esc_attr( $field['value'] ) . '"
873 placeholder="' . esc_attr( $field['placeholder'] ) . '"
874 class="' . esc_attr( $field['class'] ) . '"
875 style="' . esc_attr( $field['style'] ) . '"
876 ' . ( ($field['required']) ? 'required' : '' ) . '
877 >';
878
879 $output .= $field['after'];
880
881 break;
882 }
883 case "textarea":
884 {
885 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
886 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
887 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
888 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
889 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
890 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
891 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
892
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.
895 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
896 {
897 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
898 $field['value'] = sanitize_textarea_field( wp_unslash( $_GET[$key] ) );
899 }
900 else
901 {
902 if ( !is_post_type_archive('property') && !is_singular('property') && isset($post->ID) )
903 {
904 $value = get_post_meta( $post->ID, '_' . $key, true );
905 if ( $value != '' )
906 {
907 $field['value'] = $value;
908 }
909 }
910 }
911
912 $output .= $field['before'];
913
914 if ($field['show_label'])
915 {
916 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'];
917 if ($field['required'])
918 {
919 $output .= '<span class="required"> *</span>';
920 }
921 $output .= '</label>';
922 }
923
924 $output .= '<textarea
925 name="' . esc_attr( $key ) . '"
926 id="' . esc_attr( $key ) . '"
927 placeholder="' . esc_attr( $field['placeholder'] ) . '"
928 class="' . esc_attr( $field['class'] ) . '"
929 ' . ( ($field['required']) ? 'required' : '' ) . '
930 >' . esc_textarea( $field['value'] ) . '</textarea>';
931
932 $output .= $field['after'];
933
934 break;
935 }
936 case "checkbox":
937 {
938 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
939 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
940 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
941 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
942 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
943 $field['label_style'] = isset( $field['label_style'] ) ? $field['label_style'] : '';
944 $field['value'] = isset( $field['value'] ) ? $field['value'] : 'yes';
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.
947 if ( isset( $_GET[$key] ) && sanitize_text_field(wp_unslash($_GET[$key])) == $field['value'] )
948 {
949 $field['checked'] = true;
950 }
951 else
952 {
953 if ( !is_post_type_archive('property') && !is_singular('property') && isset($post->ID) )
954 {
955 $value = get_post_meta( $post->ID, '_' . $key, true );
956 if ( $value == 'yes' )
957 {
958 $field['checked'] = true;
959 }
960 }
961 }
962
963 $output .= $field['before'];
964
965 $output .= '<label style="' . esc_attr( $field['label_style'] ) . '"><input
966 type="' . esc_attr( $field['type'] ) . '"
967 name="' . esc_attr( $key ) . '"
968 value="' . esc_attr( $field['value'] ) . '"
969 class="' . esc_attr( $field['class'] ) . '"
970 ' . checked( $field['checked'], true, false ) . '
971 >';
972 if ($field['show_label'])
973 {
974 $output .= ' <span>' . $field['label'] . '</span>';
975 }
976 $output .= '</label>';
977
978 $output .= $field['after'];
979
980 break;
981 }
982 case "radio":
983 {
984 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
985 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
986 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
987 $field['before_option'] = isset( $field['before_option'] ) ? $field['before_option'] : '<label>';
988 $field['after_option'] = isset( $field['after_option'] ) ? $field['after_option'] : '</label>';
989 $field['before_input'] = isset( $field['before_input'] ) ? $field['before_input'] : '';
990 $field['after_input'] = isset( $field['after_input'] ) ? $field['after_input'] : '';
991 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : false;
992 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
993 $field['options'] = ( isset( $field['options'] ) && is_array( $field['options'] ) ) ? $field['options'] : array();
994
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.
997 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
998 {
999 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1000 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1001 }
1002
1003 $output .= $field['before'];
1004
1005 if ($field['show_label'])
1006 {
1007 // get first option as 'for'
1008 $option_key = '';
1009 foreach ( $field['options'] as $option_key => $value )
1010 {
1011 break;
1012 }
1013 $output .= '<label for="' . esc_attr( $key ) . '_' . esc_attr( $option_key ) . '">' . $field['label'] . '</label>';
1014 }
1015
1016 foreach ( $field['options'] as $option_key => $value )
1017 {
1018 $id = esc_attr( $key ) . '_' . esc_attr( $option_key );
1019 $output .= str_replace("{id}", $id, $field['before_option']);
1020 $output .= str_replace("{id}", $id, $field['before_input']);
1021 $output .= '<input
1022 type="' . esc_attr( $field['type'] ) . '"
1023 name="' . esc_attr( $key ) . '"
1024 id="' . $id . '"
1025 value="' . esc_attr( $option_key ) . '"
1026 class="' . esc_attr( $field['class'] ) . '"
1027 ' . checked( esc_attr( $field['value'] ), esc_attr( $option_key ), false ) . '
1028 >';
1029 $output .= str_replace("{id}", $id, $field['after_input']);
1030 $output .= ' ' . esc_html( $value );
1031 $output .= str_replace("{id}", $id, $field['after_option']);
1032 }
1033
1034 $output .= $field['after'];
1035
1036 break;
1037 }
1038 case "select":
1039 {
1040 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1041 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1042 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1043 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1044 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1045 $field['required'] = isset( $field['required'] ) ? $field['required'] : false;
1046 $field['options'] = ( isset( $field['options'] ) && is_array( $field['options'] ) ) ? $field['options'] : array();
1047 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
1048
1049 if ( $field['multiselect'] )
1050 {
1051 wp_enqueue_script( 'multiselect' );
1052 }
1053
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.
1056 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1057 {
1058 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1059 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1060 }
1061 else
1062 {
1063 if ( !is_post_type_archive('property') && !is_singular('property') && isset($post->ID) )
1064 {
1065 $value = get_post_meta( $post->ID, '_' . $key, true );
1066 if ( $value != '' )
1067 {
1068 $field['value'] = $value;
1069 }
1070 }
1071 }
1072
1073 $output .= $field['before'];
1074
1075 if ($field['show_label'])
1076 {
1077 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'];
1078 if ($field['required'])
1079 {
1080 $output .= '<span class="required"> *</span>';
1081 }
1082 $output .= '</label>';
1083 }
1084
1085 $blank_option = '';
1086 foreach ( $field['options'] as $option_key => $value )
1087 {
1088 if ( $field['multiselect'] && $option_key == '' )
1089 {
1090 $blank_option = $value;
1091 continue;
1092 }
1093 }
1094
1095 $output .= '<select
1096 name="' . esc_attr( $key ) . ( $field['multiselect'] ? '[]' : '' ) . '"
1097 id="' . esc_attr( $key ) . '"
1098 class="' . esc_attr( $field['class'] ) . ( $field['multiselect'] ? ' ph-form-multiselect' : '' ) . '"
1099 ' . ( $field['multiselect'] ? ' multiple="multiple"' : '' ) . '
1100 data-blank-option="' . esc_attr($blank_option) . '"
1101 >';
1102
1103 foreach ( $field['options'] as $option_key => $value )
1104 {
1105 if ( $field['multiselect'] && $option_key == '' )
1106 {
1107 // Skip because we don't want a blank option in the multiselect. Instead use $value as the placeholder
1108 continue;
1109 }
1110
1111 $output .= '<option
1112 value="' . esc_attr( $option_key ) . '"';
1113 if ( !$field['multiselect'] )
1114 {
1115 $output .= selected( esc_attr( $field['value'] ), esc_attr( $option_key ), false );
1116 }
1117 else
1118 {
1119 if (
1120 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1121 ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($option_key, $_REQUEST[$key]) )
1122 ||
1123 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1124 ( !isset($_REQUEST[$key]) && is_array($field['value']) && in_array($option_key, $field['value']) )
1125 )
1126 {
1127 $output .= ' selected';
1128 }
1129 }
1130 $output .= '>' . esc_html( $value ) . '</option>';
1131 }
1132
1133 $output .= '</select>';
1134
1135 $output .= $field['after'];
1136
1137 break;
1138 }
1139 case "office":
1140 {
1141 $key = 'officeID';
1142
1143 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1144 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1145 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1146 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1147 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1148 $field['blank_option'] = isset( $field['blank_option'] ) ? $field['blank_option'] : __( 'No preference', 'propertyhive' );
1149 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
1150
1151 if ( $field['multiselect'] )
1152 {
1153 wp_enqueue_script( 'multiselect' );
1154 }
1155
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.
1158 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1159 {
1160 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1161 $field['value'] = (int)$_GET[$key];
1162 }
1163
1164 $output .= $field['before'];
1165
1166 if ($field['show_label'])
1167 {
1168 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'] . '</label>';
1169 }
1170
1171 $output .= '<select
1172 name="' . esc_attr( $key ) . ( $field['multiselect'] ? '[]' : '' ) . '"
1173 id="' . esc_attr( $key ) . '"
1174 class="' . esc_attr( $field['class'] ) . ( $field['multiselect'] ? ' ph-form-multiselect' : '' ) . '"
1175 ' . ( $field['multiselect'] ? ' multiple="multiple"' : '' ) . '
1176 data-blank-option="' . esc_attr( $field['blank_option'] ) . '"
1177 >';
1178
1179 if ( !$field['multiselect'] )
1180 {
1181 $output .= '<option
1182 value=""
1183 ' . selected( esc_attr( $field['value'] ), esc_attr( '' ), false ) . '
1184 >' . esc_html( $field['blank_option'] ) . '</option>';
1185 }
1186
1187 $args = array(
1188 'post_type' => 'office',
1189 'nopaging' => true,
1190 'orderby' => 'title',
1191 'order' => 'ASC'
1192 );
1193 $office_query = new WP_Query($args);
1194
1195 if ($office_query->have_posts())
1196 {
1197 while ($office_query->have_posts())
1198 {
1199 $office_query->the_post();
1200
1201 $output .= '<option
1202 value="' . esc_attr( $post->ID ) . '" ';
1203 if ( !$field['multiselect'] )
1204 {
1205 $output .= selected( esc_attr( $field['value'] ), esc_attr( $post->ID ), false );
1206 }
1207 else
1208 {
1209 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1210 if ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($post->ID, $_REQUEST[$key]) )
1211 {
1212 $output .= ' selected';
1213 }
1214 }
1215 $output .= '>' . esc_html( get_the_title() ) . '</option>';
1216
1217 }
1218 }
1219 wp_reset_postdata();
1220
1221 $output .= '</select>';
1222
1223 $output .= $field['after'];
1224
1225 break;
1226 }
1227 case "country":
1228 {
1229 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1230 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1231 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1232 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1233 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1234
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.
1237 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1238 {
1239 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1240 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1241 }
1242
1243 $output .= $field['before'];
1244
1245 if ($field['show_label'])
1246 {
1247 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'] . '</label>';
1248 }
1249
1250 $output .= '<select
1251 name="' . esc_attr( $key ) . '"
1252 id="' . esc_attr( $key ) . '"
1253 class="' . esc_attr( $field['class'] ) . '"
1254 >';
1255
1256 $output .= '<option
1257 value=""
1258 ' . selected( esc_attr( $field['value'] ), esc_attr( '' ), false ) . '
1259 >' . esc_html( __( 'No preference', 'propertyhive' ) ) . '</option>';
1260
1261 $countries = get_option( 'propertyhive_countries', array() );
1262 if ( is_array($countries) && !empty($countries) )
1263 {
1264 $ph_countries = new PH_Countries;
1265
1266 foreach ( $countries as $country )
1267 {
1268 $ph_country = $ph_countries->get_country( $country );
1269
1270 if ( $ph_country !== FALSE )
1271 {
1272 $output .= '<option
1273 value="' . esc_attr( $country ) . '"
1274 ' . selected( esc_attr( $field['value'] ), esc_attr( $country ), false ) . '
1275 >' . esc_html( $ph_country['name'] ) . '</option>';
1276 }
1277 }
1278 }
1279
1280 $output .= '</select>';
1281
1282 $output .= $field['after'];
1283
1284 break;
1285 }
1286 case "slider":
1287 {
1288 wp_enqueue_script('jquery');
1289 wp_enqueue_script('jquery-ui-core');
1290 wp_enqueue_script('jquery-ui-slider');
1291 wp_enqueue_script( 'jquery-touch-punch' );
1292 wp_enqueue_style( 'jquery-ui-style', PH()->plugin_url() . '/assets/css/jquery-ui/jquery-ui.css', array(), PH_VERSION );
1293
1294 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1295 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1296 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1297 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1298 $field['min'] = isset( $field['min'] ) ? $field['min'] : '';
1299 $field['max'] = isset( $field['max'] ) ? $field['max'] : '';
1300 $field['step'] = isset( $field['step'] ) ? $field['step'] : '1';
1301
1302 $output .= $field['before'];
1303
1304 if ($field['show_label'])
1305 {
1306 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'];
1307 $output .= ' - <span id="search-form-slider-value-' . esc_attr( $key ) . '" class="search-form-slider-value search-form-slider-value-' . esc_attr( $key ) . '"></span>';
1308 $output .= '</label>';
1309 }
1310
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>';
1312
1313 $field_name = str_replace("_slider", "", $key);
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 ) . '">';
1321
1322 $output .= $field['after'];
1323
1324 $value = '';
1325 $prefix = '';
1326 $suffix = '';
1327
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) )
1334 {
1335 $prefix = '£';
1336
1337 $search_form_currency = get_option( 'propertyhive_search_form_currency', 'GBP' );
1338
1339 $ph_countries = new PH_Countries();
1340 $countries = $ph_countries->countries;
1341
1342 foreach ( $countries as $country_code => $country )
1343 {
1344 if ( isset($country['currency_code']) && $country['currency_code'] == $search_form_currency )
1345 {
1346 if ( $country['currency_prefix'] === true )
1347 {
1348 $prefix = $country['currency_symbol'];
1349 $suffix = '';
1350 }
1351 else
1352 {
1353 $prefix = '';
1354 $suffix = $country['currency_symbol'];
1355 }
1356 break;
1357 }
1358 }
1359 }
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
1365 if ( $field['min'] != '' && $field['max'] != '' )
1366 {
1367 $value = 'values: [ ' . ( $minimum !== '' ? (float) $minimum : (float)$field['min'] ) . ', ' . ( $maximum !== '' ? (float) $maximum : (float)$field['max'] ) . ' ],';
1368 }
1369
1370 $output .= '<script>
1371 jQuery(document).ready(function()
1372 {
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)
1378 {
1379 var $slider = jQuery(this);
1380
1381 $slider.slider({
1382 range: ' . ( ( $field['min'] != '' && $field['max'] != '' ) ? 'true' : 'false' ) . ',
1383 step: ' . (float) $field['step'] . ',
1384 ' . ( $field['min'] != '' ? 'min: ' . (float) $field['min'] . ',' : '' ) . '
1385 ' . ( $field['max'] != '' ? 'max: ' . (float) $field['max'] . ',' : '' ) . '
1386 ' . $value . '
1387 slide: function( event, ui ) {
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,");
1390
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]);
1397 }
1398 });
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 );
1406 });
1407 });
1408 </script>';
1409
1410 break;
1411 }
1412 case "hidden":
1413 {
1414 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
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.
1417 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1418 {
1419 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1420 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1421 }
1422
1423 $output .= '<input type="hidden" name="' . esc_attr( $field['name'] ) . '" value="' . esc_attr($field['value']) . '">';
1424 break;
1425 }
1426 case "html":
1427 {
1428 $field['html'] = isset( $field['html'] ) ? $field['html'] : '';
1429 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1430 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1431
1432 $output .= $field['before'];
1433 $output .= $field['html'];
1434 $output .= $field['after'];
1435
1436 break;
1437 }
1438 case "recaptcha":
1439 {
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>';
1444 break;
1445 }
1446 case "recaptcha-v3":
1447 {
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">';
1455 break;
1456 }
1457 case "hCaptcha":
1458 {
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>';
1463 break;
1464 }
1465 case "turnstile":
1466 {
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>';
1469 break;
1470 }
1471 case "daterange":
1472 {
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' );
1476
1477 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1478 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1479
1480 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1481 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1482
1483 $field['value'] = isset( $field['value'] ) ? $field['value'] : '';
1484 $field['style'] = isset( $field['style'] ) ? $field['style'] : '';
1485 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1486 $field['placeholder'] = isset( $field['placeholder'] ) ? $field['placeholder'] : '';
1487
1488 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1489 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1490 {
1491 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1492 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1493 }
1494
1495 $output .= $field['before'];
1496
1497 if ($field['show_label'])
1498 {
1499 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'] . '</label>';
1500 }
1501
1502 $output .= '<input type="text" autocomplete="off"
1503 name="' . esc_attr( $key ) . '"
1504 id="' . esc_attr( $key ) . '"
1505 value="' . esc_attr( $field['value'] ) . '"
1506 style="' . esc_attr( $field['style'] ) . '"
1507 class="' . esc_attr( $field['class'] ) . '"
1508 placeholder="' . esc_attr( $field['placeholder'] ) . '"
1509 />';
1510 $output .= $field['after'];
1511
1512 break;
1513 }
1514 default:
1515 {
1516 if ( taxonomy_exists($field['type']) )
1517 {
1518 $field['class'] = isset( $field['class'] ) ? $field['class'] : '';
1519 $field['before'] = isset( $field['before'] ) ? $field['before'] : '<div class="control control-' . esc_attr( $key ) . '">';
1520 $field['after'] = isset( $field['after'] ) ? $field['after'] : '</div>';
1521 $field['show_label'] = isset( $field['show_label'] ) ? $field['show_label'] : true;
1522 $field['label'] = isset( $field['label'] ) ? $field['label'] : '';
1523 $field['blank_option'] = isset( $field['blank_option'] ) ? $field['blank_option'] : __( 'No preference', 'propertyhive' );
1524 $field['parent_terms_only'] = isset( $field['parent_terms_only'] ) ? $field['parent_terms_only'] : false;
1525 $field['hide_empty'] = isset( $field['hide_empty'] ) ? $field['hide_empty'] : false;
1526 $field['multiselect'] = isset( $field['multiselect'] ) ? $field['multiselect'] : false;
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
1528
1529 if ( $field['multiselect'] )
1530 {
1531 wp_enqueue_script( 'multiselect' );
1532 }
1533
1534 $options = array(
1535 '' => array(
1536 'label' => $field['blank_option'],
1537 'parent' => 0
1538 )
1539 );
1540 $args = array(
1541 'hide_empty' => $field['hide_empty'],
1542 'parent' => 0
1543 );
1544 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1545 $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1546
1547 $levels_of_taxonomy = 1;
1548 if ( !empty( $terms ) && !is_wp_error( $terms ) )
1549 {
1550 foreach ($terms as $term)
1551 {
1552 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1553 {
1554 $empty_check_args = array(
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.
1560 'meta_query' => array(
1561 array(
1562 'key' => '_on_market',
1563 'value' => 'yes',
1564 ),
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.
1567 'tax_query' => array(
1568 array(
1569 'taxonomy' => $field['type'],
1570 'field' => 'term_id',
1571 'terms' => $term->term_id,
1572 ),
1573 ),
1574 );
1575
1576 $empty_check_args = apply_filters( 'propertyhive_taxonomy_hide_empty_args', $empty_check_args, $field, $term->term_id );
1577
1578 $empty_check_query = new WP_Query( $empty_check_args );
1579
1580 if ( !$empty_check_query->have_posts() )
1581 {
1582 continue;
1583 }
1584 }
1585
1586 $options[(int)$term->term_id] = array(
1587 'label' => $term->name,
1588 'parent' => 0
1589 );
1590
1591 if ($field['dynamic_population'])
1592 $levels_of_taxonomy = max(1, $levels_of_taxonomy);
1593
1594 if (
1595 !isset($field['parent_terms_only'])
1596 ||
1597 (
1598 isset($field['parent_terms_only']) &&
1599 $field['parent_terms_only'] === false
1600 )
1601 )
1602 {
1603 $args = array(
1604 'hide_empty' => $field['hide_empty'],
1605 'parent' => $term->term_id,
1606 );
1607 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1608 $args = apply_filters( 'propertyhive_form_taxonomy_subterms_args', $args, $field );
1609 $subterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1610
1611 if ( !empty( $subterms ) && !is_wp_error( $subterms ) )
1612 {
1613 foreach ($subterms as $subterm)
1614 {
1615 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1616 {
1617 $empty_check_args = array(
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.
1623 'meta_query' => array(
1624 array(
1625 'key' => '_on_market',
1626 'value' => 'yes',
1627 ),
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.
1630 'tax_query' => array(
1631 array(
1632 'taxonomy' => $field['type'],
1633 'field' => 'term_id',
1634 'terms' => $subterm->term_id,
1635 ),
1636 ),
1637 );
1638
1639 $empty_check_args = apply_filters( 'propertyhive_taxonomy_hide_empty_args', $empty_check_args, $field, $subterm->term_id );
1640
1641 $empty_check_query = new WP_Query( $empty_check_args );
1642
1643 if ( !$empty_check_query->have_posts() )
1644 {
1645 continue;
1646 }
1647 }
1648
1649 $options[(int)$subterm->term_id] = array(
1650 'label' => ( !$field['dynamic_population'] ? '- ' : '' ) . $subterm->name,
1651 'parent' => (int)$term->term_id,
1652 );
1653
1654 if ($field['dynamic_population'])
1655 $levels_of_taxonomy = max(2, $levels_of_taxonomy);
1656
1657 $args = array(
1658 'hide_empty' => $field['hide_empty'],
1659 'parent' => (int)$subterm->term_id
1660 );
1661 $args = apply_filters( 'propertyhive_form_taxonomy_terms_args', $args, $field );
1662 $args = apply_filters( 'propertyhive_form_taxonomy_subsubterms_args', $args, $field );
1663 $subsubterms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => $field['type'] ) ) );
1664
1665 if ( !empty( $subsubterms ) && !is_wp_error( $subsubterms ) )
1666 {
1667 foreach ($subsubterms as $subsubterm)
1668 {
1669 if ( isset($field['hide_empty']) && $field['hide_empty'] === true )
1670 {
1671 $empty_check_args = array(
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.
1677 'meta_query' => array(
1678 array(
1679 'key' => '_on_market',
1680 'value' => 'yes',
1681 ),
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.
1684 'tax_query' => array(
1685 array(
1686 'taxonomy' => $field['type'],
1687 'field' => 'term_id',
1688 'terms' => $subsubterm->term_id,
1689 ),
1690 ),
1691 );
1692
1693 $empty_check_args = apply_filters( 'propertyhive_taxonomy_hide_empty_args', $empty_check_args, $field, $subsubterm->term_id );
1694
1695 $empty_check_query = new WP_Query( $empty_check_args );
1696
1697 if ( !$empty_check_query->have_posts() )
1698 {
1699 continue;
1700 }
1701 }
1702
1703 $options[(int)$subsubterm->term_id] = array(
1704 'label' => ( !$field['dynamic_population'] ? '- - ' : '' ) . $subsubterm->name,
1705 'parent' => (int)$subterm->term_id,
1706 );
1707
1708 if ($field['dynamic_population'])
1709 $levels_of_taxonomy = max(3, $levels_of_taxonomy);
1710 }
1711 }
1712 }
1713 }
1714 }
1715 }
1716 }
1717
1718 if ( $field['dynamic_population'] )
1719 {
1720 wp_localize_script( 'propertyhive_dynamic_population', 'propertyhive_dynamic_population_params', array(
1721 'options' => $options,
1722 'levels_of_taxonomy' => $levels_of_taxonomy,
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(),
1727 'taxonomy' => $field['type'],
1728 ) );
1729 wp_enqueue_script( 'propertyhive_dynamic_population' );
1730 }
1731
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.
1734 if ( isset( $_GET[$key] ) && ! empty( $_GET[$key] ) )
1735 {
1736 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1737 $field['value'] = sanitize_text_field(wp_unslash($_GET[$key]));
1738 }
1739
1740 for ( $level_i = 1; $level_i <= $levels_of_taxonomy; ++$level_i )
1741 {
1742 $output .= $field['before'];
1743
1744 if ($field['show_label'])
1745 {
1746 $output .= '<label for="' . esc_attr( $key ) . '">' . $field['label'] . '</label>';
1747 }
1748
1749 $output .= '<select
1750 name="' . esc_attr( $key ) . ( $field['multiselect'] ? '[]' : '' ) . '"
1751 id="' . esc_attr( $key ) . '"
1752 class="' . esc_attr( $field['class'] ) . ( $field['multiselect'] ? ' ph-form-multiselect' : '' ) . '"
1753 ' . ( $field['multiselect'] ? ' multiple="multiple"' : '' ) .
1754 ( $field['dynamic_population'] ? ' data-dynamic-population-level="' . $level_i . '"' : '' ) .
1755 ( ( $field['dynamic_population'] && $level_i > 1 ) ? ' disabled' : '' ) . '
1756 data-blank-option="' . esc_attr($field['blank_option']) . '"
1757 >';
1758
1759 if ( $level_i == 1 )
1760 {
1761 foreach ( $options as $option_key => $value )
1762 {
1763 if ( $field['multiselect'] && $option_key == '' )
1764 {
1765 // Skip because we don't want a blank option in the multiselect. Instead use $value as the placeholder
1766 continue;
1767 }
1768
1769 if ( $field['dynamic_population'] && $value['parent'] != '0' )
1770 {
1771 continue;
1772 }
1773
1774 $output .= '<option
1775 value="' . esc_attr( $option_key ) . '"';
1776 if ( !$field['multiselect'] )
1777 {
1778 $output .= selected( esc_attr( $field['value'] ), esc_attr( $option_key ), false );
1779 }
1780 else
1781 {
1782 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public form preferences; these values do not authorize or perform a state change.
1783 if ( isset($_REQUEST[$key]) && is_array($_REQUEST[$key]) && in_array($option_key, $_REQUEST[$key]) )
1784 {
1785 $output .= ' selected';
1786 }
1787 elseif ( is_array($field['value']) && in_array($option_key, $field['value']) )
1788 {
1789 $output .= ' selected';
1790 }
1791 }
1792 $output .= '>' . esc_html( $value['label'] ) . '</option>';
1793 }
1794 }
1795
1796 $output .= '</select>';
1797
1798 $output .= $field['after'];
1799
1800 if ( $field['type'] == 'availability' )
1801 {
1802 $availability_departments = get_option( 'propertyhive_availability_departments', array() );
1803 if ( !is_array($availability_departments) ) { $availability_departments = array(); }
1804
1805 if ( !empty($availability_departments) )
1806 {
1807 ?>
1808 <script>
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 ); ?>;
1814 </script>
1815 <?php
1816 }
1817 }
1818 }
1819 }
1820 }
1821 }
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).
1824 echo $output;
1825 }
1826