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 / class-ph-additional-fields.php

class-ph-additional-fields.php in Property Hive 2.3.0, at includes/class-ph-additional-fields.php

1,876 lines 94.3 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; // Exit if accessed directly
8 }
9
10 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- Preserve the existing public PH_Additional_Fields extension-compatible class name.
11 class PH_Additional_Fields {
12
13 public function __construct() {
14
15 $current_settings = get_option( 'propertyhive_template_assistant', array() );
16
17 if ( isset($current_settings['custom_fields']) && is_array($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
18 {
19 add_action( 'propertyhive_property_meta_list_end', array( $this, 'display_custom_fields_on_website' ) );
20 add_filter( 'propertyhive_user_details_form_fields', array( $this, 'display_custom_fields_on_user_details' ), 10, 1 );
21 add_action( 'propertyhive_applicant_registered', array( $this, 'save_custom_fields_on_user_details' ), 10, 2 );
22 add_action( 'propertyhive_account_details_updated', array( $this, 'save_custom_fields_on_user_details' ), 10, 2 );
23
24 add_filter( 'propertyhive_property_query_meta_query', array( $this, 'custom_fields_in_meta_query' ) );
25
26 $post_types = array(
27 'property',
28 'contact',
29 'enquiry',
30 'appraisal',
31 'viewing',
32 'offer',
33 'sale',
34 'tenancy',
35 );
36
37 foreach ( $post_types as $post_type )
38 {
39 add_filter( 'manage_edit-' . $post_type . '_columns', function($existing_columns) use ($post_type)
40 {
41 if ( !is_array( $existing_columns ) )
42 {
43 $existing_columns = array();
44 }
45
46 $current_settings = get_option( 'propertyhive_template_assistant', array() );
47
48 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
49 {
50 foreach ( $current_settings['custom_fields'] as $custom_field )
51 {
52 if (
53 isset($custom_field['admin_list']) &&
54 $custom_field['admin_list'] == '1' &&
55 substr($custom_field['meta_box'], 0, (strlen($post_type)+1)) == $post_type .'_'
56 )
57 {
58 $existing_columns[$custom_field['field_name']] = $custom_field['field_label'];
59 }
60 }
61 }
62
63 return $existing_columns;
64 } );
65
66 add_action( 'manage_' . $post_type . '_posts_custom_column', function($column, $post_id) use ($post_type)
67 {
68 $current_settings = get_option( 'propertyhive_template_assistant', array() );
69
70 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
71 {
72 foreach ( $current_settings['custom_fields'] as $custom_field )
73 {
74 if (
75 isset($custom_field['admin_list']) &&
76 $custom_field['admin_list'] == '1' &&
77 substr($custom_field['meta_box'], 0, (strlen($post_type)+1)) == $post_type . '_' &&
78 $custom_field['field_name'] == $column
79 )
80 {
81 if ( get_post_meta( $post_id, $custom_field['field_name'], true ) != '' )
82 {
83 if ( $custom_field['field_type'] == 'multiselect' )
84 {
85 $values = get_post_meta( $post_id, $custom_field['field_name'], TRUE );
86 if ( !empty($values) )
87 {
88 echo esc_html(is_array($values) ? implode(", ", $values) : $values);
89 }
90 }
91 elseif ( $custom_field['field_type'] == 'date' )
92 {
93 echo esc_html( gmdate(get_option( 'date_format' ), strtotime(get_post_meta( $post_id, $custom_field['field_name'], true ))) );
94 }
95 elseif ( $custom_field['field_type'] == 'image' )
96 {
97 $image_id = get_post_meta( $post_id, $custom_field['field_name'], true );
98 if ( $image_id != '' )
99 {
100 $image = wp_get_attachment_image_src( $image_id, 'thumbnail' );
101 if ($image !== FALSE)
102 {
103 echo '<img src="' . esc_url($image[0]) . '" width="150" alt="">';
104 }
105 else
106 {
107 echo 'Image doesn\'t exist';
108 }
109 }
110 }
111 elseif ( $custom_field['field_type'] == 'file' )
112 {
113 $file = get_attached_file( get_post_meta( $post_id, $custom_field['field_name'], true ) );
114 if ( $file !== FALSE )
115 {
116 $filename = basename( $file );
117 echo '<a href="' . esc_url(wp_get_attachment_url(get_post_meta( $post_id, $custom_field['field_name'], true ))) . '" rel="noopener noreferrer" target="_blank">' . esc_html($filename) . '</a>';
118 }
119 else
120 {
121 echo 'File doesn\'t exist';
122 }
123 }
124 else
125 {
126 echo nl2br(esc_html(get_post_meta( $post_id, $custom_field['field_name'], true )));
127 }
128 }
129 break;
130 }
131 }
132 }
133 }, 2, 2 );
134
135 add_filter( 'manage_edit-' . $post_type . '_sortable_columns', function($columns) use ($post_type)
136 {
137 $custom = array();
138
139 $current_settings = get_option( 'propertyhive_template_assistant', array() );
140
141 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
142 {
143 foreach ( $current_settings['custom_fields'] as $custom_field )
144 {
145 if (
146 isset($custom_field['admin_list']) &&
147 $custom_field['admin_list'] == '1' &&
148 isset($custom_field['admin_list_sortable']) &&
149 $custom_field['admin_list_sortable'] == '1' &&
150 substr($custom_field['meta_box'], 0, (strlen($post_type)+1)) == $post_type . '_'
151 )
152 {
153 $custom[$custom_field['field_name']] = $custom_field['field_name'];
154 }
155 }
156 }
157
158 return wp_parse_args( $custom, $columns );
159 } );
160
161 add_filter( 'request', function($vars) use ($post_type)
162 {
163 if (
164 !is_admin() ||
165 !isset($vars['post_type']) ||
166 $vars['post_type'] !== $post_type ||
167 !isset($vars['orderby'])
168 ) {
169 return $vars;
170 }
171
172 $current_settings = get_option( 'propertyhive_template_assistant', array() );
173
174 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
175 {
176 foreach ( $current_settings['custom_fields'] as $custom_field )
177 {
178 if (
179 isset($custom_field['admin_list']) &&
180 $custom_field['admin_list'] == '1' &&
181 isset($custom_field['admin_list_sortable']) &&
182 $custom_field['admin_list_sortable'] == '1' &&
183 substr($custom_field['meta_box'], 0, (strlen($post_type)+1)) == $post_type . '_'
184 )
185 {
186 if ( $custom_field['field_name'] == $vars['orderby'] )
187 {
188 $vars = array_merge( $vars, array(
189 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Only a configured sortable custom field for this admin post type reaches this metadata ordering; preserve its existing text-sort contract.
190 'meta_key' => $custom_field['field_name'],
191 'orderby' => 'meta_value'
192 ) );
193 }
194 }
195 }
196 }
197
198 return $vars;
199 } );
200 }
201
202 add_action( 'propertyhive_office_table_header_columns', array( $this, 'add_office_additional_field_table_header_column' ), 10 );
203 add_action( 'propertyhive_office_table_row_columns', array( $this, 'add_office_additional_field_table_row_column' ), 10 );
204
205 add_action( 'propertyhive_contact_applicant_requirements_details_fields', array( $this, 'add_applicant_requirements_fields' ), 10, 2 );
206 add_action( 'propertyhive_contact_applicant_requirements_residential_details_fields', array( $this, 'add_applicant_requirements_residential_fields' ), 10, 2 );
207 add_action( 'propertyhive_contact_applicant_requirements_residential_sales_details_fields', array( $this, 'add_applicant_requirements_residential_sales_fields' ), 10, 2 );
208 add_action( 'propertyhive_contact_applicant_requirements_residential_lettings_details_fields', array( $this, 'add_applicant_requirements_residential_lettings_fields' ), 10, 2 );
209 add_action( 'propertyhive_contact_applicant_requirements_commercial_details_fields', array( $this, 'add_applicant_requirements_commercial_fields' ), 10, 2 );
210
211 add_action( 'propertyhive_save_contact_applicant_requirements', array( $this, 'save_applicant_requirements_fields' ), 10, 2 );
212
213 add_filter( 'propertyhive_applicant_requirements_display', array( $this, 'applicant_requirements_display' ), 10, 3 );
214 add_filter( 'propertyhive_matching_properties_args', array( $this, 'matching_properties_args' ), 10, 3 );
215 add_filter( 'propertyhive_matching_applicants_check', array( $this, 'matching_applicants_check' ), 10, 4 );
216 add_filter( 'propertyhive_applicant_requirements_form_fields', array( $this, 'applicant_requirements_form_fields' ), 10, 2 );
217 add_action( 'propertyhive_applicant_registered', array( $this, 'applicant_registered' ), 10, 2 );
218 add_action( 'propertyhive_account_requirements_updated', array( $this, 'applicant_registered' ), 10, 2 );
219
220 add_filter( 'propertyhive_applicant_list_check', array( $this, 'applicant_list_check' ), 10, 3 );
221
222 add_filter( 'propertyhive_room_breakdown_data', array( $this, 'add_custom_fields_to_room_breakdown' ), 10, 3 ); // Applicable when Rooms / Student Accommodation add on active
223
224 $meta_boxes_done = array();
225 $office_details_fields_exist = false;
226 $propertyhive_offices_opening_section_done = false;
227 foreach ( $current_settings['custom_fields'] as $custom_field )
228 {
229 if ( !in_array( $custom_field['meta_box'], $meta_boxes_done ) )
230 {
231 if ( substr( $custom_field['meta_box'], 0, 6 ) == 'office' )
232 {
233 add_filter( 'propertyhive_' . $custom_field['meta_box'] . '_settings', function( $settings ) use ( &$propertyhive_offices_opening_section_done )
234 {
235
236
237 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The settings filter reads an optional id to populate office setting defaults and returns a settings array. It does not save options or posts; settings writes occur in a separate guarded save callback.
238 $current_id = empty( $_REQUEST['id'] ) ? '' : (int)$_REQUEST['id'];
239
240 $meta_box_being_done = str_replace( "propertyhive_", "", current_filter() );
241 $meta_box_being_done = str_replace( "_settings", "", $meta_box_being_done );
242
243 $current_settings = get_option( 'propertyhive_template_assistant', array() );
244
245 foreach ( $current_settings['custom_fields'] as $custom_field )
246 {
247 if ( $custom_field['meta_box'] == $meta_box_being_done )
248 {
249 if ( !$propertyhive_offices_opening_section_done )
250 {
251 $settings[] = array( 'title' => __( 'Additional Fields', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'office_template_assistant_additional_field' );
252 $propertyhive_offices_opening_section_done = true;
253 }
254
255 switch ( $custom_field['field_type'] )
256 {
257 case "image":
258 {
259 if ( !did_action( 'wp_enqueue_media' ) )
260 wp_enqueue_media();
261
262 $settings[] = array(
263 'title' => $custom_field['field_label'],
264 'id' => $custom_field['field_name'],
265 'default' => get_post_meta($current_id, $custom_field['field_name'], TRUE),
266 'type' => $custom_field['field_type'],
267 'desc_tip' => false,
268 );
269 break;
270 }
271 case "select":
272 {
273 $options = array('' => '');
274 if ( isset($custom_field['dropdown_options']) && is_array($custom_field['dropdown_options']) && !empty($custom_field['dropdown_options']) )
275 {
276 foreach ( $custom_field['dropdown_options'] as $dropdown_option )
277 {
278 $options[$dropdown_option] = $dropdown_option;
279 }
280 }
281
282 $settings[] = array(
283 'title' => $custom_field['field_label'],
284 'id' => $custom_field['field_name'],
285 'default' => get_post_meta($current_id, $custom_field['field_name'], TRUE),
286 'type' => $custom_field['field_type'],
287 'desc_tip' => false,
288 'options' => $options,
289 );
290 break;
291 }
292 default:
293 {
294 $settings[] = array(
295 'title' => $custom_field['field_label'],
296 'id' => $custom_field['field_name'],
297 'default' => get_post_meta($current_id, $custom_field['field_name'], TRUE),
298 'type' => $custom_field['field_type'],
299 'desc_tip' => false,
300 );
301 }
302 }
303 }
304 }
305
306 if ( $propertyhive_offices_opening_section_done )
307 {
308 $settings[] = array( 'type' => 'sectionend', 'id' => 'office_template_assistant_additional_field');
309 }
310
311 return $settings;
312 });
313
314 $office_details_fields_exist = true;
315
316 add_action( 'propertyhive_save_office', function( $post_id )
317 {
318 $meta_box_being_done = 'office_details';
319
320 $current_settings = get_option( 'propertyhive_template_assistant', array() );
321
322 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
323 {
324 $current_settings['custom_fields'] = apply_filters( 'propertyhive_template_assistant_custom_fields_to_save', $current_settings['custom_fields'] );
325
326 foreach ( $current_settings['custom_fields'] as $custom_field )
327 {
328 if ( $custom_field['meta_box'] == $meta_box_being_done )
329 {
330 $field_value = $this->get_submitted_custom_field_value( $custom_field, true );
331 if ( null !== $field_value ) {
332 update_post_meta( $post_id, $custom_field['field_name'], wp_slash( $field_value ) );
333 }
334 }
335 }
336 }
337 });
338 }
339 else
340 {
341 add_action( 'propertyhive_' . $custom_field['meta_box'] . '_fields', function()
342 {
343 global $thepostid;
344
345 $meta_box_being_done = str_replace( "propertyhive_", "", current_filter() );
346 $meta_box_being_done = str_replace( "_fields", "", $meta_box_being_done );
347
348 $current_settings = get_option( 'propertyhive_template_assistant', array() );
349
350 foreach ( $current_settings['custom_fields'] as $custom_field )
351 {
352 if ( $custom_field['meta_box'] == $meta_box_being_done )
353 {
354 if ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'select' )
355 {
356 $options = array('' => '');
357 if ( isset($custom_field['dropdown_options']) && is_array($custom_field['dropdown_options']) && !empty($custom_field['dropdown_options']) )
358 {
359 foreach ( $custom_field['dropdown_options'] as $dropdown_option )
360 {
361 $options[$dropdown_option] = $dropdown_option;
362 }
363 }
364 propertyhive_wp_select( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
365 'id' => $custom_field['field_name'],
366 'label' => $custom_field['field_label'],
367 'desc_tip' => false,
368 'options' => $options
369 ), $thepostid ) );
370 }
371 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'multiselect' )
372 {
373 ?>
374 <p class="form-field <?php echo esc_attr($custom_field['field_name']); ?>_field"><label for="<?php echo esc_attr($custom_field['field_name']); ?>"><?php echo esc_html($custom_field['field_label']); ?></label>
375 <select id="<?php echo esc_attr($custom_field['field_name']); ?>" name="<?php echo esc_attr($custom_field['field_name']); ?>[]" multiple="multiple" data-placeholder="<?php echo esc_attr(/* translators: %s: Field label. */ sprintf( __( 'Select %s', 'propertyhive' ), $custom_field['field_label'] )); ?>" class="multiselect attribute_values">
376 <?php
377 $selected_values = get_post_meta( $thepostid, $custom_field['field_name'], true );
378 if ( !is_array($selected_values) && $selected_values == '' )
379 {
380 $selected_values = array();
381 }
382 elseif ( !is_array($selected_values) && $selected_values != '' )
383 {
384 $selected_values = array($selected_values);
385 }
386
387 if ( isset($custom_field['dropdown_options']) && is_array($custom_field['dropdown_options']) && !empty($custom_field['dropdown_options']) )
388 {
389 foreach ( $custom_field['dropdown_options'] as $dropdown_option )
390 {
391 echo '<option value="' . esc_attr( $dropdown_option ) . '"';
392 if ( in_array( $dropdown_option, $selected_values ) )
393 {
394 echo ' selected';
395 }
396 echo '>' . esc_html( $dropdown_option ) . '</option>';
397 }
398 }
399 ?>
400 </select>
401 <?php
402 }
403 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'textarea' )
404 {
405 propertyhive_wp_textarea_input( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
406 'id' => $custom_field['field_name'],
407 'label' => $custom_field['field_label'],
408 'desc_tip' => false,
409 'type' => 'text'
410 ), $thepostid ) );
411 }
412 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'date' )
413 {
414 propertyhive_wp_text_input( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
415 'id' => $custom_field['field_name'],
416 'label' => $custom_field['field_label'],
417 'desc_tip' => false,
418 'type' => 'date',
419 'class' => 'small',
420 ), $thepostid ) );
421 }
422 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'checkbox' )
423 {
424 propertyhive_wp_checkbox( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
425 'id' => $custom_field['field_name'],
426 'label' => $custom_field['field_label'],
427 'desc_tip' => false,
428 ), $thepostid ) );
429 }
430 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'image' )
431 {
432 propertyhive_wp_photo_upload( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
433 'id' => $custom_field['field_name'],
434 'label' => $custom_field['field_label'],
435 'desc_tip' => false,
436 'button_label' => __( 'Select Image', 'propertyhive' )
437 ), $thepostid ) );
438 }
439 elseif ( isset($custom_field['field_type']) && $custom_field['field_type'] == 'file' )
440 {
441 propertyhive_wp_file_upload( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
442 'id' => $custom_field['field_name'],
443 'label' => $custom_field['field_label'],
444 'desc_tip' => false,
445 'button_label' => __( 'Select File', 'propertyhive' )
446 ), $thepostid ) );
447 }
448 else
449 {
450 propertyhive_wp_text_input( apply_filters( 'propertyhive_template_assistant_custom_field_args_' . ltrim($custom_field['field_name'], '_'), array(
451 'id' => $custom_field['field_name'],
452 'label' => $custom_field['field_label'],
453 'desc_tip' => false,
454 'type' => 'text'
455 ), $thepostid ) );
456 }
457 }
458 }
459 });
460
461 add_action( 'propertyhive_save_' . $custom_field['meta_box'], function( $post_id )
462 {
463 $meta_box_being_done = str_replace( "propertyhive_save_", "", current_filter() );
464
465 $current_settings = get_option( 'propertyhive_template_assistant', array() );
466
467 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
468 {
469 $current_settings['custom_fields'] = apply_filters( 'propertyhive_template_assistant_custom_fields_to_save', $current_settings['custom_fields'] );
470
471 foreach ( $current_settings['custom_fields'] as $custom_field )
472 {
473 if ( $custom_field['meta_box'] == $meta_box_being_done )
474 {
475 $field_value = $this->get_submitted_custom_field_value( $custom_field, true );
476 if ( null !== $field_value ) {
477 update_post_meta( $post_id, $custom_field['field_name'], wp_slash( $field_value ) );
478 }
479 }
480 }
481 }
482 });
483 }
484
485 $meta_boxes_done[] = $custom_field['meta_box'];
486 }
487 }
488
489 if ( $office_details_fields_exist )
490 {
491 add_filter( 'propertyhive_' . $custom_field['meta_box'] . '_settings', function( $settings ) use ( &$propertyhive_offices_opening_section_done )
492 {
493 $settings[] = array( 'type' => 'sectionend', 'id' => 'office_location_options' );
494
495 return $settings;
496 });
497 }
498
499 $shortcodes = array(
500 'properties',
501 'recent_properties',
502 'featured_properties',
503 'similar_properties',
504 );
505
506 foreach ( $shortcodes as $shortcode )
507 {
508 add_filter( 'shortcode_atts_' . $shortcode, function ($out, $pairs, $atts, $shortcode)
509 {
510 $current_settings = get_option( 'propertyhive_template_assistant', array() );
511
512 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
513 {
514 foreach ( $current_settings['custom_fields'] as $custom_field )
515 {
516 if ( strpos($custom_field['meta_box'], 'property') !== FALSE )
517 {
518 $out[trim($custom_field['field_name'], '_')] = ( isset($atts[trim($custom_field['field_name'], '_')]) ? $atts[trim($custom_field['field_name'], '_')] : '' );
519 }
520 }
521 }
522
523 return $out;
524 }, 10, 4 );
525
526 add_filter( 'propertyhive_shortcode_' . $shortcode . '_query', function ($args, $atts)
527 {
528 $current_settings = get_option( 'propertyhive_template_assistant', array() );
529
530 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
531 {
532 foreach ( $current_settings['custom_fields'] as $custom_field )
533 {
534 if ( strpos($custom_field['meta_box'], 'property') !== FALSE )
535 {
536 if (
537 isset($atts[trim($custom_field['field_name'], '_')]) &&
538 $atts[trim($custom_field['field_name'], '_')] != ''
539 )
540 {
541 if ( !isset($args['meta_query']) )
542 {
543 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Configured shortcode fields are stored in post metadata; append their existing scalar/multiselect predicates without replacing other query constraints.
544 $args['meta_query'] = array();
545 }
546
547 // Format meta query as "= value" or "LIKE value"
548 $value = $atts[trim($custom_field['field_name'], '_')];
549 $compare = $custom_field['field_type'] == 'multiselect' ? 'LIKE' : '=';
550
551 // A comma-delimited list of values has been specified
552 if ( strpos($value, ',') !== false )
553 {
554 if ( $custom_field['field_type'] == 'multiselect' )
555 {
556 // Format meta query as "REGEXP value1|value2"
557 $value = '"' . str_replace(',', '"|"', $value) . '"';
558 $compare = 'REGEXP';
559 }
560 else
561 {
562 // Format meta query as "IN array(value1, value2)"
563 $value = explode(',', $value);
564 $compare = 'IN';
565 }
566 }
567
568 $args['meta_query'][] = array(
569 'key' => $custom_field['field_name'],
570 'value' => $value,
571 'compare' => $compare,
572 );
573 }
574 }
575 }
576 }
577 return $args;
578 }, 99, 2 );
579 }
580 }
581 }
582
583 public function display_custom_fields_on_website()
584 {
585 global $property;
586
587 $current_settings = get_option( 'propertyhive_template_assistant', array() );
588
589 $custom_fields = ( (isset($current_settings['custom_fields'])) ? $current_settings['custom_fields'] : array() );
590
591 foreach ( $custom_fields as $custom_field )
592 {
593 if ( isset($custom_field['display_on_website']) && $custom_field['display_on_website'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
594 {
595 $label = '<span class="' . esc_attr(trim($custom_field['field_name'], '_')) . '_label">' . esc_html($custom_field['field_label']) . ': </span>';
596
597 if ( $custom_field['field_type'] == 'multiselect' )
598 {
599 $values = get_post_meta( $property->id, $custom_field['field_name'], TRUE );
600
601 if ( !empty($values) )
602 {
603 echo '<li class="' . esc_attr(trim($custom_field['field_name'], '_')) . '">' . wp_kses_post( $label );
604 echo esc_html(is_array($values) ? implode(", ", $values) : $values);
605 echo '</li>';
606 }
607 }
608 elseif ( $custom_field['field_type'] == 'date' )
609 {
610 if ( $property->{$custom_field['field_name']} != '' )
611 {
612 ?>
613 <li class="<?php echo esc_attr(trim($custom_field['field_name'], '_')); ?>">
614 <?php echo wp_kses_post( $label ) . esc_html( gmdate(get_option( 'date_format' ), strtotime($property->{$custom_field['field_name']})) ); ?>
615 </li>
616 <?php
617 }
618 }
619 elseif ( $custom_field['field_type'] == 'image' )
620 {
621 if ( $property->{$custom_field['field_name']} != '' )
622 {
623 ?>
624 <li class="<?php echo esc_attr(trim($custom_field['field_name'], '_')); ?>">
625 <?php echo wp_kses_post( $label . wp_get_attachment_image($property->{$custom_field['field_name']}) ); ?>
626 </li>
627 <?php
628 }
629 }
630 elseif ( $custom_field['field_type'] == 'file' )
631 {
632 if ( $property->{$custom_field['field_name']} != '' )
633 {
634 ?>
635 <li class="<?php echo esc_attr(trim($custom_field['field_name'], '_')); ?>">
636 <?php echo wp_kses_post( $label ) . '<a href="' . esc_url(wp_get_attachment_url($property->{$custom_field['field_name']})) . '" rel="noopener noreferrer" target="_blank">' . esc_html(__( 'View', 'propertyhive' )) . '</a>'; ?>
637 </li>
638 <?php
639 }
640 }
641 else
642 {
643 if ( $property->{$custom_field['field_name']} != '' )
644 {
645 $value = trim( $property->{$custom_field['field_name']} );
646
647 // If the custom field value is an email address or a URL, automatically make it a link
648 if ( apply_filters( 'propertyhive_auto_hyperlink_custom_fields', true ) )
649 {
650 if ( filter_var($value, FILTER_VALIDATE_URL) )
651 {
652 $value = '<a href="' . esc_url($value) . '" rel="noopener noreferrer" target="_blank">' . esc_html($value) . '</a>';
653 }
654 elseif ( filter_var($value, FILTER_VALIDATE_EMAIL) )
655 {
656 $value = '<a href="mailto:' . antispambot( sanitize_email( $value ) ) . '">' . esc_html($value) . '</a>';
657 }
658 }
659 ?>
660 <li class="<?php echo esc_attr(trim($custom_field['field_name'], '_')); ?>">
661 <?php echo wp_kses_post( $label . $value ); ?>
662 </li>
663 <?php
664 }
665 }
666 }
667 }
668 }
669
670 public function display_custom_fields_on_user_details( $form_controls )
671 {
672 if ( is_user_logged_in() )
673 {
674 $current_user = wp_get_current_user();
675
676 if ( $current_user instanceof WP_User )
677 {
678 $contact = new PH_Contact( '', $current_user->ID );
679 }
680 }
681
682 $current_settings = get_option( 'propertyhive_template_assistant', array() );
683
684 $custom_fields = ( (isset($current_settings['custom_fields'])) ? $current_settings['custom_fields'] : array() );
685
686 foreach ( $custom_fields as $custom_field )
687 {
688 if ( isset($custom_field['display_on_user_details']) && $custom_field['display_on_user_details'] == '1' && substr($custom_field['meta_box'], 0, 8) == 'contact_' )
689 {
690 $form_controls[$custom_field['field_name']] = array(
691 'type' => $custom_field['field_type'],
692 'label' => $custom_field['field_label'],
693 );
694
695 if ( is_user_logged_in() && $current_user instanceof WP_User )
696 {
697 $form_controls[$custom_field['field_name']]['value'] = $contact->{$custom_field['field_name']};
698 }
699
700 switch ( $custom_field['field_type'] )
701 {
702 case 'select':
703 case 'multiselect':
704 {
705 $options = array('' => '');
706 if ( isset($custom_field['dropdown_options']) && is_array($custom_field['dropdown_options']) && !empty($custom_field['dropdown_options']) )
707 {
708 foreach ( $custom_field['dropdown_options'] as $dropdown_option )
709 {
710 $options[$dropdown_option] = $dropdown_option;
711 }
712 }
713 $form_controls[$custom_field['field_name']]['options'] = $options;
714 break;
715 }
716 }
717 }
718 }
719 return $form_controls;
720 }
721
722 /**
723 * Read a configured custom field without changing the shared request.
724 *
725 * A null result indicates a malformed value and leaves existing metadata intact.
726 * Callers run through the office, meta-box or user-registration save gates.
727 */
728 private function get_submitted_custom_field_value( $custom_field, $multiline = false, $default = '' )
729 {
730 $field_name = $custom_field['field_name'];
731 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Internal input helper used by the nonce-checked office, meta-box and user-details save callbacks; authorization belongs to those distinct entry points.
732 if ( ! isset( $_POST[$field_name] ) ) {
733 return $default;
734 }
735 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input helper; the calling save entry point verifies its own nonce.
736 if ( is_string( $_POST[$field_name] ) ) {
737 if ( $multiline && isset( $custom_field['field_type'] ) && 'textarea' === $custom_field['field_type'] ) {
738 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input helper; the calling save entry point verifies its own nonce.
739 return sanitize_textarea_field( wp_unslash( $_POST[$field_name] ) );
740 }
741 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input helper; the calling save entry point verifies its own nonce.
742 return sanitize_text_field( wp_unslash( $_POST[$field_name] ) );
743 }
744 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input helper; the calling save entry point verifies its own nonce.
745 if ( isset( $custom_field['field_type'] ) && 'multiselect' === $custom_field['field_type'] && is_array( $_POST[$field_name] ) ) {
746 // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- This loop validates element types only; every accepted element is sanitized and unslashed in the return below.
747 foreach ( $_POST[$field_name] as $field_value ) {
748 if ( ! is_string( $field_value ) ) {
749 return null;
750 }
751 }
752 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Input helper; the calling save entry point verifies its own nonce.
753 return ph_clean( wp_unslash( $_POST[$field_name] ) );
754 }
755 return null;
756 }
757
758 public function save_custom_fields_on_user_details( $contact_post_id, $user_id )
759 {
760 $current_settings = get_option( 'propertyhive_template_assistant', array() );
761
762 $custom_fields = ( (isset($current_settings['custom_fields'])) ? $current_settings['custom_fields'] : array() );
763
764 foreach ( $custom_fields as $custom_field )
765 {
766 if ( isset($custom_field['display_on_user_details']) && $custom_field['display_on_user_details'] == '1' && substr($custom_field['meta_box'], 0, 8) == 'contact_' )
767 {
768 $field_value = $this->get_submitted_custom_field_value( $custom_field );
769 if ( null !== $field_value ) {
770 update_post_meta( $contact_post_id, $custom_field['field_name'], wp_slash( $field_value ) );
771 }
772 }
773 }
774 }
775
776 /** Validate the scalar or flat selection-list shape used by search controls. */
777 private function is_valid_custom_field_filter( $value, $field_type )
778 {
779 if ( is_string( $value ) ) {
780 return true;
781 }
782 if ( ! in_array( $field_type, array( 'select', 'multiselect' ), true ) || ! is_array( $value ) ) {
783 return false;
784 }
785 foreach ( $value as $selection ) {
786 if ( ! is_string( $selection ) ) {
787 return false;
788 }
789 }
790 return true;
791 }
792
793 public function custom_fields_in_meta_query( $meta_query )
794 {
795 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only property/applicant search filter; no data is saved or sent.
796 $filter_department = ( isset( $_REQUEST['department'] ) && is_string( $_REQUEST['department'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['department'] ) ) : null;
797
798 $current_settings = get_option( 'propertyhive_template_assistant', array() );
799
800 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
801 {
802 foreach ( $current_settings['custom_fields'] as $custom_field )
803 {
804 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only property/applicant search filter; no data is saved or sent.
805 $filter_value = isset( $_REQUEST[$custom_field['field_name']] ) ? ph_clean( wp_unslash( $_REQUEST[$custom_field['field_name']] ) ) : null;
806 if ( null !== $filter_value && ! $this->is_valid_custom_field_filter( $filter_value, $custom_field['field_type'] ) ) {
807 continue;
808 }
809 if (
810 $custom_field['meta_box'] == 'property_residential_sales_details'
811 ||
812 $custom_field['meta_box'] == 'property_residential_lettings_details'
813 ||
814 $custom_field['meta_box'] == 'property_commercial_details'
815 )
816 {
817 // this is a department specific field. Make sure department in question in being searched
818 $meta_box_department = str_replace("property_", "", $custom_field['meta_box']);
819 $meta_box_department = str_replace("_details", "", $meta_box_department);
820 $meta_box_department = str_replace("_", "-", $meta_box_department);
821
822 if (
823
824 null !== $filter_department &&
825
826 ( $filter_department == $meta_box_department || ph_get_custom_department_based_on($filter_department) == $meta_box_department )
827 )
828 {
829
830 }
831 else
832 {
833 continue;
834 }
835 }
836
837 if ( $custom_field['field_type'] == 'checkbox' )
838 {
839 if ( $custom_field['exact_match'] == '' )
840 {
841 // not exact match (i.e. pets allowed)
842
843 if ( null !== $filter_value && ph_clean( $filter_value ) == 'yes' )
844 {
845 $meta_query[] = array(
846 'key' => $custom_field['field_name'],
847
848 'value' => ph_clean( $filter_value ),
849 );
850 }
851 }
852 else
853 {
854 // should match exactly only (i.e. something only)
855
856 if ( null !== $filter_value && ph_clean( $filter_value ) == 'yes' )
857 {
858 $meta_query[] = array(
859 'key' => $custom_field['field_name'],
860 'value' => 'yes',
861 );
862 }
863 else
864 {
865 $meta_query[] = array(
866 'relation' => 'OR',
867 array(
868 'key' => $custom_field['field_name'],
869 'value' => '',
870 ),
871 array(
872 'key' => $custom_field['field_name'],
873 'compare' => 'NOT EXISTS',
874 )
875 );
876
877 }
878 }
879 }
880 else
881 {
882 if (
883
884 null !== $filter_value && $filter_value != ''
885 )
886 {
887 if (
888 ( $custom_field['field_type'] == 'select' || $custom_field['field_type'] == 'multiselect' ) &&
889
890 is_array($filter_value)
891 )
892 {
893 $sub_meta_query = array('relation' => 'OR');
894
895 foreach ( $filter_value as $value )
896 {
897 $sub_meta_query[] = array(
898 'key' => $custom_field['field_name'],
899 'value' => ph_clean( $value ),
900 'compare' => '=',
901 );
902 $sub_meta_query[] = array(
903 'key' => $custom_field['field_name'],
904 'value' => '"' . ph_clean( $value ) . '"',
905 'compare' => 'LIKE',
906 );
907 }
908 $meta_query[] = $sub_meta_query;
909 }
910 elseif ( $custom_field['field_type'] == 'select' )
911 {
912 $meta_query[] = array(
913 'key' => $custom_field['field_name'],
914
915 'value' => ph_clean( $filter_value ),
916 'compare' => '=',
917 );
918 }
919 else
920 {
921 $meta_query[] = array(
922 'key' => $custom_field['field_name'],
923
924 'value' => ph_clean( $filter_value ),
925 'compare' => 'LIKE',
926 );
927 }
928 }
929 }
930 }
931 }
932
933 return $meta_query;
934 }
935
936 public function add_office_additional_field_table_header_column()
937 {
938 $current_settings = get_option( 'propertyhive_template_assistant', array() );
939
940 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
941 {
942 foreach ( $current_settings['custom_fields'] as $custom_field )
943 {
944 if (
945 isset($custom_field['admin_list']) &&
946 $custom_field['admin_list'] == '1' &&
947 substr($custom_field['meta_box'], 0, 6) == 'office'
948 )
949 {
950 echo '<th>' . esc_html($custom_field['field_label']) . '</th>';
951 }
952 }
953 }
954 }
955
956 public function add_office_additional_field_table_row_column( $office_id )
957 {
958 $current_settings = get_option( 'propertyhive_template_assistant', array() );
959
960 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
961 {
962 foreach ( $current_settings['custom_fields'] as $custom_field )
963 {
964 if ( isset($custom_field['admin_list']) && $custom_field['admin_list'] == '1' && substr($custom_field['meta_box'], 0, 6) == 'office' )
965 {
966 echo '<td>';
967 switch ( $custom_field['field_type'] )
968 {
969 case "image":
970 {
971 $image_id = get_post_meta( $office_id, $custom_field['field_name'], TRUE );
972 if ( $image_id != '' )
973 {
974 $image = wp_get_attachment_image_src( $image_id, 'thumbnail' );
975 if ($image !== FALSE)
976 {
977 echo '<img src="' . esc_url($image[0]) . '" width="150" alt="">';
978 }
979 else
980 {
981 echo 'Image doesn\'t exist';
982 }
983 }
984 break;
985 }
986 default:
987 {
988 echo esc_html(get_post_meta( $office_id, $custom_field['field_name'], TRUE ));
989 }
990 }
991 echo '</td>';
992 }
993 }
994 }
995 }
996
997 public function add_applicant_requirements_fields( $contact_post_id, $applicant_profile_id )
998 {
999 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1000
1001 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1002
1003 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1004 {
1005 foreach ( $current_settings['custom_fields'] as $custom_field )
1006 {
1007 if (
1008 isset($custom_field['display_on_applicant_requirements']) &&
1009 $custom_field['display_on_applicant_requirements'] == '1' &&
1010 substr($custom_field['meta_box'], 0, 9) == 'property_' &&
1011 !in_array( $custom_field['meta_box'], array('property_residential_details', 'property_residential_sales_details', 'property_residential_lettings_details', 'property_commercial_details') )
1012 )
1013 {
1014 $this->add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id );
1015 }
1016 }
1017 }
1018 }
1019
1020 private function add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id )
1021 {
1022 switch ( $custom_field['field_type'] )
1023 {
1024 case "select":
1025 {
1026 $options = array('' => '');
1027 foreach ($custom_field['dropdown_options'] as $dropdown_option)
1028 {
1029 $options[$dropdown_option] = ph_clean($dropdown_option);
1030 }
1031
1032 propertyhive_wp_select( array(
1033 'id' => '_applicant' . $custom_field['field_name'] . '_' . $applicant_profile_id,
1034 'label' => $custom_field['field_label'],
1035 'desc_tip' => false,
1036 'custom_attributes' => array(
1037 'style' => 'width:100%; max-width:150px;'
1038 ),
1039 'value' => ( ( isset($applicant_profile[$custom_field['field_name']]) ) ? $applicant_profile[$custom_field['field_name']] : '' ),
1040 'options' => $options,
1041 ) );
1042
1043 break;
1044 }
1045 case "multiselect":
1046 {
1047 $options = array('' => '');
1048 foreach ($custom_field['dropdown_options'] as $dropdown_option)
1049 {
1050 $options[$dropdown_option] = ph_clean($dropdown_option);
1051 }
1052 ?>
1053 <p class="form-field">
1054 <label for="_applicant<?php echo esc_attr($custom_field['field_name']); ?>_<?php echo esc_attr( $applicant_profile_id ); ?>"><?php echo esc_html($custom_field['field_label']); ?></label>
1055 <select id="_applicant<?php echo esc_attr($custom_field['field_name']); ?>_<?php echo esc_attr( $applicant_profile_id ); ?>" name="_applicant<?php echo esc_attr($custom_field['field_name']); ?>_<?php echo esc_attr( $applicant_profile_id ); ?>[]" multiple="multiple" data-placeholder="Start typing to add <?php echo esc_attr($custom_field['field_label']); ?>..." class="multiselect attribute_values">
1056 <?php
1057 foreach ( $options as $option )
1058 {
1059 echo '<option value="' . esc_attr( $option ) . '"';
1060 if (
1061 isset($applicant_profile[$custom_field['field_name']])
1062 )
1063 {
1064 if ( !is_array($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] != '' )
1065 {
1066 $applicant_profile[$custom_field['field_name']] = array($applicant_profile[$custom_field['field_name']]);
1067 }
1068
1069 if ( in_array( $option, $applicant_profile[$custom_field['field_name']] ) )
1070 {
1071 echo ' selected';
1072 }
1073 }
1074 echo '>' . esc_html( $option ) . '</option>';
1075 }
1076 ?>
1077 </select>
1078 </p>
1079 <?php
1080 break;
1081 }
1082 case "checkbox":
1083 {
1084 propertyhive_wp_checkbox( array(
1085 'id' => '_applicant' . $custom_field['field_name'] . '_' . $applicant_profile_id,
1086 'label' => $custom_field['field_label'],
1087 'desc_tip' => false,
1088 'value' => ( ( isset($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] == 'yes' ) ? 'yes' : '' ),
1089 ) );
1090
1091 break;
1092 }
1093 }
1094 }
1095
1096 public function add_applicant_requirements_residential_fields( $contact_post_id, $applicant_profile_id )
1097 {
1098 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1099
1100 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1101
1102 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1103 {
1104 foreach ( $current_settings['custom_fields'] as $custom_field )
1105 {
1106 if (
1107 isset($custom_field['display_on_applicant_requirements']) &&
1108 $custom_field['display_on_applicant_requirements'] == '1' &&
1109 substr($custom_field['meta_box'], 0, 9) == 'property_' &&
1110 in_array( $custom_field['meta_box'], array('property_residential_details') )
1111 )
1112 {
1113 $this->add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id );
1114 }
1115 }
1116 }
1117 }
1118
1119 public function add_applicant_requirements_residential_sales_fields( $contact_post_id, $applicant_profile_id )
1120 {
1121 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1122
1123 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1124
1125 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1126 {
1127 foreach ( $current_settings['custom_fields'] as $custom_field )
1128 {
1129 if (
1130 isset($custom_field['display_on_applicant_requirements']) &&
1131 $custom_field['display_on_applicant_requirements'] == '1' &&
1132 substr($custom_field['meta_box'], 0, 9) == 'property_' &&
1133 in_array( $custom_field['meta_box'], array('property_residential_sales_details') )
1134 )
1135 {
1136 $this->add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id );
1137 }
1138 }
1139 }
1140 }
1141
1142 public function add_applicant_requirements_residential_lettings_fields( $contact_post_id, $applicant_profile_id )
1143 {
1144 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1145
1146 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1147
1148 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1149 {
1150 foreach ( $current_settings['custom_fields'] as $custom_field )
1151 {
1152 if (
1153 isset($custom_field['display_on_applicant_requirements']) &&
1154 $custom_field['display_on_applicant_requirements'] == '1' &&
1155 substr($custom_field['meta_box'], 0, 9) == 'property_' &&
1156 in_array( $custom_field['meta_box'], array('property_residential_lettings_details') )
1157 )
1158 {
1159 $this->add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id );
1160 }
1161 }
1162 }
1163 }
1164
1165 public function add_applicant_requirements_commercial_fields( $contact_post_id, $applicant_profile_id )
1166 {
1167 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1168
1169 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1170
1171 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1172 {
1173 foreach ( $current_settings['custom_fields'] as $custom_field )
1174 {
1175 if (
1176 isset($custom_field['display_on_applicant_requirements']) &&
1177 $custom_field['display_on_applicant_requirements'] == '1' &&
1178 substr($custom_field['meta_box'], 0, 9) == 'property_' &&
1179 in_array( $custom_field['meta_box'], array('property_commercial_details') )
1180 )
1181 {
1182 $this->add_applicant_requirements_field( $custom_field, $applicant_profile, $applicant_profile_id );
1183 }
1184 }
1185 }
1186 }
1187
1188 public function save_applicant_requirements_fields( $contact_post_id, $applicant_profile_id )
1189 {
1190 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, TRUE );
1191 if ( ! is_array( $applicant_profile ) ) {
1192 $applicant_profile = array();
1193 }
1194
1195 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1196
1197 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1198 {
1199 foreach ( $current_settings['custom_fields'] as $custom_field )
1200 {
1201 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1202 {
1203 $submitted_field = $custom_field;
1204 $submitted_field['field_name'] = '_applicant' . $custom_field['field_name'] . '_' . $applicant_profile_id;
1205 $field_value = $this->get_submitted_custom_field_value( $submitted_field );
1206 if ( null === $field_value ) {
1207 continue;
1208 }
1209 switch ( $custom_field['field_type'] )
1210 {
1211 case "select":
1212 case "multiselect":
1213 {
1214 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Presence check only; the contact save entry point verifies the nonce before this hook and values are normalized by get_submitted_custom_field_value.
1215 if ( isset($_POST['_applicant' . $custom_field['field_name'] . '_' . $applicant_profile_id]) )
1216 {
1217 $applicant_profile[$custom_field['field_name']] = $field_value;
1218 }
1219 break;
1220 }
1221 case "checkbox":
1222 {
1223 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Presence check only; the contact save entry point verifies the nonce before this hook and values are normalized by get_submitted_custom_field_value.
1224 if ( isset($_POST['_applicant' . $custom_field['field_name'] . '_' . $applicant_profile_id]) )
1225 {
1226 $applicant_profile[$custom_field['field_name']] = $field_value;
1227 }
1228 else
1229 {
1230 $applicant_profile[$custom_field['field_name']] = '';
1231 }
1232 break;
1233 }
1234 }
1235 }
1236 }
1237 }
1238
1239 update_post_meta( $contact_post_id, '_applicant_profile_' . $applicant_profile_id, wp_slash( $applicant_profile ) );
1240 }
1241
1242 public function applicant_requirements_display( $requirements, $contact_post_id, $applicant_profile )
1243 {
1244 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1245
1246 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1247 {
1248 foreach ( $current_settings['custom_fields'] as $custom_field )
1249 {
1250 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1251 {
1252 if ( isset($applicant_profile[$custom_field['field_name']]) )
1253 {
1254 switch ( $custom_field['field_type'] )
1255 {
1256 case "select":
1257 case "checkbox":
1258 {
1259 if ( $applicant_profile[$custom_field['field_name']] != '' )
1260 {
1261 $requirements[] = array(
1262 'label' => $custom_field['field_label'],
1263 'value' => ph_clean($applicant_profile[$custom_field['field_name']]),
1264 );
1265 }
1266 break;
1267 }
1268 case "multiselect":
1269 {
1270 if ( !is_array($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] != '' )
1271 {
1272 $applicant_profile[$custom_field['field_name']] = array($applicant_profile[$custom_field['field_name']]);
1273 }
1274
1275 if ( !empty($applicant_profile[$custom_field['field_name']]) )
1276 {
1277 $sliced_terms = array_slice( ph_clean($applicant_profile[$custom_field['field_name']]), 0, 2 );
1278 $requirements[] = array(
1279 'label' => $custom_field['field_label'],
1280 'value' => implode(", ", $sliced_terms) . ( (count($applicant_profile[$custom_field['field_name']]) > 2) ? '<span title="' . esc_attr( implode(", ", $applicant_profile[$custom_field['field_name']]) ) .'"> + ' . (count($applicant_profile[$custom_field['field_name']]) - 2) . ' more</span>' : '' )
1281 );
1282 }
1283 break;
1284 }
1285 }
1286 }
1287 }
1288 }
1289 }
1290
1291 return $requirements;
1292 }
1293
1294 public function matching_properties_args( $args, $contact_post_id, $applicant_profile )
1295 {
1296 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1297
1298 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1299 {
1300 foreach ( $current_settings['custom_fields'] as $custom_field )
1301 {
1302 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1303 {
1304 if ( isset($applicant_profile[$custom_field['field_name']]) )
1305 {
1306 // ensure if field is specific to department it's taken into account, else ignored
1307 if (
1308 $custom_field['meta_box'] == 'property_residential_sales_details'
1309 ||
1310 $custom_field['meta_box'] == 'property_residential_lettings_details'
1311 ||
1312 $custom_field['meta_box'] == 'property_commercial_details'
1313 )
1314 {
1315 $meta_box_department = str_replace("property_", "", $custom_field['meta_box']);
1316 $meta_box_department = str_replace("_details", "", $meta_box_department);
1317 $meta_box_department = str_replace("_", "-", $meta_box_department);
1318
1319 if (
1320 isset( $applicant_profile['department'] ) &&
1321 ( $applicant_profile['department'] == $meta_box_department || ph_get_custom_department_based_on($applicant_profile['department']) == $meta_box_department )
1322 )
1323 {
1324
1325 }
1326 else
1327 {
1328 continue;
1329 }
1330 }
1331
1332 switch ( $custom_field['field_type'] )
1333 {
1334 case "select":
1335 {
1336 if ( $applicant_profile[$custom_field['field_name']] != '' )
1337 {
1338 $args['meta_query'][] = array(
1339 'key' => $custom_field['field_name'],
1340 'value' => $applicant_profile[$custom_field['field_name']],
1341 );
1342 }
1343 break;
1344 }
1345 case "multiselect":
1346 {
1347 if ( !is_array($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] != '' )
1348 {
1349 $applicant_profile[$custom_field['field_name']] = array($applicant_profile[$custom_field['field_name']]);
1350 }
1351
1352 if ( !empty($applicant_profile[$custom_field['field_name']]) )
1353 {
1354 $sub_meta_query = array(
1355 'relation' => 'OR'
1356 );
1357
1358 foreach ( $applicant_profile[$custom_field['field_name']] as $option )
1359 {
1360 $sub_meta_query[] = array(
1361 'key' => $custom_field['field_name'],
1362 'value' => $option,
1363 'compare' => 'LIKE',
1364 );
1365 }
1366
1367 $args['meta_query'][] = $sub_meta_query;
1368 }
1369 break;
1370 }
1371 case "checkbox":
1372 {
1373 if ( $custom_field['exact_match'] == '' )
1374 {
1375 if ( $applicant_profile[$custom_field['field_name']] != '' )
1376 {
1377 $args['meta_query'][] = array(
1378 'key' => $custom_field['field_name'],
1379 'value' => $applicant_profile[$custom_field['field_name']],
1380 );
1381 }
1382 }
1383 else
1384 {
1385 // should match exactly only
1386 if ( $applicant_profile[$custom_field['field_name']] == 'yes' )
1387 {
1388 $args['meta_query'][] = array(
1389 'key' => $custom_field['field_name'],
1390 'value' => 'yes',
1391 );
1392 }
1393 else
1394 {
1395 $args['meta_query'][] = array(
1396 'relation' => 'OR',
1397 array(
1398 'key' => $custom_field['field_name'],
1399 'value' => '',
1400 ),
1401 array(
1402 'key' => $custom_field['field_name'],
1403 'compare' => 'NOT EXISTS',
1404 )
1405 );
1406
1407 }
1408 }
1409 break;
1410 }
1411 }
1412 }
1413 }
1414 }
1415 }
1416
1417 return $args;
1418 }
1419
1420 public function matching_applicants_check( $check, $property, $contact_post_id, $applicant_profile )
1421 {
1422 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1423
1424 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1425 {
1426 foreach ( $current_settings['custom_fields'] as $custom_field )
1427 {
1428 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1429 {
1430 // ensure if field is specific to department it's taken into account, else ignored
1431 if (
1432 $custom_field['meta_box'] == 'property_residential_sales_details'
1433 ||
1434 $custom_field['meta_box'] == 'property_residential_lettings_details'
1435 ||
1436 $custom_field['meta_box'] == 'property_commercial_details'
1437 )
1438 {
1439 $meta_box_department = str_replace("property_", "", $custom_field['meta_box']);
1440 $meta_box_department = str_replace("_details", "", $meta_box_department);
1441 $meta_box_department = str_replace("_", "-", $meta_box_department);
1442
1443 if (
1444 isset( $applicant_profile['department'] ) &&
1445 ( $applicant_profile['department'] == $meta_box_department || ph_get_custom_department_based_on($applicant_profile['department']) == $meta_box_department )
1446 )
1447 {
1448
1449 }
1450 else
1451 {
1452 continue;
1453 }
1454 }
1455
1456 if ( isset($applicant_profile[$custom_field['field_name']]) )
1457 {
1458 switch ( $custom_field['field_type'] )
1459 {
1460 case "select":
1461 {
1462 if (
1463 $applicant_profile[$custom_field['field_name']] == '' ||
1464 $property->{$custom_field['field_name']} == $applicant_profile[$custom_field['field_name']]
1465 )
1466 {
1467
1468 }
1469 else
1470 {
1471 return false;
1472 }
1473 break;
1474 }
1475 case "multiselect":
1476 {
1477 if ( !is_array($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] != '' )
1478 {
1479 $applicant_profile[$custom_field['field_name']] = array($applicant_profile[$custom_field['field_name']]);
1480 }
1481
1482 if ( empty($applicant_profile[$custom_field['field_name']]) )
1483 {
1484
1485 }
1486 else
1487 {
1488 $property_values = !is_array($property->{$custom_field['field_name']}) ? array($property->{$custom_field['field_name']}) : $property->{$custom_field['field_name']};
1489 if ( empty($property_values) )
1490 {
1491 return false;
1492 }
1493
1494 $applicant_values = $applicant_profile[$custom_field['field_name']];
1495
1496 $value_exists = false;
1497
1498 foreach ( $property_values as $property_value )
1499 {
1500 foreach ( $applicant_values as $applicant_value )
1501 {
1502 if ( $property_value == $applicant_value )
1503 {
1504 $value_exists = true;
1505 }
1506 }
1507 }
1508
1509 if ( !$value_exists )
1510 {
1511 return false;
1512 }
1513 }
1514
1515 break;
1516 }
1517 case "checkbox":
1518 {
1519 if ( $custom_field['exact_match'] == '' )
1520 {
1521 // not exact match (i.e. pets allowed)
1522 if (
1523 $applicant_profile[$custom_field['field_name']] == '' ||
1524 $property->{$custom_field['field_name']} == $applicant_profile[$custom_field['field_name']]
1525 )
1526 {
1527
1528 }
1529 else
1530 {
1531 return false;
1532 }
1533 }
1534 else
1535 {
1536 // exact match
1537 if (
1538 $property->{$custom_field['field_name']} == $applicant_profile[$custom_field['field_name']]
1539 )
1540 {
1541
1542 }
1543 else
1544 {
1545 return false;
1546 }
1547 }
1548 break;
1549 }
1550 }
1551 }
1552 }
1553 }
1554 }
1555
1556 return $check;
1557 }
1558
1559 public function applicant_requirements_form_fields( $form_controls, $applicant_profile = false )
1560 {
1561 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1562
1563 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1564 {
1565 foreach ( $current_settings['custom_fields'] as $custom_field )
1566 {
1567 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1568 {
1569 switch ( $custom_field['field_type'] )
1570 {
1571 case "select":
1572 case "multiselect":
1573 {
1574 $options = array('' => '');
1575 foreach ($custom_field['dropdown_options'] as $dropdown_option)
1576 {
1577 $options[$dropdown_option] = ph_clean($dropdown_option);
1578 }
1579
1580 $value = isset($applicant_profile[$custom_field['field_name']]) ? $applicant_profile[$custom_field['field_name']] : '';
1581 /*if ( is_array($value) && !empty($value) )
1582 {
1583 $value = $value[0];
1584 }*/
1585
1586 $form_controls[$custom_field['field_name']] = array(
1587 'type' => 'select',
1588 'label' => $custom_field['field_label'],
1589 'required' => false,
1590 'show_label' => true,
1591 'value' => $value,
1592 'options' => $options,
1593 'multiselect' => $custom_field['field_type'] == 'multiselect' ? true : false
1594 );
1595
1596 break;
1597 }
1598 case "checkbox":
1599 {
1600 $value = isset($applicant_profile[$custom_field['field_name']]) ? $applicant_profile[$custom_field['field_name']] : '';
1601
1602 $form_controls[$custom_field['field_name']] = array(
1603 'type' => 'checkbox',
1604 'label' => $custom_field['field_label'],
1605 'required' => false,
1606 'show_label' => true,
1607 'value' => $value,
1608 );
1609
1610 break;
1611 }
1612 }
1613 }
1614 }
1615 }
1616
1617 return $form_controls;
1618 }
1619
1620 public function applicant_registered( $contact_post_id, $user_id )
1621 {
1622 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Registration/account callback runs after its parent AJAX nonce and ownership checks; this hook only updates the supplied contact.
1623 if ( isset( $_POST['profile_id'] ) && ! is_string( $_POST['profile_id'] ) ) {
1624 return;
1625 }
1626 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- The parent registration/account AJAX callback verifies its nonce before dispatching this hook.
1627 $profile_id = isset( $_POST['profile_id'] ) ? absint( $_POST['profile_id'] ) : 0;
1628 $applicant_profile = get_post_meta( $contact_post_id, '_applicant_profile_' . $profile_id, TRUE );
1629 if ( ! is_array( $applicant_profile ) ) {
1630 $applicant_profile = array();
1631 }
1632
1633 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1634
1635 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1636 {
1637 foreach ( $current_settings['custom_fields'] as $custom_field )
1638 {
1639 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1640 {
1641 $field_value = $this->get_submitted_custom_field_value( $custom_field, false, 'multiselect' === $custom_field['field_type'] ? array() : '' );
1642 if ( null === $field_value ) {
1643 continue;
1644 }
1645 switch ( $custom_field['field_type'] )
1646 {
1647 case "select":
1648 {
1649 $applicant_profile[$custom_field['field_name']] = $field_value;
1650 break;
1651 }
1652 case "multiselect":
1653 {
1654 $applicant_profile[$custom_field['field_name']] = is_array( $field_value ) ? $field_value : array( $field_value );
1655 break;
1656 }
1657 case "checkbox":
1658 {
1659 $applicant_profile[$custom_field['field_name']] = $field_value;
1660 break;
1661 }
1662 }
1663 }
1664 }
1665 }
1666
1667 update_post_meta( $contact_post_id, '_applicant_profile_' . $profile_id, wp_slash( $applicant_profile ) );
1668 }
1669
1670 public function applicant_list_check( $check, $contact_post_id, $applicant_profile )
1671 {
1672 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read-only property/applicant search filter; no data is saved or sent.
1673 $filter_department = ( isset( $_POST['department'] ) && is_string( $_POST['department'] ) ) ? sanitize_text_field( wp_unslash( $_POST['department'] ) ) : null;
1674
1675 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1676
1677 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1678 {
1679 foreach ( $current_settings['custom_fields'] as $custom_field )
1680 {
1681 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Read-only property/applicant search filter; no data is saved or sent.
1682 $filter_value = isset( $_POST[$custom_field['field_name']] ) ? ph_clean( wp_unslash( $_POST[$custom_field['field_name']] ) ) : null;
1683 if ( null !== $filter_value && ! $this->is_valid_custom_field_filter( $filter_value, $custom_field['field_type'] ) ) {
1684 return false;
1685 }
1686 if ( isset($custom_field['display_on_applicant_requirements']) && $custom_field['display_on_applicant_requirements'] == '1' && substr($custom_field['meta_box'], 0, 9) == 'property_' )
1687 {
1688 // ensure if field is specific to department it's taken into account, else ignored
1689 if (
1690 $custom_field['meta_box'] == 'property_residential_sales_details'
1691 ||
1692 $custom_field['meta_box'] == 'property_residential_lettings_details'
1693 ||
1694 $custom_field['meta_box'] == 'property_commercial_details'
1695 )
1696 {
1697 $meta_box_department = str_replace("property_", "", $custom_field['meta_box']);
1698 $meta_box_department = str_replace("_details", "", $meta_box_department);
1699 $meta_box_department = str_replace("_", "-", $meta_box_department);
1700
1701 if (
1702
1703 null !== $filter_department &&
1704
1705 ( $filter_department == $meta_box_department || ph_get_custom_department_based_on($filter_department) == $meta_box_department )
1706 )
1707 {
1708
1709 }
1710 else
1711 {
1712 continue;
1713 }
1714 }
1715
1716
1717 if ( isset($applicant_profile[$custom_field['field_name']]) )
1718 {
1719 switch ( $custom_field['field_type'] )
1720 {
1721 case "select":
1722 {
1723
1724 if ( !empty($filter_value) )
1725 {
1726 if (
1727 $applicant_profile[$custom_field['field_name']] == '' ||
1728
1729 $filter_value == $applicant_profile[$custom_field['field_name']]
1730 )
1731 {
1732
1733 }
1734 else
1735 {
1736 return false;
1737 }
1738 }
1739 break;
1740 }
1741 case "multiselect":
1742 {
1743
1744 if ( !empty($filter_value) )
1745 {
1746 if ( !is_array($applicant_profile[$custom_field['field_name']]) && $applicant_profile[$custom_field['field_name']] != '' )
1747 {
1748 $applicant_profile[$custom_field['field_name']] = array($applicant_profile[$custom_field['field_name']]);
1749 }
1750
1751 if ( empty($applicant_profile[$custom_field['field_name']]) )
1752 {
1753
1754 }
1755 else
1756 {
1757
1758 $property_values = is_array( $filter_value ) ? $filter_value : array( $filter_value );
1759 if ( empty($property_values) )
1760 {
1761 return false;
1762 }
1763
1764 $applicant_values = $applicant_profile[$custom_field['field_name']];
1765
1766 $value_exists = false;
1767
1768 foreach ( $property_values as $property_value )
1769 {
1770 foreach ( $applicant_values as $applicant_value )
1771 {
1772 if ( $property_value == $applicant_value )
1773 {
1774 $value_exists = true;
1775 }
1776 }
1777 }
1778
1779 if ( !$value_exists )
1780 {
1781 return false;
1782 }
1783 }
1784 }
1785
1786 break;
1787 }
1788 case "checkbox":
1789 {
1790 if ( $custom_field['exact_match'] == '' )
1791 {
1792 // not exact match (i.e. pets allowed)
1793 if (
1794 $applicant_profile[$custom_field['field_name']] == '' ||
1795
1796 $filter_value == $applicant_profile[$custom_field['field_name']]
1797 )
1798 {
1799
1800 }
1801 else
1802 {
1803 return false;
1804 }
1805 }
1806 else
1807 {
1808 // exact match
1809
1810 if ( null !== $filter_value )
1811 {
1812 if (
1813
1814 $filter_value == $applicant_profile[$custom_field['field_name']]
1815 )
1816 {
1817
1818 }
1819 else
1820 {
1821 return false;
1822 }
1823 }
1824 else
1825 {
1826 if (
1827 '' == $applicant_profile[$custom_field['field_name']]
1828 )
1829 {
1830
1831 }
1832 else
1833 {
1834 return false;
1835 }
1836 }
1837 }
1838 break;
1839 }
1840 }
1841 }
1842 }
1843 }
1844 }
1845
1846 return $check;
1847 }
1848
1849 public function add_custom_fields_to_room_breakdown( $room_data, $post_id, $room )
1850 {
1851 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1852
1853 if ( isset($current_settings['custom_fields']) && !empty($current_settings['custom_fields']) )
1854 {
1855 foreach ( $current_settings['custom_fields'] as $custom_field )
1856 {
1857 if ( isset($custom_field['display_on_website']) && $custom_field['display_on_website'] == '1' && $custom_field['meta_box'] == 'property_rooms_breakdown' )
1858 {
1859 if ( $room->{$custom_field['field_name']} != '' )
1860 {
1861 $room_data[] = array(
1862 'class' => sanitize_title($custom_field['field_name']),
1863 'label' => $custom_field['field_label'],
1864 'value' => $room->{$custom_field['field_name']}
1865 );
1866 }
1867 }
1868 }
1869 }
1870
1871 return $room_data;
1872 }
1873 }
1874
1875 new PH_Additional_Fields();
1876