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-template-functions.php

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

2,166 lines 75.8 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 * PropertyHive Template
7 *
8 * Functions for the templating system.
9 *
10 * @author PropertyHive
11 * @category Core
12 * @package PropertyHive/Functions
13 * @version 1.0.0
14 */
15
16 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
17
18 /**
19 * When the_post is called, put property data into a global.
20 *
21 * @param mixed $post
22 * @return PH_Property
23 */
24 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_setup_property_data; the established callable name is part of the plugin/extension API and must remain stable.
25 function ph_setup_property_data( $post ) {
26 unset( $GLOBALS['property'] );
27
28 if ( is_int( $post ) )
29 $post = get_post( $post );
30
31 if ( empty( $post->post_type ) || ! in_array( $post->post_type, array( 'property' ) ) )
32 return;
33
34 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared frontend template global; Property Hive intentionally publishes the current property object for templates and builder integrations.
35 $GLOBALS['property'] = get_property( $post );
36
37 return $GLOBALS['property'];
38 }
39 add_action( 'the_post', 'ph_setup_property_data' );
40
41 /**
42 * Properties RSS Feed.
43 *
44 * @access public
45 * @return void
46 */
47 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_properties_rss_feed; the established callable name is part of the plugin/extension API and must remain stable.
48 function ph_properties_rss_feed() {
49 // Property RSS
50 if ( is_post_type_archive( 'property' ) || is_singular( 'property' ) ) {
51
52 $feed = get_post_type_archive_feed_link( 'property' );
53
54 echo '<link rel="alternate" type="application/rss+xml" title="' . esc_attr(__( 'Latest Properties', 'propertyhive' )) . '" href="' . esc_url( $feed ) . '" />';
55
56 }
57 }
58
59 /**
60 * Output generator tag to aid debugging.
61 *
62 * @access public
63 * @return void
64 */
65 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_generator_tag; the established callable name is part of the plugin/extension API and must remain stable.
66 function ph_generator_tag( $gen, $type ) {
67 switch ( $type ) {
68 case 'html':
69 $gen .= "\n" . '<meta name="generator" content="PropertyHive ' . esc_attr( PH_VERSION ) . '">';
70 break;
71 case 'xhtml':
72 $gen .= "\n" . '<meta name="generator" content="PropertyHive ' . esc_attr( PH_VERSION ) . '" />';
73 break;
74 }
75 return $gen;
76 }
77
78 /**
79 * Add body classes for PH pages
80 *
81 * @param array $classes
82 * @return array
83 */
84 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_body_class; the established callable name is part of the plugin/extension API and must remain stable.
85 function ph_body_class( $classes ) {
86 global $wp_query;
87
88 $classes = (array) $classes;
89
90 if ( is_propertyhive() ) {
91 $classes[] = 'propertyhive';
92 $classes[] = 'propertyhive-page';
93 }
94
95 // If we're on a single property, add body classes for taxonomy fields and department
96 if ( is_single() )
97 {
98 $post = $wp_query->get_queried_object();
99 if ( $post->post_type === 'property' )
100 {
101 // Duplication of the code in post-template-php that is done for search results posts in get_post_class()
102 // All public taxonomies.
103 $taxonomies = get_taxonomies( array( 'public' => true ) );
104 foreach ( (array) $taxonomies as $taxonomy ) {
105 if ( is_object_in_taxonomy( $post->post_type, $taxonomy ) ) {
106 foreach ( (array) get_the_terms( $post->ID, $taxonomy ) as $term ) {
107 if ( empty( $term->slug ) ) {
108 continue;
109 }
110
111 $term_class = sanitize_html_class( $term->slug, $term->term_id );
112 if ( is_numeric( $term_class ) || ! trim( $term_class, '-' ) ) {
113 $term_class = $term->term_id;
114 }
115
116 // 'post_tag' uses the 'tag' prefix for backward compatibility.
117 if ( 'post_tag' == $taxonomy ) {
118 $classes[] = 'tag-' . $term_class;
119 } else {
120 $classes[] = sanitize_html_class( $taxonomy . '-' . $term_class, $taxonomy . '-' . $term->term_id );
121 }
122 }
123 }
124 }
125 //
126
127 $property = get_property( $post->ID );
128 $classes[] = 'department-' . $property->department;
129 $classes[] = 'on-market-' . ( $property->on_market == 'yes' ? 'yes' : 'no' );
130 $classes[] = 'featured-' . ( $property->featured == 'yes' ? 'yes' : 'no' );
131 $classes[] = 'office-' . $property->office_id;
132 }
133 }
134
135 return array_unique( $classes );
136 }
137
138 /**
139 * Adds extra post classes for properties
140 *
141 * @since 1.0.0
142 * @param array $classes
143 * @param string|array $class
144 * @param int $post_id
145 * @return array
146 */
147 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_property_post_class; the established callable name is part of the plugin/extension API and must remain stable.
148 function ph_property_post_class( $classes, $class = '', $post_id = '' ) {
149 if ( ! $post_id || get_post_type( $post_id ) !== 'property' )
150 return $classes;
151
152 $property = get_property( $post_id );
153
154 if ( $property ) {
155 if ( $property->is_featured() ) {
156 $classes[] = 'featured';
157 }
158 }
159
160 if ( ( $key = array_search( 'hentry', $classes ) ) !== false ) {
161 unset( $classes[ $key ] );
162 }
163
164 // Add 'property' class, removing it first incase it exists
165 // Needed as results loaded with AJAX don't get the property class by default
166 if ( ( $key = array_search( 'property', $classes ) ) !== false ) {
167 unset( $classes[ $key ] );
168 }
169 $classes[] = 'property';
170 $classes[] = 'department-' . $property->department;
171 $classes[] = 'office-' . $property->office_id;
172
173 $classes = array_values($classes);
174
175 return $classes;
176 }
177
178 /** Global ****************************************************************/
179
180 if ( ! function_exists( 'propertyhive_output_content_wrapper' ) ) {
181
182 /**
183 * Output the start of the page wrapper.
184 *
185 * @access public
186 * @return void
187 */
188 function propertyhive_output_content_wrapper() {
189 ph_get_template( 'global/wrapper-start.php' );
190 }
191 }
192
193 if ( ! function_exists( 'propertyhive_output_content_wrapper_end' ) ) {
194
195 /**
196 * Output the end of the page wrapper.
197 *
198 * @access public
199 * @return void
200 */
201 function propertyhive_output_content_wrapper_end() {
202 ph_get_template( 'global/wrapper-end.php' );
203 }
204 }
205
206 /** Loop ******************************************************************/
207
208 if ( ! function_exists( 'propertyhive_page_title' ) ) {
209
210 /**
211 * propertyhive_page_title function.
212 *
213 * @param boolean $echo
214 * @return string
215 */
216 function propertyhive_page_title( $echo = true ) {
217
218 if ( is_search() )
219 {
220 $page_title = sprintf(
221 /* translators: %s: search query */
222 __( 'Search Results: &ldquo;%s&rdquo;', 'propertyhive' ),
223 get_search_query()
224 );
225
226 if ( get_query_var( 'paged' ) )
227 {
228 $page_title .= sprintf(
229 /* translators: %s: page number */
230 __( '&nbsp;&ndash; Page %s', 'propertyhive' ),
231 get_query_var( 'paged' )
232 );
233 }
234
235 }elseif ( is_tax() )
236 {
237 $page_title = single_term_title( "", false );
238 }
239 else
240 {
241 $search_results_page_id = ph_get_page_id( 'search_results' );
242 $page_title = get_the_title( $search_results_page_id );
243 }
244
245 $page_title = apply_filters( 'propertyhive_page_title', wp_kses_post( $page_title ) );
246
247 if ( $echo )
248 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- The core title is KSES-filtered before the trusted PHP propertyhive_page_title filter, which intentionally supports formatted titles.
249 echo $page_title;
250 else
251 return $page_title;
252 }
253 }
254
255 if ( ! function_exists( 'propertyhive_property_loop_start' ) ) {
256
257 /**
258 * Output the start of a property loop. By default this is a UL
259 *
260 * @access public
261 * @param bool $echo
262 * @return string
263 */
264 function propertyhive_property_loop_start( $echo = true ) {
265 ob_start();
266 ph_get_template( 'search/loop-start.php' );
267 if ( $echo )
268 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Captured trusted PHP loop template; the built-in template emits static list markup and theme overrides own their escaping.
269 echo ob_get_clean();
270 else
271 return ob_get_clean();
272 }
273 }
274 if ( ! function_exists( 'propertyhive_property_loop_end' ) ) {
275
276 /**
277 * Output the end of a property loop. By default this is a UL
278 *
279 * @access public
280 * @param bool $echo
281 * @return string
282 */
283 function propertyhive_property_loop_end( $echo = true ) {
284 ob_start();
285
286 ph_get_template( 'search/loop-end.php' );
287
288 if ( $echo )
289 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Captured trusted PHP loop template; the built-in template emits static list markup and theme overrides own their escaping.
290 echo ob_get_clean();
291 else
292 return ob_get_clean();
293 }
294 }
295
296 if ( ! function_exists( 'propertyhive_template_loop_property_thumbnail' ) ) {
297
298 /**
299 * Get the property thumbnail for the loop.
300 *
301 * @access public
302 * @subpackage Loop
303 * @return void
304 */
305 function propertyhive_template_loop_property_thumbnail() {
306 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound, WordPress.Security.EscapeOutput.OutputNotEscaped -- The thumbnail helper escapes image attributes; preserve its trusted PHP override and placeholder HTML hook, and the existing image-size hook name.
307 echo propertyhive_get_property_thumbnail( apply_filters( 'property_search_results_thumbnail_size', 'medium' ) );
308 }
309 }
310
311 if ( ! function_exists( 'propertyhive_get_property_thumbnail' ) ) {
312
313 /**
314 * Get the property thumbnail, or the placeholder if not set.
315 *
316 * @access public
317 * @subpackage Loop
318 * @param string $size (default: 'medium')
319 * @param int $placeholder_width (default: 0)
320 * @param int $placeholder_height (default: 0)
321 * @return string
322 */
323 function propertyhive_get_property_thumbnail( $size = 'medium', $class = '', $placeholder_width = 0, $placeholder_height = 0 ) {
324 global $post, $property;
325
326 $photo_url = $property->get_main_photo_src( $size );
327
328 if ($photo_url !== FALSE)
329 return '<img src="' . esc_url( $photo_url ) . '" alt="' . esc_attr( get_the_title($post->ID) ) . '" class="' . esc_attr( $class ) . '">';
330
331 if ( ph_placeholder_img_src() )
332 return ph_placeholder_img( $size );
333 }
334 }
335
336 if ( ! function_exists( 'propertyhive_template_loop_floor_area' ) ) {
337
338 /**
339 * Get the property floor area for the loop.
340 *
341 * @access public
342 * @subpackage Loop
343 * @return void
344 */
345 function propertyhive_template_loop_floor_area() {
346 global $property;
347
348 if ( $property->department == 'commercial' || ph_get_custom_department_based_on( $property->department ) == 'commercial' )
349 {
350 ph_get_template( 'search/floor-area.php' );
351 }
352 }
353 }
354
355 if ( ! function_exists( 'propertyhive_template_loop_price' ) ) {
356
357 /**
358 * Get the property price for the loop.
359 *
360 * @access public
361 * @subpackage Loop
362 * @return void
363 */
364 function propertyhive_template_loop_price() {
365
366 global $property;
367
368 $fees = '';
369 if ( get_option('propertyhive_lettings_fees_display_search_results', '') == 'yes' )
370 {
371 if (
372 $property->department == 'residential-lettings' &&
373 get_option('propertyhive_lettings_fees', '') != ''
374 )
375 {
376 $fees = nl2br(get_option('propertyhive_lettings_fees', ''));
377 }
378 if (
379 $property->department == 'commercial' &&
380 $property->to_rent == 'yes' &&
381 get_option('propertyhive_lettings_fees_commercial', '') != ''
382 )
383 {
384 $fees = nl2br(get_option('propertyhive_lettings_fees_commercial', ''));
385 }
386 }
387
388 $price_qualifier = '';
389 if (
390 (
391 $property->department == 'residential-sales' ||
392 ph_get_custom_department_based_on($property->department) == 'residential-sales' ||
393 $property->department == 'commercial' ||
394 ph_get_custom_department_based_on($property->department) == 'commercial'
395 ) &&
396 $property->price_qualifier != ''
397 )
398 {
399 $price_qualifier = $property->price_qualifier;
400 }
401
402 ph_get_template( 'search/price.php', array( 'price_qualifier' => $price_qualifier, 'fees' => $fees ) );
403 }
404 }
405
406 if ( ! function_exists( 'propertyhive_template_loop_summary' ) ) {
407
408 /**
409 * Get the property summary for the loop.
410 *
411 * @access public
412 * @subpackage Loop
413 * @return void
414 */
415 function propertyhive_template_loop_summary() {
416 ph_get_template( 'search/summary.php' );
417 }
418 }
419
420 if ( ! function_exists( 'propertyhive_template_loop_actions' ) ) {
421
422 /**
423 * Get the actions for the loop (ie More Details).
424 *
425 * @access public
426 * @subpackage Loop
427 * @return void
428 */
429 function propertyhive_template_loop_actions() {
430 ph_get_template( 'search/actions.php' );
431 }
432 }
433
434 if ( ! function_exists( 'propertyhive_search_form' ) ) {
435
436 /**
437 * Output the search form
438 *
439 * @access public
440 * @subpackage Loop
441 * @return void
442 */
443 function propertyhive_search_form($id = 'default') {
444 ph_get_search_form( ( $id != '' ) ? $id : 'default' );
445 }
446 }
447
448 if ( ! function_exists( 'propertyhive_result_count' ) ) {
449
450 /**
451 * Output the result count text (Showing x - x of x results).
452 *
453 * @access public
454 * @subpackage Loop
455 * @return void
456 */
457 function propertyhive_result_count( $paged = '', $per_page = null, $total = null, $first = null, $last = null ) {
458 global $wp_query;
459
460 $paged = $paged !== '' ? (int)$paged : max( 1, (int)$wp_query->get( 'paged' ) );
461 $per_page = $per_page !== null ? (int)$per_page : max( 1, (int)$wp_query->get( 'posts_per_page' ) );
462 $total = $total !== null ? (int)$total : (int)$wp_query->found_posts;
463 $first = $first !== null ? (int)$first : ( $per_page * $paged ) - $per_page + 1;
464 $last = $last !== null ? (int)$last : min( $total, $per_page * $paged );
465
466 $args = array(
467 'paged' => $paged,
468 'per_page' => $per_page,
469 'total' => $total,
470 'first' => $first,
471 'last' => $last,
472 );
473
474 ph_get_template( 'search/result-count.php', $args );
475 }
476 }
477
478 if ( ! function_exists( 'propertyhive_catalog_ordering' ) ) {
479
480 /**
481 * Output the property sorting options.
482 *
483 * @access public
484 * @subpackage Loop
485 * @return void
486 */
487 function propertyhive_catalog_ordering( $department = '', $orderby = '' ) {
488
489 if ( $orderby === '' )
490 {
491 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public result ordering; no state change.
492 $orderby = isset( $_GET['orderby'] ) && is_string( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : apply_filters( 'propertyhive_default_search_results_orderby', get_option( 'propertyhive_default_search_results_orderby' ) );
493 }
494
495 $args = array(
496 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only public ordering control; explicit PHP arguments retain precedence.
497 'department' => $department !== '' ? $department : ( isset($_REQUEST['department']) && is_string( $_REQUEST['department'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['department'] ) ) : '' ),
498 'orderby' => $orderby,
499 );
500
501 ph_get_template( 'search/orderby.php', $args );
502 }
503 }
504
505 if ( ! function_exists( 'propertyhive_pagination' ) ) {
506
507 /**
508 * Output the pagination.
509 *
510 * @access public
511 * @subpackage Loop
512 * @return void
513 */
514 function propertyhive_pagination( $max_num_pages = '' ) {
515
516 global $wp_query;
517
518 $args = array(
519 'max_num_pages' => $max_num_pages !== '' ? $max_num_pages : $wp_query->max_num_pages,
520 );
521
522 ph_get_template( 'search/pagination.php', $args );
523 }
524 }
525
526 /** Single Property ********************************************************/
527
528 if ( ! function_exists( 'propertyhive_template_not_on_market' ) ) {
529
530 /**
531 * Output a warning/message if property is not on the market
532 *
533 * @access public
534 * @subpackage Property
535 * @return void
536 */
537 function propertyhive_template_not_on_market() {
538 ph_get_template( 'single-property/not-on-market.php' );
539 }
540 }
541
542 if ( get_option('propertyhive_off_market_behaviour', '') == 'redirect' )
543 {
544 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper ph_redirect_off_market_properties; the established callable name is part of the plugin/extension API and must remain stable.
545 function ph_redirect_off_market_properties()
546 {
547 // If we're viewing an off market property, redirect to the search form
548 if (is_singular('property'))
549 {
550 if ( get_post_meta(get_the_ID(), '_on_market', TRUE) === '' )
551 {
552 if ( !is_user_logged_in() || !current_user_can('administrator') && !current_user_can('editor') )
553 {
554 wp_safe_redirect(get_permalink(ph_get_page_id('search_results')), 301);
555 exit;
556 }
557 }
558 }
559 }
560 add_action( 'template_redirect', 'ph_redirect_off_market_properties', 5 );
561 }
562
563 if ( ! function_exists( 'propertyhive_show_property_images' ) ) {
564
565 /**
566 * Output the property image before the single property summary.
567 *
568 * @access public
569 * @subpackage Property
570 * @return void
571 */
572 function propertyhive_show_property_images( $num_images = '' )
573 {
574 global $property;
575
576 $images = array();
577 if ( get_option('propertyhive_images_stored_as', '') == 'urls' )
578 {
579 $photo_urls = $property->_photo_urls;
580 if ( !is_array($photo_urls) ) { $photo_urls = array(); }
581
582 if ( !empty($num_images) )
583 {
584 $photo_urls = array_slice($photo_urls, 0, $num_images);
585 }
586
587 foreach ( $photo_urls as $photo )
588 {
589 $images[] = array(
590 'title' => isset($photo['title']) ? $photo['title'] : '',
591 'url' => isset($photo['url']) ? $photo['url'] : '',
592 'image' => '<img src="' . esc_url( isset($photo['url']) ? $photo['url'] : '' ) . '" alt="' . esc_attr( isset($photo['title']) ? $photo['title'] : '' ) . '">',
593 );
594 }
595 }
596 else
597 {
598 $gallery_attachments = $property->get_gallery_attachment_ids();
599
600 if ( !empty($gallery_attachments) )
601 {
602 if ( !empty($num_images) )
603 {
604 $gallery_attachments = array_slice($gallery_attachments, 0, $num_images);
605 }
606
607 foreach ($gallery_attachments as $gallery_attachment)
608 {
609 $images[] = array(
610 'title' => esc_attr( get_the_title( $gallery_attachment ) ),
611 'url' => wp_get_attachment_url( $gallery_attachment ),
612 'image' => wp_get_attachment_image( $gallery_attachment, apply_filters( 'propertyhive_single_property_image_size', 'original' ) ),
613 'attachment_id' => $gallery_attachment,
614 );
615 }
616 }
617 }
618
619 ph_get_template( 'single-property/property-images.php', array( 'images' => $images ) );
620 }
621 }
622
623 if ( ! function_exists( 'propertyhive_show_property_thumbnails' ) ) {
624
625 /**
626 * Output the property thumbnails.
627 *
628 * @access public
629 * @subpackage Property
630 * @return void
631 */
632 function propertyhive_show_property_thumbnails() {
633
634 global $property;
635
636 $images = array();
637 if ( get_option('propertyhive_images_stored_as', '') == 'urls' )
638 {
639 $photo_urls = $property->_photo_urls;
640 if ( !is_array($photo_urls) ) { $photo_urls = array(); }
641
642 foreach ( $photo_urls as $photo )
643 {
644 $images[] = array(
645 'title' => isset($photo['title']) ? $photo['title'] : '',
646 'url' => isset($photo['url']) ? $photo['url'] : '',
647 'image' => '<img src="' . esc_url( isset($photo['url']) ? $photo['url'] : '' ) . '" alt="' . esc_attr( isset($photo['title']) ? $photo['title'] : '' ) . '">',
648 );
649 }
650 }
651 else
652 {
653 $gallery_attachments = $property->get_gallery_attachment_ids();
654
655 if ( !empty($gallery_attachments) )
656 {
657 foreach ($gallery_attachments as $gallery_attachment)
658 {
659 $images[] = array(
660 'title' => esc_attr( get_the_title( $gallery_attachment ) ),
661 'url' => wp_get_attachment_url( $gallery_attachment ),
662 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Existing public Property Hive extension hook single_property_small_thumbnail_size; changing the established name would detach installed callbacks.
663 'image' => wp_get_attachment_image( $gallery_attachment, apply_filters( 'single_property_small_thumbnail_size', 'thumbnail' ) ),
664 'attachment_id' => $gallery_attachment,
665 );
666 }
667 }
668 }
669
670 ph_get_template( 'single-property/property-thumbnails.php', array( 'images' => $images ) );
671 }
672 }
673
674 if ( ! function_exists( 'propertyhive_template_single_title' ) ) {
675
676 /**
677 * Output the property title.
678 *
679 * @access public
680 * @subpackage Property
681 * @return void
682 */
683 function propertyhive_template_single_title() {
684 ph_get_template( 'single-property/title.php' );
685 }
686 }
687
688 if ( ! function_exists( 'propertyhive_template_single_floor_area' ) ) {
689
690 /**
691 * Output the property floor area.
692 *
693 * @access public
694 * @subpackage Property
695 * @return void
696 */
697 function propertyhive_template_single_floor_area() {
698 global $property;
699
700 if ( $property->department == 'commercial' || ph_get_custom_department_based_on( $property->department ) == 'commercial' )
701 {
702 ph_get_template( 'single-property/floor-area.php' );
703 }
704 }
705 }
706
707 if ( ! function_exists( 'propertyhive_template_single_price' ) ) {
708
709 /**
710 * Output the property price.
711 *
712 * @access public
713 * @subpackage Property
714 * @return void
715 */
716 function propertyhive_template_single_price() {
717
718 global $property;
719
720 $fees = '';
721 if ( get_option('propertyhive_lettings_fees_display_single_property', '') == 'yes' )
722 {
723 if (
724 $property->department == 'residential-lettings' &&
725 get_option('propertyhive_lettings_fees', '') != ''
726 )
727 {
728 $fees = nl2br(get_option('propertyhive_lettings_fees', ''));
729 }
730 if (
731 $property->department == 'commercial' &&
732 $property->to_rent == 'yes' &&
733 get_option('propertyhive_lettings_fees_commercial', '') != ''
734 )
735 {
736 $fees = nl2br(get_option('propertyhive_lettings_fees_commercial', ''));
737 }
738 }
739
740 $price_qualifier = '';
741 if (
742 (
743 $property->department == 'residential-sales' ||
744 ph_get_custom_department_based_on($property->department) == 'residential-sales' ||
745 $property->department == 'commercial' ||
746 ph_get_custom_department_based_on($property->department) == 'commercial'
747 ) &&
748 $property->price_qualifier != ''
749 )
750 {
751 $price_qualifier = $property->price_qualifier;
752 }
753
754 ph_get_template( 'single-property/price.php', array( 'price_qualifier' => $price_qualifier, 'fees' => $fees ) );
755 }
756 }
757
758 if ( ! function_exists( 'propertyhive_template_single_meta' ) ) {
759
760 /**
761 * Output the product meta.
762 *
763 * @access public
764 * @subpackage Property
765 * @return void
766 */
767 function propertyhive_template_single_meta() {
768
769 global $post, $property;
770
771 $meta = array();
772
773 if ( $property->reference_number != '' )
774 {
775 $meta['reference-number'] = array(
776 'label' => __('Ref', 'propertyhive'),
777 'value' => $property->reference_number
778 );
779 }
780
781 if ( $property->property_type != '' )
782 {
783 $meta['property-type'] = array(
784 'label' => __('Type', 'propertyhive'),
785 'value' => $property->property_type
786 );
787 }
788
789 if ( $property->availability != '' )
790 {
791 $meta['availability'] = array(
792 'label' => __('Availability', 'propertyhive'),
793 'value' => $property->availability
794 );
795 }
796
797 if ( $property->department != 'commercial' && ph_get_custom_department_based_on( $property->department ) != 'commercial' )
798 {
799 if ( $property->bedrooms > 0 )
800 {
801 $meta['bedrooms'] = array(
802 'label' => __('Bedrooms', 'propertyhive'),
803 'value' => $property->bedrooms
804 );
805 }
806
807 if ( $property->bathrooms > 0 )
808 {
809 $meta['bathrooms'] = array(
810 'label' => __('Bathrooms', 'propertyhive'),
811 'value' => $property->bathrooms
812 );
813 }
814
815 if ( $property->reception_rooms > 0 )
816 {
817 $meta['reception-rooms'] = array(
818 'label' => __('Reception Rooms', 'propertyhive'),
819 'value' => $property->reception_rooms
820 );
821 }
822
823 if ( $property->parking != '' )
824 {
825 $meta['parking'] = array(
826 'label' => __('Parking', 'propertyhive'),
827 'value' => $property->parking
828 );
829 }
830
831 if ( $property->outside_space != '' )
832 {
833 $meta['outside-space'] = array(
834 'label' => __('Outside Space', 'propertyhive'),
835 'value' => $property->outside_space
836 );
837 }
838
839 if ( $property->council_tax_band != '' )
840 {
841 $meta['council-tax-band'] = array(
842 'label' => __('Council Tax Band', 'propertyhive'),
843 'value' => $property->council_tax_band
844 );
845 }
846 }
847
848 if ( $property->department == 'residential-sales' || ph_get_custom_department_based_on( $property->department ) == 'residential-sales' )
849 {
850 if ( $property->tenure != '' )
851 {
852 $meta['tenure'] = array(
853 'label' => __('Tenure', 'propertyhive'),
854 'value' => $property->tenure
855 );
856
857 if ( in_array( strtolower($property->tenure), apply_filters('propertyhive_leasehold_tenure_names', array( 'leasehold', 'share of freehold' ) ) ) )
858 {
859 if ( $property->leasehold_years_remaining != '' )
860 {
861 $meta['leasehold-years-remaining'] = array(
862 'label' => __('Leasehold Remaining', 'propertyhive'),
863 'value' => $property->leasehold_years_remaining . ' ' . __( 'years', 'propertyhive' )
864 );
865 }
866
867 if ( $property->ground_rent != '' )
868 {
869 $meta['ground-rent'] = array(
870 'label' => __('Ground Rent', 'propertyhive'),
871 'value' => '&pound;' . ph_display_price_field($property->ground_rent, true)
872 );
873 }
874
875 if ( $property->ground_rent_review_years != '' )
876 {
877 $meta['ground-rent-review-years'] = array(
878 'label' => __('Ground Rent Review Period', 'propertyhive'),
879 'value' => $property->ground_rent_review_years . ' ' . __( 'years', 'propertyhive' )
880 );
881 }
882
883 if ( $property->service_charge != '' )
884 {
885 $meta['service-charge'] = array(
886 'label' => __('Service Charge', 'propertyhive'),
887 'value' => '&pound;' . ph_display_price_field($property->service_charge, true)
888 );
889 }
890
891 if ( $property->service_charge_review_years != '' )
892 {
893 $meta['service-charge-review-years'] = array(
894 'label' => __('Service Charge Review Period', 'propertyhive'),
895 'value' => $property->service_charge_review_years . ' ' . __( 'years', 'propertyhive' )
896 );
897 }
898
899 if ( $property->shared_ownership == 'yes' )
900 {
901 $meta['shared-ownership'] = array(
902 'label' => __('Shared Ownership', 'propertyhive'),
903 'value' => $property->shared_ownership . ( $property->shared_ownership_percentage != '' ? ' (' . $property->shared_ownership_percentage . '%)' : '' )
904 );
905 }
906 }
907 }
908 }
909
910 if ( $property->department == 'residential-lettings' || ph_get_custom_department_based_on( $property->department ) == 'residential-lettings' )
911 {
912 if ( $property->furnished != '' )
913 {
914 $meta['furnished'] = array(
915 'label' => __('Furnished', 'propertyhive'),
916 'value' => $property->furnished
917 );
918 }
919
920 if ( $property->deposit > 0 )
921 {
922 $meta['deposit'] = array(
923 'label' => __('Deposit', 'propertyhive'),
924 'value' => $property->get_formatted_deposit()
925 );
926 }
927
928 if ( $property->available_date != '' )
929 {
930 $meta['available-date'] = array(
931 'label' => __('Available', 'propertyhive'),
932 'value' => $property->get_available_date()
933 );
934 }
935 }
936
937 $meta = apply_filters( 'propertyhive_single_property_meta', $meta );
938
939 ph_get_template( 'single-property/meta.php', array( 'meta' => $meta ) );
940 }
941 }
942
943 if ( ! function_exists( 'propertyhive_template_single_sharing' ) ) {
944
945 /**
946 * Output the product sharing.
947 *
948 * @access public
949 * @subpackage Property
950 * @return void
951 */
952 function propertyhive_template_single_sharing() {
953 ph_get_template( 'single-property/share.php' );
954 }
955 }
956
957 if ( ! function_exists( 'propertyhive_get_template_single_floorplans_action' ) ) {
958
959 function propertyhive_get_template_single_floorplans_action() {
960
961 global $post, $property;
962
963 $actions = array();
964
965 if ( get_option('propertyhive_floorplans_stored_as', '') == 'urls' )
966 {
967 $floorplan_urls = $property->_floorplan_urls;
968 if ( is_array($floorplan_urls) && !empty( $floorplan_urls ) )
969 {
970 foreach ($floorplan_urls as $floorplan)
971 {
972 $actions[] = array(
973 'href' => ( ( isset($floorplan['url']) ) ? $floorplan['url'] : '' ),
974 'label' => __( 'Floorplan', 'propertyhive' ),
975 'class' => 'action-floorplans',
976 'attributes' => array(
977 'data-fancybox' => 'floorplans'
978 )
979 );
980 }
981 }
982 }
983 else
984 {
985 $floorplan_ids = $property->get_floorplan_attachment_ids();
986 if ( !empty( $floorplan_ids ) )
987 {
988 foreach ($floorplan_ids as $floorplan_id)
989 {
990 $label = __( 'Floorplan', 'propertyhive' );
991
992 $attachment_data = wp_prepare_attachment_for_js( $floorplan_id );
993 if ( isset( $attachment_data['caption'] ) && $attachment_data['caption'] != '' )
994 {
995 $label = $attachment_data['caption'];
996 }
997
998
999 $actions[] = array(
1000 'href' => wp_get_attachment_url( $floorplan_id ),
1001 'label' => $label,
1002 'class' => 'action-floorplans',
1003 'attributes' => array(
1004 'data-fancybox' => 'floorplans'
1005 )
1006 );
1007 }
1008 }
1009 }
1010
1011 $actions = apply_filters( 'propertyhive_single_property_floorplans_actions', $actions );
1012
1013 return $actions;
1014 }
1015
1016 }
1017
1018 if ( ! function_exists( 'propertyhive_get_template_single_brochures_action' ) ) {
1019
1020 function propertyhive_get_template_single_brochures_action() {
1021
1022 global $post, $property;
1023
1024 $actions = array();
1025
1026 if ( get_option('propertyhive_brochures_stored_as', '') == 'urls' )
1027 {
1028 $brochure_urls = $property->_brochure_urls;
1029 if ( is_array($brochure_urls) && !empty( $brochure_urls ) )
1030 {
1031 foreach ($brochure_urls as $brochure)
1032 {
1033 $actions[] = array(
1034 'href' => ( ( isset($brochure['url']) ) ? $brochure['url'] : '' ),
1035 'label' => __( 'View Brochure', 'propertyhive' ),
1036 'class' => 'action-brochure',
1037 'attributes' => array(
1038 'target' => '_blank'
1039 )
1040 );
1041 }
1042 }
1043 }
1044 else
1045 {
1046 $brochure_ids = $property->get_brochure_attachment_ids();
1047 if ( !empty( $brochure_ids ) )
1048 {
1049 foreach ($brochure_ids as $brochure_id)
1050 {
1051 $actions[] = array(
1052 'href' => wp_get_attachment_url( $brochure_id ),
1053 'label' => __( 'View Brochure', 'propertyhive' ),
1054 'class' => 'action-brochure',
1055 'attributes' => array(
1056 'target' => '_blank'
1057 )
1058 );
1059 }
1060 }
1061 }
1062
1063 $actions = apply_filters( 'propertyhive_single_property_brochures_actions', $actions );
1064
1065 return $actions;
1066 }
1067
1068 }
1069
1070 if ( ! function_exists( 'propertyhive_get_template_single_epcs_action' ) ) {
1071
1072 function propertyhive_get_template_single_epcs_action() {
1073
1074 global $post, $property;
1075
1076 $actions = array();
1077
1078 if ( get_option('propertyhive_epcs_stored_as', '') == 'urls' )
1079 {
1080 $epc_urls = $property->_epc_urls;
1081 if ( is_array($epc_urls) && !empty( $epc_urls ) )
1082 {
1083 foreach ($epc_urls as $epc)
1084 {
1085 $actions[] = array(
1086 'href' => ( ( isset($epc['url']) ) ? $epc['url'] : '' ),
1087 'label' => __( 'View EPC', 'propertyhive' ),
1088 'class' => 'action-epc',
1089 'attributes' => array(
1090 'target' => '_blank'
1091 )
1092 );
1093 }
1094 }
1095 }
1096 else
1097 {
1098 $epc_ids = $property->get_epc_attachment_ids();
1099 if ( !empty( $epc_ids ) )
1100 {
1101 foreach ($epc_ids as $epc_id)
1102 {
1103 $attributes = array('target' => '_blank');
1104 if ( wp_attachment_is_image($epc_id) )
1105 {
1106 $attributes = array('data-fancybox' => 'epcs');
1107 }
1108 $actions[] = array(
1109 'href' => wp_get_attachment_url( $epc_id ),
1110 'label' => __( 'View EPC', 'propertyhive' ),
1111 'class' => 'action-epc',
1112 'attributes' => $attributes
1113 );
1114 }
1115 }
1116 }
1117
1118 $actions = apply_filters( 'propertyhive_single_property_epcs_actions', $actions );
1119
1120 return $actions;
1121 }
1122
1123 }
1124
1125 if ( ! function_exists( 'propertyhive_get_template_single_virtual_tours_action' ) ) {
1126
1127 function propertyhive_get_template_single_virtual_tours_action() {
1128
1129 global $post, $property;
1130
1131 $actions = array();
1132
1133 $virtual_tours = $property->get_virtual_tours();
1134 if ( !empty( $virtual_tours ) )
1135 {
1136 foreach ($virtual_tours as $virtual_tour)
1137 {
1138 $attributes = array('target' => '_blank');
1139 if ( strpos($virtual_tour['url'], 'yout') !== FALSE || strpos($virtual_tour['url'], 'vimeo') !== FALSE )
1140 {
1141 $attributes['data-fancybox'] = '';
1142 }
1143
1144 $actions[] = array(
1145 'href' => $virtual_tour['url'],
1146 'label' => $virtual_tour['label'],
1147 'class' => 'action-virtual-tour',
1148 'attributes' => $attributes,
1149 );
1150 }
1151 }
1152
1153 $actions = apply_filters( 'propertyhive_single_property_virtual_tours_actions', $actions );
1154
1155 return $actions;
1156 }
1157
1158 }
1159
1160 if ( ! function_exists( 'propertyhive_get_template_single_material_information_action' ) ) {
1161
1162 function propertyhive_get_template_single_material_information_action() {
1163
1164 global $post, $property;
1165
1166 $actions = array();
1167
1168 $material_information = $property->get_material_information();
1169
1170 // Only show if at least one bit of material information has been completed
1171 if ( empty($material_information) )
1172 {
1173 return $actions;
1174 }
1175
1176 $actions[] = array(
1177 'href' => 'javascript:;',
1178 'label' => __( 'Utilities & More', 'propertyhive' ),
1179 'class' => 'action-material-information',
1180 'attributes' => array(
1181 'data-fancybox' => '',
1182 'data-src' => '#ph_material_information'
1183 ),
1184 );
1185
1186 echo '<div id="ph_material_information" style="display:none;">';
1187
1188 ph_get_template( 'single-property/material-information.php' );
1189
1190 echo '</div>';
1191
1192 $actions = apply_filters( 'propertyhive_single_property_material_information_actions', $actions );
1193
1194 return $actions;
1195 }
1196
1197 }
1198
1199 if ( ! function_exists( 'propertyhive_get_template_single_actions' ) ) {
1200
1201 function propertyhive_get_template_single_actions() {
1202
1203 global $post, $property;
1204
1205 $actions = array_merge(
1206 propertyhive_get_template_single_floorplans_action(),
1207 propertyhive_get_template_single_brochures_action(),
1208 propertyhive_get_template_single_epcs_action(),
1209 propertyhive_get_template_single_virtual_tours_action(),
1210 propertyhive_get_template_single_material_information_action(),
1211 );
1212
1213
1214 $actions = apply_filters( 'propertyhive_single_property_actions', $actions );
1215
1216 return $actions;
1217 }
1218
1219 }
1220
1221 if ( ! function_exists( 'propertyhive_template_single_actions' ) ) {
1222
1223 /**
1224 * Output the product actions (make enquiry etc)
1225 *
1226 * @access public
1227 * @subpackage Property
1228 * @return void
1229 */
1230 function propertyhive_template_single_actions() {
1231
1232 global $post, $property;
1233
1234 $actions = propertyhive_get_template_single_actions();
1235
1236 ph_get_template( 'single-property/actions.php', array( 'actions' => $actions ) );
1237 }
1238 }
1239
1240 if ( ! function_exists( 'propertyhive_template_single_features' ) ) {
1241
1242 /**
1243 * Output the property features.
1244 *
1245 * @access public
1246 * @subpackage Property
1247 * @return void
1248 */
1249 function propertyhive_template_single_features() {
1250 ph_get_template( 'single-property/features.php' );
1251 }
1252 }
1253
1254 if ( ! function_exists( 'propertyhive_template_single_summary' ) ) {
1255
1256 /**
1257 * Output the product summary description.
1258 *
1259 * @access public
1260 * @subpackage Property
1261 * @return void
1262 */
1263 function propertyhive_template_single_summary() {
1264 ph_get_template( 'single-property/summary-description.php' );
1265 }
1266 }
1267
1268
1269 if ( ! function_exists( 'propertyhive_template_single_description' ) ) {
1270
1271 /**
1272 * Output the product rooms or descriptions to form a full description
1273 *
1274 * @access public
1275 * @subpackage Property
1276 * @return void
1277 */
1278 function propertyhive_template_single_description() {
1279 ph_get_template( 'single-property/description.php' );
1280 }
1281 }
1282
1283 if ( ! function_exists( 'propertyhive_make_enquiry_button' ) ) {
1284
1285 /**
1286 * Output the make enquiry button and lightbox
1287 *
1288 * @access public
1289 * @subpackage Property
1290 * @return void
1291 */
1292 function propertyhive_make_enquiry_button() {
1293 ph_get_template( 'global/make-enquiry.php' );
1294 }
1295 }
1296
1297 function propertyhive_my_account_pages()
1298 {
1299 $user_id = get_current_user_id();
1300
1301 $contact = new PH_Contact( '', $user_id );
1302
1303 $pages = array(
1304 'dashboard' => array(
1305 'name' => __( 'Dashboard', 'propertyhive' )
1306 ),
1307 'details' => array(
1308 'name' => __( 'My Details', 'propertyhive' )
1309 ),
1310 );
1311
1312 // Add 'requirements' tab if applicant
1313
1314 if ( !empty($contact->contact_types) )
1315 {
1316 $contact_types = $contact->contact_types;
1317 if ( !is_array($contact_types) )
1318 {
1319 $contact_types = array($contact_types);
1320 }
1321 if ( in_array('applicant', $contact_types) )
1322 {
1323 $applicant_profiles = $contact->applicant_profiles;
1324
1325 $buy_rent = array();
1326
1327 if ( $applicant_profiles && $applicant_profiles > 0 )
1328 {
1329 for ( $i = 0; $i < $applicant_profiles; ++$i )
1330 {
1331 $pages['requirements'] = array(
1332 'name' => __( 'Requirements', 'propertyhive' ),
1333 );
1334
1335 $applicant_profile = $contact->{'applicant_profile_' . $i};
1336
1337 if ( isset($applicant_profile['department']) && $applicant_profile['department'] == 'residential-sales' )
1338 {
1339 $buy_rent[] = 'To Buy';
1340 }
1341 if ( isset($applicant_profile['department']) && $applicant_profile['department'] == 'residential-lettings' )
1342 {
1343 $buy_rent[] = 'To Rent';
1344 }
1345 }
1346 }
1347
1348 $buy_rent = array_unique($buy_rent);
1349
1350 // Check viewing module is active and that viewings exist, either future or past
1351 if ( get_option('propertyhive_module_disabled_viewings', '') != 'yes' )
1352 {
1353 $args = array(
1354 'post_type' => 'viewing',
1355 'posts_per_page' => 1,
1356 'post_status' => 'publish',
1357 'fields' => 'ids',
1358 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account page setup tests whether a contact has viewings; the first query and the owner-viewings query both use posts_per_page=1. The result is presence/count only and fields=ids; the owner query’s IN list is derived from the current owner’s properties.
1359 'meta_query' => array(
1360 array(
1361 'key' => '_applicant_contact_id',
1362 'value' => $contact->id
1363 )
1364 )
1365 );
1366 $viewings_query = new WP_Query( $args );
1367
1368 if ( $viewings_query->have_posts() )
1369 {
1370 $pages['applicant_viewings'] = array(
1371 'name' => __( 'Viewings', 'propertyhive' ) . ( !empty($buy_rent) ? ' ' . implode('/', $buy_rent) : '' ),
1372 );
1373 }
1374 wp_reset_postdata();
1375 }
1376 }
1377 if ( in_array('owner', $contact_types) )
1378 {
1379 $sell_let = array();
1380
1381 // Get properties belonging to this owner
1382 $args = array(
1383 'post_type' => 'property',
1384 'nopaging' => true,
1385 'post_status' => 'publish',
1386 'fields' => 'ids',
1387 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1388 'meta_query' => array(
1389 'relation' => 'OR',
1390 array(
1391 'key' => '_owner_contact_id',
1392 'value' => ':' . $contact->id . ';',
1393 'compare' => 'LIKE'
1394 ),
1395 array(
1396 'key' => '_owner_contact_id',
1397 'value' => ':"' . $contact->id . '";',
1398 'compare' => 'LIKE'
1399 )
1400 )
1401 );
1402
1403 $properties_query = new WP_Query( $args );
1404
1405 $property_ids = array();
1406
1407 if ( $properties_query->have_posts() )
1408 {
1409 while ( $properties_query->have_posts() )
1410 {
1411 $properties_query->the_post();
1412
1413 $property_ids[] = get_the_ID();
1414
1415 if ( get_post_meta( get_the_ID(), '_department', TRUE ) == 'residential-sales' )
1416 {
1417 $sell_let[] = 'To Sell';
1418 }
1419 if ( get_post_meta( get_the_ID(), '_department', TRUE ) == 'residential-lettings' )
1420 {
1421 $sell_let[] = 'To Let';
1422 }
1423 }
1424
1425 $pages['owner_properties'] = array(
1426 'name' => __( 'Properties', 'propertyhive' ),
1427 );
1428 }
1429 wp_reset_postdata();
1430
1431 $sell_let = array_unique($sell_let);
1432
1433 // Check viewing module is active and that viewings exist, either future or past
1434 if ( get_option('propertyhive_module_disabled_viewings', '') != 'yes' )
1435 {
1436 $past_viewings = array();
1437 $upcoming_viewings = array();
1438
1439 if ( !empty($property_ids) )
1440 {
1441 $args = array(
1442 'post_type' => 'viewing',
1443 'posts_per_page' => 1,
1444 'post_status' => 'publish',
1445 'fields' => 'ids',
1446 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account page setup tests whether a contact has viewings; the first query and the owner-viewings query both use posts_per_page=1. The result is presence/count only and fields=ids; the owner query’s IN list is derived from the current owner’s properties.
1447 'meta_query' => array(
1448 array(
1449 'key' => '_property_id',
1450 'value' => $property_ids,
1451 'compare' => 'IN'
1452 )
1453 )
1454 );
1455 $viewings_query = new WP_Query( $args );
1456
1457 if ( $viewings_query->have_posts() )
1458 {
1459 $pages['owner_viewings'] = array(
1460 'name' => __( 'Viewings', 'propertyhive' ) . ( !empty($sell_let) ? ' ' . implode('/', $sell_let) : '' ),
1461 );
1462 }
1463 wp_reset_postdata();
1464 }
1465 }
1466 }
1467 }
1468
1469 $pages = apply_filters( 'propertyhive_my_account_pages', $pages );
1470
1471 /*$pages['delete'] = array(
1472 'name' => __( 'Delete Account', 'propertyhive' )
1473 );*/
1474
1475 $pages['logout'] = array(
1476 'name' => __( 'Logout', 'propertyhive' ),
1477 'href' => wp_nonce_url( add_query_arg( 'logout', '1', home_url( '/' ) ), 'log-out' ) // Logout URL
1478 );
1479
1480 return $pages;
1481 }
1482
1483 if ( ! function_exists( 'propertyhive_my_account_navigation' ) ) {
1484
1485 /**
1486 * Output the navigation/tabs within a users 'My Account' page
1487 *
1488 * @access public
1489 * @return void
1490 */
1491 function propertyhive_my_account_navigation() {
1492
1493 $pages = propertyhive_my_account_pages();
1494
1495 ph_get_template( 'account/navigation.php', array( 'pages' => $pages ) );
1496 }
1497 }
1498
1499 if ( ! function_exists( 'propertyhive_my_account_sections' ) ) {
1500
1501 /**
1502 * Output the main sections within a users 'My Account' page that relate to the navigation tabs/links
1503 *
1504 * @access public
1505 * @return void
1506 */
1507 function propertyhive_my_account_sections() {
1508
1509 $pages = propertyhive_my_account_pages();
1510
1511 ph_get_template( 'account/sections.php', array( 'pages' => $pages ) );
1512 }
1513 }
1514
1515 if ( ! function_exists( 'propertyhive_my_account_dashboard' ) ) {
1516
1517 /**
1518 * Output the dashboard section within a users account
1519 *
1520 * @access public
1521 * @return void
1522 */
1523 function propertyhive_my_account_dashboard() {
1524
1525 ph_get_template( 'account/dashboard.php' );
1526 }
1527 }
1528
1529 if ( ! function_exists( 'propertyhive_my_account_details' ) ) {
1530
1531 /**
1532 * Output the details section within a users account
1533 *
1534 * @access public
1535 * @return void
1536 */
1537 function propertyhive_my_account_details() {
1538
1539 $form_controls = ph_get_user_details_form_fields();
1540
1541 $form_controls = apply_filters( 'propertyhive_user_details_form_fields', $form_controls );
1542
1543 // Make sure password fields aren't require
1544 foreach ( $form_controls as $i => $form_control )
1545 {
1546 if ( $form_control['type'] == 'password' )
1547 {
1548 $form_control['required'] = false;
1549
1550 $form_controls[$i] = $form_control;
1551 }
1552 }
1553
1554 ph_get_template( 'account/details.php', array( 'form_controls' => $form_controls ) );
1555 }
1556 }
1557
1558 if ( ! function_exists( 'propertyhive_my_account_requirements' ) ) {
1559
1560 /**
1561 * Output the requirements section within a users account
1562 *
1563 * @access public
1564 * @return void
1565 */
1566 function propertyhive_my_account_requirements() {
1567
1568 $user_id = get_current_user_id();
1569
1570 $contact = new PH_Contact( '', $user_id );
1571
1572 if ( is_array($contact->contact_types) && in_array('applicant', $contact->contact_types) )
1573 {
1574 $applicant_profiles = $contact->applicant_profiles;
1575
1576 for ( $i = 0; $i < $applicant_profiles; ++$i )
1577 {
1578 $form_controls = ph_get_applicant_requirements_form_fields($contact->{'applicant_profile_' . $i});
1579
1580 $form_controls = apply_filters( 'propertyhive_applicant_requirements_form_fields', $form_controls, $contact->{'applicant_profile_' . $i} );
1581
1582 $form_controls['profile_id'] = array(
1583 'type' => 'hidden',
1584 'value' => $i,
1585 );
1586
1587 // Remove office as this is only required on initial sign up (at the moment anyway)
1588 if ( isset($form_controls['office_id']) )
1589 {
1590 unset($form_controls['office_id']);
1591 }
1592
1593 ph_get_template( 'account/requirements.php', array( 'form_controls' => $form_controls ) );
1594 }
1595 }
1596 }
1597 }
1598
1599 if ( ! function_exists( 'propertyhive_my_account_applicant_viewings' ) ) {
1600
1601 /**
1602 * Output the applicant viewings section within a users account
1603 *
1604 * @access public
1605 * @return void
1606 */
1607 function propertyhive_my_account_applicant_viewings() {
1608
1609 $user_id = get_current_user_id();
1610
1611 $contact = new PH_Contact( '', $user_id );
1612
1613 $past_viewings = array();
1614 $upcoming_viewings = array();
1615
1616 $args = array(
1617 'post_type' => 'viewing',
1618 'nopaging' => 'true',
1619 'post_status' => 'publish',
1620 'fields' => 'ids',
1621 'orderby' => 'meta_value',
1622 'order' => 'DESC',
1623 'post_status' => 'publish',
1624 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1625 'meta_key' => '_start_date_time',
1626 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1627 'meta_query' => array(
1628 array(
1629 'key' => '_applicant_contact_id',
1630 'value' => $contact->id
1631 )
1632 )
1633 );
1634
1635 // Do past viewings
1636 $args2 = $args;
1637 $args2['meta_query'][] = array(
1638 'key' => '_start_date_time',
1639 'value' => gmdate("Y-m-d H:i:s"),
1640 'compare' => '<='
1641 );
1642
1643 $viewings_query = new WP_Query( $args2 );
1644
1645 if ( $viewings_query->have_posts() )
1646 {
1647 while ( $viewings_query->have_posts() )
1648 {
1649 $viewings_query->the_post();
1650
1651 $viewing = new PH_Viewing( get_the_ID() );
1652
1653 $past_viewings[] = $viewing;
1654 }
1655 }
1656 wp_reset_postdata();
1657
1658 // Do upcoming viewings
1659 $args2 = $args;
1660 $args2['meta_query'][] = array(
1661 'key' => '_start_date_time',
1662 'value' => gmdate("Y-m-d H:i:s"),
1663 'compare' => '>='
1664 );
1665
1666 $viewings_query = new WP_Query( $args2 );
1667
1668 if ( $viewings_query->have_posts() )
1669 {
1670 while ( $viewings_query->have_posts() )
1671 {
1672 $viewings_query->the_post();
1673
1674 $viewing = new PH_Viewing( get_the_ID() );
1675
1676 $upcoming_viewings[] = $viewing;
1677 }
1678 }
1679 wp_reset_postdata();
1680
1681 ph_get_template( 'account/applicant-viewings.php', array( 'past_viewings' => $past_viewings, 'upcoming_viewings' => $upcoming_viewings ) );
1682 }
1683 }
1684
1685 if ( ! function_exists( 'propertyhive_my_account_owner_properties' ) ) {
1686
1687 /**
1688 * Output the owner properties section within a users account
1689 *
1690 * @access public
1691 * @return void
1692 */
1693 function propertyhive_my_account_owner_properties() {
1694
1695 $user_id = get_current_user_id();
1696
1697 $contact = new PH_Contact( '', $user_id );
1698
1699 // Get properties belonging to this owner
1700 $args = array(
1701 'post_type' => 'property',
1702 'nopaging' => true,
1703 'post_status' => 'publish',
1704 'fields' => 'ids',
1705 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1706 'meta_query' => array(
1707 'relation' => 'OR',
1708 array(
1709 'key' => '_owner_contact_id',
1710 'value' => ':' . $contact->id . ';',
1711 'compare' => 'LIKE'
1712 ),
1713 array(
1714 'key' => '_owner_contact_id',
1715 'value' => ':"' . $contact->id . '";',
1716 'compare' => 'LIKE'
1717 )
1718 )
1719 );
1720
1721 $properties_query = new WP_Query( $args );
1722
1723 $properties = array();
1724
1725 if ( $properties_query->have_posts() )
1726 {
1727 while ( $properties_query->have_posts() )
1728 {
1729 $properties_query->the_post();
1730
1731 $properties[] = new PH_Property( get_the_id() );
1732 }
1733 }
1734 wp_reset_postdata();
1735 ph_get_template( 'account/owner-properties.php', array( 'properties' => $properties ) );
1736 }
1737 }
1738
1739 if ( ! function_exists( 'propertyhive_my_account_owner_viewings' ) ) {
1740
1741 /**
1742 * Output the owner viewings section within a users account
1743 *
1744 * @access public
1745 * @return void
1746 */
1747 function propertyhive_my_account_owner_viewings() {
1748
1749 $user_id = get_current_user_id();
1750
1751 $contact = new PH_Contact( '', $user_id );
1752
1753 // Get properties belonging to this owner
1754 $args = array(
1755 'post_type' => 'property',
1756 'nopaging' => true,
1757 'post_status' => 'publish',
1758 'fields' => 'ids',
1759 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1760 'meta_query' => array(
1761 'relation' => 'OR',
1762 array(
1763 'key' => '_owner_contact_id',
1764 'value' => ':' . $contact->id . ';',
1765 'compare' => 'LIKE'
1766 ),
1767 array(
1768 'key' => '_owner_contact_id',
1769 'value' => ':"' . $contact->id . '";',
1770 'compare' => 'LIKE'
1771 )
1772 )
1773 );
1774
1775 $properties_query = new WP_Query( $args );
1776
1777 $property_ids = array();
1778
1779 if ( $properties_query->have_posts() )
1780 {
1781 while ( $properties_query->have_posts() )
1782 {
1783 $properties_query->the_post();
1784
1785 $property_ids[] = get_the_id();
1786 }
1787 }
1788 wp_reset_postdata();
1789
1790 $past_viewings = array();
1791 $upcoming_viewings = array();
1792
1793 if ( !empty($property_ids) )
1794 {
1795 $args = array(
1796 'post_type' => 'viewing',
1797 'nopaging' => true,
1798 'post_status' => 'publish',
1799 'fields' => 'ids',
1800 'orderby' => 'meta_value',
1801 'order' => 'DESC',
1802 'post_status' => 'publish',
1803 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1804 'meta_key' => '_start_date_time',
1805 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Account query is scoped to the current contact or their owned property IDs; these legacy relationship/date meta keys are required to return the complete account history using WordPress query APIs.
1806 'meta_query' => array(
1807 array(
1808 'key' => '_property_id',
1809 'value' => $property_ids,
1810 'compare' => 'IN'
1811 )
1812 )
1813 );
1814
1815 // Do past viewings
1816 $args2 = $args;
1817 $args2['meta_query'][] = array(
1818 'key' => '_start_date_time',
1819 'value' => gmdate("Y-m-d H:i:s"),
1820 'compare' => '<='
1821 );
1822
1823 $viewings_query = new WP_Query( $args2 );
1824
1825 if ( $viewings_query->have_posts() )
1826 {
1827 while ( $viewings_query->have_posts() )
1828 {
1829 $viewings_query->the_post();
1830
1831 $viewing = new PH_Viewing( get_the_ID() );
1832
1833 $past_viewings[] = $viewing;
1834 }
1835 }
1836 wp_reset_postdata();
1837
1838 // Do upcoming viewings
1839 $args2 = $args;
1840 $args2['meta_query'][] = array(
1841 'key' => '_start_date_time',
1842 'value' => gmdate("Y-m-d H:i:s"),
1843 'compare' => '>='
1844 );
1845
1846 $viewings_query = new WP_Query( $args2 );
1847
1848 if ( $viewings_query->have_posts() )
1849 {
1850 while ( $viewings_query->have_posts() )
1851 {
1852 $viewings_query->the_post();
1853
1854 $viewing = new PH_Viewing( get_the_ID() );
1855
1856 $upcoming_viewings[] = $viewing;
1857 }
1858 }
1859 wp_reset_postdata();
1860 }
1861
1862 ph_get_template( 'account/owner-viewings.php', array( 'past_viewings' => $past_viewings, 'upcoming_viewings' => $upcoming_viewings ) );
1863 }
1864 }
1865
1866 if ( ! function_exists( 'propertyhive_my_account_delete' ) ) {
1867
1868 /**
1869 * Output the delete section within a users account
1870 *
1871 * @access public
1872 * @return void
1873 */
1874 function propertyhive_my_account_delete() {
1875
1876 ph_get_template( 'account/delete.php' );
1877 }
1878 }
1879
1880 add_filter( 'loop_search_results_per_page', 'template_assistant_loop_search_results_per_page', 1 );
1881 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_loop_search_results_per_page; the established callable name is part of the plugin/extension API and must remain stable.
1882 function template_assistant_loop_search_results_per_page( $cols )
1883 {
1884 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1885
1886 if ( isset($current_settings['search_result_columns']) && in_array($current_settings['search_result_columns'], array(3,4)) )
1887 {
1888 return 12;
1889 }
1890
1891 return $cols;
1892 }
1893
1894 add_filter( 'loop_search_results_columns', 'template_assistant_search_result_columns', 1 );
1895 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_search_result_columns; the established callable name is part of the plugin/extension API and must remain stable.
1896 function template_assistant_search_result_columns( $cols = 1 )
1897 {
1898 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1899
1900 if ( isset($current_settings['search_result_columns']) && in_array($current_settings['search_result_columns'], array(1,2,3,4)) )
1901 {
1902 return $current_settings['search_result_columns'];
1903 }
1904
1905 return 1;
1906 }
1907
1908 add_filter( 'post_class', 'template_assistant_property_columns_post_class', 20, 3 );
1909 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_property_columns_post_class; the established callable name is part of the plugin/extension API and must remain stable.
1910 function template_assistant_property_columns_post_class( $classes, $class = '', $post_id = '' )
1911 {
1912 if ( ! $post_id || get_post_type( $post_id ) !== 'property' )
1913 return $classes;
1914
1915 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1916
1917 if ( isset($current_settings['search_result_columns']) && in_array($current_settings['search_result_columns'], array(2,3,4)) )
1918 {
1919 $property = get_property( $post_id );
1920
1921 if ( $property )
1922 {
1923 $classes[] = 'ph-cols-' . $current_settings['search_result_columns'];
1924
1925 if ( ($key = array_search('clear', $classes)) !== false )
1926 {
1927 unset($classes[$key]);
1928 }
1929 }
1930 }
1931
1932 return $classes;
1933 }
1934
1935 add_action( 'wp_head', 'load_template_assistant_styles' );
1936 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper load_template_assistant_styles; the established callable name is part of the plugin/extension API and must remain stable.
1937 function load_template_assistant_styles()
1938 {
1939 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1940
1941 if (
1942 is_post_type_archive('property')
1943 ||
1944 ( isset($current_settings['search_result_css_all_pages']) && $current_settings['search_result_css_all_pages'] == 'yes' )
1945 )
1946 {
1947 if ( isset( $current_settings['search_result_css'] ) && is_string( $current_settings['search_result_css'] ) )
1948 {
1949 // Escape HTML's raw-text terminator without stripping valid stylesheet syntax.
1950 $css = preg_replace_callback( '~</style~i', static function( $match ) {
1951 return '<\\/' . substr( $match[0], 2 );
1952 }, $current_settings['search_result_css'] );
1953 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Privileged custom stylesheet: closing style tags are escaped above; HTML escaping would corrupt valid CSS strings and selectors.
1954 echo '<style type="text/css">' . $css . '</style>';
1955 }
1956 }
1957 }
1958
1959 add_filter( 'propertyhive_default_search_results_orderby', 'template_assistant_change_default_order' );
1960 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_change_default_order; the established callable name is part of the plugin/extension API and must remain stable.
1961 function template_assistant_change_default_order( $orderby )
1962 {
1963 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1964
1965 if ( isset($current_settings['search_result_default_order']) && $current_settings['search_result_default_order'] != '' )
1966 {
1967 return $current_settings['search_result_default_order'];
1968 }
1969
1970 return $orderby;
1971 }
1972
1973 add_filter( 'property_search_results_thumbnail_size', 'template_assistant_search_result_image_size_changes' );
1974 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_search_result_image_size_changes; the established callable name is part of the plugin/extension API and must remain stable.
1975 function template_assistant_search_result_image_size_changes( $image_size )
1976 {
1977 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1978
1979 if ( isset($current_settings['search_result_image_size']) && $current_settings['search_result_image_size'] != '' )
1980 {
1981 $image_size = $current_settings['search_result_image_size'];
1982 }
1983
1984 return $image_size;
1985 }
1986
1987 add_action( 'wp', 'template_assistant_search_result_field_changes' );
1988 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound -- Legacy public global helper template_assistant_search_result_field_changes; the established callable name is part of the plugin/extension API and must remain stable.
1989 function template_assistant_search_result_field_changes()
1990 {
1991 $current_settings = get_option( 'propertyhive_template_assistant', array() );
1992
1993 if ( isset($current_settings['search_result_fields']) && is_array($current_settings['search_result_fields']) && !empty($current_settings['search_result_fields']) )
1994 {
1995 remove_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_floor_area', 5 );
1996 remove_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_price', 10 );
1997 remove_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_summary', 20 );
1998 remove_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_actions', 30 );
1999
2000 $priority = 5;
2001 foreach ( $current_settings['search_result_fields'] as $search_result_field )
2002 {
2003 if ( substr($search_result_field, 0, 12) == 'custom_field' )
2004 {
2005 // custom field output here
2006 $custom_field = substr($search_result_field, 12);
2007
2008 add_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_custom_field', $priority );
2009
2010 $priority += 5;
2011 continue;
2012 }
2013
2014 switch ( $search_result_field )
2015 {
2016 case "price":
2017 case "floor_area":
2018 case "summary":
2019 case "actions":
2020 {
2021 add_action( 'propertyhive_after_search_results_loop_item_title', 'propertyhive_template_loop_' . $search_result_field, $priority );
2022 break;
2023 }
2024 case "availability":
2025 {
2026 add_action( 'propertyhive_after_search_results_loop_item_title', function() { global $property; echo '<div class="availability">' . esc_html( $property->availability ) . '</div>'; }, $priority );
2027 break;
2028 }
2029 case "property_type":
2030 {
2031 add_action( 'propertyhive_after_search_results_loop_item_title', function() { global $property; echo '<div class="property-type">' . esc_html( $property->property_type ) . '</div>'; }, $priority );
2032 break;
2033 }
2034 case "available_date":
2035 {
2036 add_action( 'propertyhive_after_search_results_loop_item_title', function() { global $property; if ( $property->department == 'residential-lettings' && $property->get_available_date() != '' ) { echo '<div class="available-date">' . esc_html( $property->get_available_date() ) . '</div>'; } }, $priority );
2037 break;
2038 }
2039 case "rooms":
2040 {
2041 add_action( 'propertyhive_after_search_results_loop_item_title', function() {
2042 global $property;
2043
2044 if ( ($property->bedrooms != '' && $property->bedrooms != '0') || ($property->bathrooms != '' && $property->bathrooms != '0') || ($property->reception_rooms != '' && $property->reception_rooms != '0') )
2045 {
2046 echo '<div class="rooms">';
2047 if ( $property->bedrooms != '' && $property->bedrooms != '0' ) { echo '<div class="room room-bedrooms"><span class="room-count">' . esc_html( $property->bedrooms ) . '</span> <span class="room-label">Bedroom' . ( $property->bedrooms != 1 ? 's' : '' ) . '</span></div>'; }
2048 if ( $property->bathrooms != '' && $property->bathrooms != '0' ) { echo '<div class="room room-bathrooms"><span class="room-count">' . esc_html( $property->bathrooms ) . '</span> <span class="room-label">Bathroom' . ( $property->bathrooms != 1 ? 's' : '' ) . '</span></div>'; }
2049 if ( $property->reception_rooms != '' && $property->reception_rooms != '0' ) { echo '<div class="room room-receptions"><span class="room-count">' . esc_html( $property->reception_rooms ) . '</span> <span class="room-label">Reception' . ( $property->reception_rooms != 1 ? 's' : '' ) . '</span></div>'; }
2050 echo '</div>';
2051 }
2052 }, $priority );
2053 break;
2054 }
2055 default:
2056 {
2057 echo 'unknown search result field requested';
2058 }
2059 }
2060
2061 $priority += 5;
2062 }
2063 }
2064 }
2065
2066 function propertyhive_template_loop_custom_field()
2067 {
2068 global $property;
2069
2070 $current_settings = get_option( 'propertyhive_template_assistant', array() );
2071
2072 foreach ( $current_settings['search_result_fields'] as $search_result_field )
2073 {
2074 if ( substr($search_result_field, 0, 12) == 'custom_field' )
2075 {
2076 // custom field output here
2077 $custom_field = substr($search_result_field, 12);
2078
2079 $value = $property->{$custom_field};
2080 $value = is_array($value) ? implode(", ", $value) : $value;
2081
2082 if ( $value != '' )
2083 {
2084 echo '<div class="custom-field custom-field-' . esc_attr( sanitize_title(trim($custom_field, "_")) ) . '">' . wp_kses_post( $value ) . '</div>';
2085 }
2086 }
2087 }
2088 }
2089
2090 /**
2091 * Sanitize configurable flag CSS while retaining CSS color functions.
2092 */
2093 function propertyhive_get_flag_custom_style( $settings ) {
2094 $css = ( isset( $settings['flag_position'] ) && is_string( $settings['flag_position'] ) ? $settings['flag_position'] : '' );
2095 foreach ( array( 'flag_text_color' => 'color', 'flag_bg_color' => 'background' ) as $key => $property_name ) {
2096 if ( isset( $settings[ $key ] ) && is_string( $settings[ $key ] ) ) {
2097 $css .= ';' . $property_name . ':' . $settings[ $key ];
2098 }
2099 }
2100 $allow_color = static function( $allowed, $declaration ) {
2101 // The only parentheses accepted here enclose an RGB/HSL color value.
2102 return $allowed || 1 === preg_match( '/^(?:color|background):\s*(?:rgba?|hsla?)\([0-9a-z\s.,%+\-\/]*\)(?:\s*!important)?$/i', $declaration );
2103 };
2104 add_filter( 'safecss_filter_attr_allow_css', $allow_color, 10, 2 );
2105 try {
2106 return safecss_filter_attr( $css );
2107 } finally {
2108 remove_filter( 'safecss_filter_attr_allow_css', $allow_color, 10 );
2109 }
2110 }
2111
2112 add_action( 'propertyhive_before_search_results_loop_item_title', 'propertyhive_add_flag' );
2113 function propertyhive_add_flag()
2114 {
2115 global $property;
2116
2117 $current_settings = get_option( 'propertyhive_template_assistant', array() );
2118
2119 if ( isset($current_settings['flags_active']) && $current_settings['flags_active'] == '1' )
2120 {
2121 $flag = propertyhive_get_flag();
2122
2123 if ( $flag != '' )
2124 {
2125 echo '<div class="flag flag-' . esc_attr( sanitize_title($flag) ) . '" style="' . esc_attr( 'position:absolute; text-transform:uppercase; font-size:13px; box-sizing:border-box; padding:7px 20px; ' . propertyhive_get_flag_custom_style( $current_settings ) ) . '">' . esc_html( $flag ) . '</div>';
2126 }
2127 }
2128 }
2129
2130 add_action( 'propertyhive_before_single_property_images', 'propertyhive_add_flag_single', 5 );
2131 function propertyhive_add_flag_single()
2132 {
2133 global $property;
2134
2135 $current_settings = get_option( 'propertyhive_template_assistant', array() );
2136
2137 if ( isset($current_settings['flags_active_single']) && $current_settings['flags_active_single'] == '1' )
2138 {
2139 $flag = propertyhive_get_flag();
2140
2141 if ( $flag != '' )
2142 {
2143 echo '<div class="flag flag-' . esc_attr( sanitize_title($flag) ) . '" style="' . esc_attr( 'position:absolute; z-index:99; text-transform:uppercase; font-size:13px; box-sizing:border-box; padding:7px 20px; ' . propertyhive_get_flag_custom_style( $current_settings ) ) . '">' . esc_html( $flag ) . '</div>';
2144 }
2145 }
2146 }
2147
2148 function propertyhive_get_flag()
2149 {
2150 global $property;
2151
2152 $flag = $property->availability;
2153
2154 if ( $property->marketing_flag != '' )
2155 {
2156 $flag = $property->marketing_flag;
2157 }
2158
2159 $flag = apply_filters( 'propertyhive_template_assistant_flag', $flag );
2160
2161 return $flag;
2162 }
2163
2164
2165
2166