PluginProbe
Property Hive / 2.3.1
Property Hive v2.3.1
2.3.1 2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 All 261 releases
propertyhive / includes / elementor-widgets / property-tabbed-details.php

property-tabbed-details.php in Property Hive 2.3.1, at includes/elementor-widgets/property-tabbed-details.php

931 lines 28.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Elementor Property Tabbed Details Widget.
4 *
5 * @since 1.0.0
6 */
7 class Elementor_Property_Tabbed_Details_Widget extends \Elementor\Widget_Base {
8
9 public function get_name() {
10 return 'property-tabbed-details';
11 }
12
13 public function get_title() {
14 return __( 'Tabbed Details', 'propertyhive' );
15 }
16
17 public function get_icon() {
18 return 'eicon-tabs';
19 }
20
21 public function get_categories() {
22 return [ 'property-hive' ];
23 }
24
25 public function get_keywords() {
26 return [ 'property hive', 'propertyhive', 'property', 'tab', 'tabs', 'tabbed' ];
27 }
28
29 public function get_style_depends(): array {
30 return [ 'widget-tabs' ];
31 }
32
33 protected function register_controls() {
34
35 $this->start_controls_section(
36 'section_tabs',
37 [
38 'label' => __( 'Tabs', 'propertyhive' ),
39 ]
40 );
41
42 $this->add_control(
43 'type',
44 [
45 'label' => __( 'Type', 'propertyhive' ),
46 'type' => \Elementor\Controls_Manager::SELECT,
47 'default' => 'horizontal',
48 'options' => [
49 'horizontal' => __( 'Horizontal', 'propertyhive' ),
50 'vertical' => __( 'Vertical', 'propertyhive' ),
51 ],
52 'prefix_class' => 'elementor-widget-tabs elementor-tabs-view-',
53 ]
54 );
55
56 $this->add_control(
57 'property_tabs',
58 [
59 'label' => __( 'Tabs Items', 'propertyhive' ),
60 'type' => \Elementor\Controls_Manager::REPEATER,
61 'default' => [
62 [
63 'tab_title' => __( 'Details', 'propertyhive' ),
64 'tab_display' => array('features', 'summary_description', 'full_description'),
65 ],
66 [
67 'tab_title' => __( 'Floorplan', 'propertyhive' ),
68 'tab_display' => array('floorplan'),
69 ],
70 [
71 'tab_title' => __( 'Brochure', 'propertyhive' ),
72 'tab_display' => array('brochure'),
73 ],
74 [
75 'tab_title' => __( 'EPC', 'propertyhive' ),
76 'tab_display' => array('epc'),
77 ],
78 [
79 'tab_title' => __( 'Virtual Tour', 'propertyhive' ),
80 'tab_display' => array('embedded_virtual_tour'),
81 ],
82 [
83 'tab_title' => __( 'Map View', 'propertyhive' ),
84 'tab_display' => array('map'),
85 ],
86 [
87 'tab_title' => __( 'Street View', 'propertyhive' ),
88 'tab_display' => array('street_view'),
89 ],
90 [
91 'tab_title' => __( 'Make Enquiry', 'propertyhive' ),
92 'tab_display' => array('make_enquiry'),
93 ],
94 ],
95 'fields' => [
96 [
97 'name' => 'tab_title',
98 'label' => __( 'Title', 'propertyhive' ),
99 'type' => \Elementor\Controls_Manager::TEXT,
100 'default' => __( 'Tab Title', 'propertyhive' ),
101 'placeholder' => __( 'Tab Title', 'propertyhive' ),
102 'label_block' => true,
103 ],
104 [
105 'name' => 'tab_display',
106 'label' => __( 'Display', 'propertyhive' ),
107 'type' => \Elementor\Controls_Manager::SELECT2,
108 'multiple' => true,
109 'default' => array(),
110 'label_block' => true,
111 'options' => apply_filters( 'propertyhive_elementor_tabbed_details_display_options', array(
112 'features' => __( 'Features', 'propertyhive' ),
113 'summary_description' => __( 'Summary Description', 'propertyhive' ),
114 'full_description' => __( 'Full Description', 'propertyhive' ),
115 'gallery' => __( 'Gallery', 'propertyhive' ),
116 'floorplan' => __( 'Floorplans', 'propertyhive' ),
117 'brochure' => __( 'Brochures', 'propertyhive' ),
118 'epc' => __( 'EPCs', 'propertyhive' ),
119 'virtual_tour' => __( 'Virtual Tour Links', 'propertyhive' ),
120 'embedded_virtual_tour' => __( 'Virtual Tours Embedded', 'propertyhive' ),
121 'map' => __( 'Map View', 'propertyhive' ),
122 'street_view' => __( 'Street View', 'propertyhive' ),
123 'make_enquiry' => __( 'Make Enquiry Form', 'propertyhive' ),
124 'content' => __( 'Other Content', 'propertyhive' ),
125 ) )
126 ],
127 [
128 'name' => 'tab_content',
129 'label' => __( 'Other Content', 'propertyhive' ),
130 'type' => \Elementor\Controls_Manager::WYSIWYG,
131 'dynamic' => [ 'active' => true ],
132 'label_block' => true,
133 'conditions' => [
134 'terms' => [
135 [
136 'name' => 'tab_display',
137 'operator' => 'contains',
138 'value' => 'content',
139 ],
140 ],
141 ],
142 ],
143 ],
144 'title_field' => '{{{ tab_title }}}',
145 ]
146 );
147
148 $this->end_controls_section();
149
150 $this->start_controls_section(
151 'section_tabs_style',
152 [
153 'label' => __( 'Tabs', 'propertyhive' ),
154 'tab' => \Elementor\Controls_Manager::TAB_STYLE,
155 ]
156 );
157
158 $this->add_control(
159 'navigation_width',
160 [
161 'label' => __( 'Navigation Width', 'propertyhive' ),
162 'type' => \Elementor\Controls_Manager::SLIDER,
163 'default' => [
164 'unit' => '%',
165 ],
166 'range' => [
167 '%' => [
168 'min' => 10,
169 'max' => 50,
170 ],
171 ],
172 'selectors' => [
173 '{{WRAPPER}} .elementor-tabs-wrapper' => 'width: {{SIZE}}{{UNIT}}',
174 ],
175 'condition' => [
176 'type' => 'vertical',
177 ],
178 ]
179 );
180
181 $this->add_control(
182 'border_width',
183 [
184 'label' => __( 'Border Width', 'propertyhive' ),
185 'type' => \Elementor\Controls_Manager::SLIDER,
186 'default' => [
187 'size' => 1,
188 ],
189 'range' => [
190 'px' => [
191 'min' => 0,
192 'max' => 10,
193 ],
194 ],
195 'selectors' => [
196 '{{WRAPPER}} .elementor-tab-title, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-width: {{SIZE}}{{UNIT}};',
197 ],
198 ]
199 );
200
201 $this->add_control(
202 'border_color',
203 [
204 'label' => __( 'Border Color', 'propertyhive' ),
205 'type' => \Elementor\Controls_Manager::COLOR,
206 'selectors' => [
207 '{{WRAPPER}} .elementor-tab-mobile-title, {{WRAPPER}} .elementor-tab-desktop-title.elementor-active, {{WRAPPER}} .elementor-tab-title:before, {{WRAPPER}} .elementor-tab-title:after, {{WRAPPER}} .elementor-tab-content, {{WRAPPER}} .elementor-tabs-content-wrapper' => 'border-color: {{VALUE}};',
208 ],
209 ]
210 );
211
212 $this->add_control(
213 'background_color',
214 [
215 'label' => __( 'Background Color', 'propertyhive' ),
216 'type' => \Elementor\Controls_Manager::COLOR,
217 'selectors' => [
218 '{{WRAPPER}} .elementor-tab-desktop-title.elementor-active' => 'background-color: {{VALUE}};',
219 '{{WRAPPER}} .elementor-tabs-content-wrapper' => 'background-color: {{VALUE}};',
220 ],
221 ]
222 );
223
224 $this->add_control(
225 'heading_title',
226 [
227 'label' => __( 'Title', 'propertyhive' ),
228 'type' => \Elementor\Controls_Manager::HEADING,
229 'separator' => 'before',
230 ]
231 );
232
233 $this->add_control(
234 'tab_color',
235 [
236 'label' => __( 'Color', 'propertyhive' ),
237 'type' => \Elementor\Controls_Manager::COLOR,
238 'selectors' => [
239 '{{WRAPPER}} .elementor-tab-title' => 'color: {{VALUE}};',
240 ],
241 'global' => [
242 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_PRIMARY,
243 ],
244 ]
245 );
246
247 $this->add_control(
248 'tab_active_color',
249 [
250 'label' => __( 'Active Color', 'propertyhive' ),
251 'type' => \Elementor\Controls_Manager::COLOR,
252 'selectors' => [
253 '{{WRAPPER}} .elementor-tab-title.elementor-active' => 'color: {{VALUE}};',
254 ],
255 'global' => [
256 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_ACCENT,
257 ],
258 ]
259 );
260
261 $this->add_group_control(
262 \Elementor\Group_Control_Typography::get_type(),
263 [
264 'name' => 'tab_typography',
265 'selector' => '{{WRAPPER}} .elementor-tab-title',
266 'global' => [
267 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_PRIMARY,
268 ],
269 ]
270 );
271
272 $this->add_control(
273 'heading_content',
274 [
275 'label' => __( 'Content', 'propertyhive' ),
276 'type' => \Elementor\Controls_Manager::HEADING,
277 'separator' => 'before',
278 ]
279 );
280
281 $this->add_control(
282 'content_color',
283 [
284 'label' => __( 'Color', 'propertyhive' ),
285 'type' => \Elementor\Controls_Manager::COLOR,
286 'selectors' => [
287 '{{WRAPPER}} .elementor-tab-content' => 'color: {{VALUE}};',
288 ],
289 'global' => [
290 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Colors::COLOR_TEXT,
291 ],
292 ]
293 );
294
295 $this->add_group_control(
296 \Elementor\Group_Control_Typography::get_type(),
297 [
298 'name' => 'content_typography',
299 'selector' => '{{WRAPPER}} .elementor-tab-content',
300 'global' => [
301 'default' => \Elementor\Core\Kits\Documents\Tabs\Global_Typography::TYPOGRAPHY_TEXT,
302 ],
303 ]
304 );
305
306 $this->end_controls_section();
307
308 }
309
310 private function show_tab($item)
311 {
312 global $property;
313
314 if ( is_null($property) && isset($post->ID) && get_post_type($post->ID) == 'property' )
315 {
316 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared frontend property global used by the Elementor widget contract; the widget intentionally consumes the current property context.
317 $property = new PH_Property($post->ID);
318 }
319
320 if ( is_null($property) )
321 {
322 return false;
323 }
324
325 $tab_display = $item['tab_display'];
326
327 $show = false;
328
329 foreach ( $item['tab_display'] as $display )
330 {
331 switch ( $display )
332 {
333 case "gallery":
334 {
335 if ( get_option('propertyhive_images_stored_as', '') == 'urls' )
336 {
337 $photo_urls = $property->photo_urls;
338 if ( !is_array($photo_urls) ) { $photo_urls = array(); }
339
340 if ( !empty($photo_urls) )
341 {
342 return true;
343 }
344 }
345 else
346 {
347 $attachment_ids = $property->get_gallery_attachment_ids();
348 if ( !empty($attachment_ids) )
349 {
350 return true;
351 }
352 }
353 break;
354 }
355 case "floorplan":
356 {
357 if ( get_option('propertyhive_floorplans_stored_as', '') == 'urls' )
358 {
359 $floorplan_urls = $property->floorplan_urls;
360 if ( !is_array($floorplan_urls) ) { $floorplan_urls = array(); }
361
362 if ( !empty($floorplan_urls) )
363 {
364 return true;
365 }
366 }
367 else
368 {
369 $attachment_ids = $property->get_floorplan_attachment_ids();
370 if ( !empty($attachment_ids) )
371 {
372 return true;
373 }
374 }
375 break;
376 }
377 case "brochure":
378 {
379 if ( get_option('propertyhive_brochures_stored_as', '') == 'urls' )
380 {
381 $brochure_urls = $property->brochure_urls;
382 if ( !is_array($brochure_urls) ) { $brochure_urls = array(); }
383
384 if ( !empty($brochure_urls) )
385 {
386 return true;
387 }
388 }
389 else
390 {
391 $attachment_ids = $property->get_brochure_attachment_ids();
392 if ( !empty($attachment_ids) )
393 {
394 return true;
395 }
396 }
397 break;
398 }
399 case "epc":
400 {
401 if ( get_option('propertyhive_epcs_stored_as', '') == 'urls' )
402 {
403 $epc_urls = $property->epc_urls;
404 if ( !is_array($epc_urls) ) { $epc_urls = array(); }
405
406 if ( !empty($epc_urls) )
407 {
408 return true;
409 }
410 }
411 else
412 {
413 $attachment_ids = $property->get_epc_attachment_ids();
414 if ( !empty($attachment_ids) )
415 {
416 return true;
417 }
418 }
419 break;
420 }
421 case "virtual_tour":
422 case "embedded_virtual_tour":
423 {
424 $virtual_tours = $property->get_virtual_tours();
425 if ( !empty($virtual_tours) )
426 {
427 return true;
428 }
429 break;
430 }
431 case "map":
432 case "street_view":
433 {
434 if ( $property->latitude != '' && $property->latitude != '0' && $property->longitude != '' && $property->longitude != '0' )
435 {
436 return true;
437 }
438 break;
439 }
440 case "features":
441 {
442 if ( !empty($property->get_features()) )
443 {
444 return true;
445 }
446 break;
447 }
448 case "content":
449 {
450 if ( ! empty( $item['tab_content'] ) )
451 {
452 return true;
453 }
454 break;
455 }
456 default:
457 {
458 return apply_filters( 'propertyhive_elementor_tabbed_details_show_tab', true, $property, $display );
459 }
460 }
461 }
462
463 return $show;
464 }
465
466 protected function render() {
467
468 global $property, $post;
469
470 if ( is_null($property) && isset($post->ID) && get_post_type($post->ID) == 'property' )
471 {
472 // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared frontend property global used by the Elementor widget contract; the widget intentionally consumes the current property context.
473 $property = new PH_Property($post->ID);
474 }
475
476 $tabs = $this->get_settings( 'property_tabs' );
477
478 $id_int = substr( $this->get_id_int(), 0, 3 );
479 ?>
480 <!--<div class="elementor-widget-tabs elementor-tabs-view-horizontal">-->
481 <div class="elementor-tabs" role="tablist">
482 <div class="elementor-tabs-wrapper">
483 <?php
484 foreach ( $tabs as $index => $item )
485 {
486 $show_tab = $this->show_tab($item);
487 if ($show_tab)
488 {
489 $tab_count = $index + 1;
490
491 $tab_title_setting_key = $this->get_repeater_setting_key( 'tab_title', 'tabs', $index );
492
493 $onclick = '';
494 if ( in_array('map', $item['tab_display']) )
495 {
496 $onclick .= 'setTimeout(function() { initialize_property_map(); }, 10);';
497 }
498 if ( in_array('street_view', $item['tab_display']) )
499 {
500 $onclick .= 'setTimeout(function() { initialize_property_street_view(); }, 10);';
501 }
502 if ( in_array('gallery', $item['tab_display']) )
503 {
504 $onclick .= 'setTimeout(function() { jQuery(window).trigger(\'resize\'); }, 10);';
505 }
506 $onclick = apply_filters( 'propertyhive_elementor_tabbed_details_tab_onclick', $onclick, $property, $item );
507
508 $this->add_render_attribute( $tab_title_setting_key, [
509 'id' => 'elementor-tab-title-' . $id_int . $tab_count,
510 'class' => [ 'elementor-tab-title', 'elementor-tab-desktop-title' ],
511 'data-tab' => $tab_count,
512 'tabindex' => $id_int . $tab_count,
513 'role' => 'tab',
514 'aria-controls' => 'elementor-tab-content-' . $id_int . $tab_count,
515 'onclick' => $onclick
516 ] );
517 ?>
518 <div <?php
519 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Elementor get_render_attribute_string uses Utils::render_html_attributes, which escapes attribute values; attribute names above are fixed literals.
520 echo $this->get_render_attribute_string( $tab_title_setting_key ); ?>><?php echo esc_html( $item['tab_title'] ); ?></div>
521 <?php
522 }
523 }
524 ?>
525 </div>
526 <div class="elementor-tabs-content-wrapper">
527 <?php
528 foreach ( $tabs as $index => $item )
529 {
530 $show_tab = $this->show_tab($item);
531 if ($show_tab)
532 {
533 $tab_count = $index + 1;
534
535 $tab_content_setting_key = $this->get_repeater_setting_key( 'tab_content', 'tabs', $index );
536
537 $tab_title_mobile_setting_key = $this->get_repeater_setting_key( 'tab_title_mobile', 'tabs', $tab_count );
538
539 $onclick = '';
540 if ( in_array('map', $item['tab_display']) )
541 {
542 $onclick .= 'setTimeout(function() { initialize_property_map(); }, 10);';
543 }
544 if ( in_array('street_view', $item['tab_display']) )
545 {
546 $onclick .= 'setTimeout(function() { initialize_property_street_view(); }, 10);';
547 }
548 if ( in_array('gallery', $item['tab_display']) )
549 {
550 $onclick .= 'setTimeout(function() { jQuery(window).trigger(\'resize\'); }, 10);';
551 }
552 $onclick = apply_filters( 'propertyhive_elementor_tabbed_details_tab_onclick', $onclick, $property, $item );
553
554 $this->add_render_attribute( $tab_content_setting_key, [
555 'id' => 'elementor-tab-content-' . $id_int . $tab_count,
556 'class' => [ 'elementor-tab-content', 'elementor-clearfix' ],
557 'data-tab' => $tab_count,
558 'role' => 'tabpanel',
559 'aria-labelledby' => 'elementor-tab-title-' . $id_int . $tab_count,
560 ] );
561
562 $this->add_render_attribute( $tab_title_mobile_setting_key, [
563 'class' => [ 'elementor-tab-title', 'elementor-tab-mobile-title' ],
564 'tabindex' => $id_int . $tab_count,
565 'data-tab' => $tab_count,
566 'role' => 'tab',
567 'onclick' => $onclick
568 ] );
569
570 $this->add_inline_editing_attributes( $tab_content_setting_key, 'advanced' );
571 ?>
572 <div <?php
573 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Elementor get_render_attribute_string uses Utils::render_html_attributes, which escapes attribute values; attribute names above are fixed literals.
574 echo $this->get_render_attribute_string( $tab_title_mobile_setting_key ); ?>><?php echo esc_html($item['tab_title']); ?></div>
575 <div <?php
576 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Elementor get_render_attribute_string uses Utils::render_html_attributes, which escapes attribute values; attribute names above are fixed literals.
577 echo $this->get_render_attribute_string( $tab_content_setting_key ); ?>><?php
578 foreach ( $item['tab_display'] as $display )
579 {
580 switch ( $display )
581 {
582 case "features":
583 {
584 propertyhive_template_single_features();
585 break;
586 }
587 case "summary_description":
588 {
589 propertyhive_template_single_summary();
590 break;
591 }
592 case "full_description":
593 {
594 propertyhive_template_single_description();
595 break;
596 }
597 case "gallery":
598 {
599 echo '<style type="text/css">
600 .tabbed-gallery-container {
601
602 }
603 .tabbed-gallery {
604 display: grid;
605 grid-template-columns: repeat(4, 1fr); /* 4 items per row */
606 gap: 10px;
607 }
608 .tabbed-gallery a { }
609 .tabbed-gallery a img {
610 width: 100%; /* Ensure the images fill their grid cell */
611 height: auto; /* Maintain aspect ratio */
612 display: block; /* Ensure no extra space below images */
613 }
614 </style>';
615 if ( get_option('propertyhive_images_stored_as', '') == 'urls' )
616 {
617 $photo_urls = $property->photo_urls;
618 if ( !is_array($photo_urls) ) { $photo_urls = array(); }
619
620 if ( !empty($photo_urls) )
621 {
622 echo '<div class="tabbed-gallery">';
623
624 foreach ( $photo_urls as $photo )
625 {
626 echo '<a href="' . esc_url($photo['url']) . '" data-fancybox="tabbed_photos" rel="nofollow"><img src="' . esc_url($photo['url']) . '" alt=""></a>';
627 }
628
629 echo '</div>';
630 }
631 }
632 else
633 {
634 $gallery_attachment_ids = $property->get_gallery_attachment_ids();
635
636 if ( !empty($gallery_attachment_ids) )
637 {
638 echo '<div class="tabbed-gallery">';
639
640 foreach ( $gallery_attachment_ids as $attachment_id )
641 {
642 $image_medium_url = '';
643 $image = wp_get_attachment_image_src( $attachment_id, 'medium' );
644 if ( $image !== false )
645 {
646 $image_medium_url = $image[0];
647 }
648 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" data-fancybox="tabbed_photos" rel="nofollow"><img src="' . esc_url($image_medium_url) . '" alt=""></a>';
649 }
650
651 echo '</div>';
652 }
653 }
654 break;
655 }
656 case "floorplan":
657 {
658 if ( get_option('propertyhive_floorplans_stored_as', '') == 'urls' )
659 {
660 $floorplan_urls = $property->floorplan_urls;
661 if ( !is_array($floorplan_urls) ) { $floorplan_urls = array(); }
662
663 if ( !empty($floorplan_urls) )
664 {
665 echo '<div class="floorplans">';
666
667 foreach ( $floorplan_urls as $floorplan )
668 {
669 echo '<a href="' . esc_url($floorplan['url']) . '" data-fancybox="floorplans" rel="nofollow"><img src="' . esc_url($floorplan['url']) . '" alt=""></a>';
670 }
671
672 echo '</div>';
673 }
674 }
675 else
676 {
677 $floorplan_attachment_ids = $property->get_floorplan_attachment_ids();
678
679 if ( !empty($floorplan_attachment_ids) )
680 {
681 echo '<div class="floorplans">';
682
683 foreach ( $floorplan_attachment_ids as $attachment_id )
684 {
685 if ( wp_attachment_is_image($attachment_id) )
686 {
687 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" data-fancybox="floorplans" rel="nofollow"><img src="' . esc_url(wp_get_attachment_url($attachment_id)) . '" alt=""></a>';
688 }
689 else
690 {
691 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" target="_blank" rel="nofollow">' . esc_html(__( 'View Floorplan', 'propertyhive' )) . '</a>';
692 }
693 }
694
695 echo '</div>';
696 }
697 }
698 break;
699 }
700 case "brochure":
701 {
702 if ( get_option('propertyhive_brochures_stored_as', '') == 'urls' )
703 {
704 $brochure_urls = $property->brochure_urls;
705 if ( !is_array($brochure_urls) ) { $brochure_urls = array(); }
706
707 if ( !empty($brochure_urls) )
708 {
709 echo '<div class="brochures">';
710
711 foreach ( $brochure_urls as $brochure )
712 {
713 echo '<a href="' . esc_url($brochure['url']). '" target="_blank" rel="nofollow">' . esc_html(__( 'View Brochure', 'propertyhive' )) . '</a>';
714 }
715
716 echo '</div>';
717 }
718 }
719 else
720 {
721 $brochure_attachment_ids = $property->get_brochure_attachment_ids();
722
723 if ( !empty($brochure_attachment_ids) )
724 {
725 echo '<div class="brochures">';
726
727 foreach ( $brochure_attachment_ids as $attachment_id )
728 {
729 if ( wp_attachment_is_image($attachment_id) )
730 {
731 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" data-fancybox="brochures" rel="nofollow"><img src="' . esc_url(wp_get_attachment_url($attachment_id)) . '" alt=""></a>';
732 }
733 else
734 {
735 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" target="_blank" rel="nofollow">' . esc_html(__( 'View Brochure', 'propertyhive' )) . '</a>';
736 }
737 }
738
739 echo '</div>';
740 }
741 }
742 break;
743 }
744 case "epc":
745 {
746 if ( get_option('propertyhive_epcs_stored_as', '') == 'urls' )
747 {
748 $epc_urls = $property->epc_urls;
749 if ( !is_array($epc_urls) ) { $epc_urls = array(); }
750
751 if ( !empty($epc_urls) )
752 {
753 echo '<div class="epcs">';
754
755 foreach ( $epc_urls as $epc )
756 {
757 echo '<a href="' . esc_url($epc['url']) . '" data-fancybox="epcs" rel="nofollow"><img src="' . esc_url($epc['url']) . '" alt=""></a>';
758 }
759
760 echo '</div>';
761 }
762 }
763 else
764 {
765 $epc_attachment_ids = $property->get_epc_attachment_ids();
766
767 if ( !empty($epc_attachment_ids) )
768 {
769 echo '<div class="epcs">';
770
771 foreach ( $epc_attachment_ids as $attachment_id )
772 {
773 if ( wp_attachment_is_image($attachment_id) )
774 {
775 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" data-fancybox="epcs" rel="nofollow"><img src="' . esc_url(wp_get_attachment_url($attachment_id)) . '" alt=""></a>';
776 }
777 else
778 {
779 echo '<a href="' . esc_url(wp_get_attachment_url($attachment_id)) . '" target="_blank" rel="nofollow">' . esc_html(__( 'View EPC', 'propertyhive' )) . '</a>';
780 }
781 }
782
783 echo '</div>';
784 }
785 }
786 break;
787 }
788 case "virtual_tour":
789 {
790 $virtual_tours = $property->get_virtual_tours();
791
792 if ( !empty($virtual_tours) )
793 {
794 echo '<div class="virtual-tours">';
795
796 foreach ( $virtual_tours as $virtual_tour )
797 {
798 echo '<a href="' . esc_url($virtual_tour['url']) . '" target="_blank" rel="nofollow">' . esc_html($virtual_tour['label']) . '</a>';
799 }
800
801 echo '</div>';
802 }
803 break;
804 }
805 case "embedded_virtual_tour":
806 {
807 $virtual_tours = $property->get_virtual_tours();
808
809 if ( !empty($virtual_tours) )
810 {
811 echo '<div class="virtual-tours">';
812
813 $fb_sdk_printed = false;
814
815 foreach ( $virtual_tours as $virtual_tour )
816 {
817 $virtual_tour['url'] = preg_replace(
818 "/\s*[a-zA-Z\/\/:\.]*youtu(be.com\/watch\?v=|.be\/)([a-zA-Z0-9\-_]+)([a-zA-Z0-9\/\*\-\_\?\&\;\%\=\.]*)/i",
819 "//www.youtube.com/embed/$2",
820 $virtual_tour['url']
821 );
822
823 $virtual_tour['url'] = preg_replace(
824 '#https?://(www\.)?youtube\.com/shorts/([^/?]+)#',
825 '//www.youtube.com/embed/$2',
826 $virtual_tour['url']
827 );
828
829 if ( strpos($virtual_tour['url'], 'vimeo') !== FALSE && strpos($virtual_tour['url'], 'player.') === FALSE )
830 {
831 $virtual_tour['url'] = preg_replace(
832 '/(https?:\/\/)?(www\.)?(player\.)?vimeo\.com\/?(showcase\/)*([0-9))([a-z]*\/)*([0-9]{6,11})[?]?.*/i',
833 "//player.vimeo.com/video/$6",
834 $virtual_tour['url']
835 );
836 }
837
838 if ( preg_match('#^https?://(www\.)?facebook\.com/reel/[^?\s]+#i', $virtual_tour['url']) )
839 {
840 // Print SDK once (uses en_GB locale to match your site)
841 if ( ! $fb_sdk_printed )
842 {
843 $fb_sdk_printed = true;
844 echo '<div id="fb-root"></div>';
845 // Use the standard SDK include; id prevents double-loading
846 // phpcs:ignore PluginCheck.CodeAnalysis.EnqueuedResourceOffloading.OffloadedContent, WordPress.WP.EnqueuedResourceParameters.MissingVersion -- Provider maintains this API endpoint without a plugin version. Required Facebook SDK for the property's configured Reel embed.
847 wp_enqueue_script( 'propertyhive-facebook-embed', 'https://connect.facebook.net/en_GB/sdk.js#xfbml=1&version=v20.0', array(), null, true );
848 }
849
850 // Output the Reel embed container; the SDK converts it into a player
851 echo '<div class="fb-video" data-href="' . esc_url( $virtual_tour['url'] ) . '" data-allowfullscreen="true" data-width="auto" style="max-width:100%;"></div>';
852
853 // Skip the generic iframe path for FB Reels
854 continue;
855 }
856
857 echo '<iframe src="' . esc_url($virtual_tour['url']) . '" height="500" width="100%" allowfullscreen frameborder="0" allow="fullscreen"></iframe>';
858 }
859
860 echo '</div>';
861 }
862 break;
863 }
864 case "map":
865 {
866 echo do_shortcode('[property_map scrollwheel="false"' . ( ( $tab_count > 1 ) ? ' init_on_load="false"' : '' ) . ']');
867 break;
868 }
869 case "street_view":
870 {
871 echo do_shortcode('[property_street_view' . ( ( $tab_count > 1 ) ? ' init_on_load="false"' : '' ) . ']');
872 break;
873 }
874 case "make_enquiry":
875 {
876 propertyhive_enquiry_form();
877 break;
878 }
879 case "content":
880 {
881 if ( ! empty( $item['tab_content'] ) )
882 {
883 echo '<div class="tabbed-custom-content">';
884 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Elementor parses this rich-text control, including authorized shortcodes and embeds.
885 echo $this->parse_text_editor( $item['tab_content'] );
886 echo '</div>';
887 }
888 break;
889 }
890 }
891
892 do_action( 'propertyhive_elementor_tabbed_details_tab_contents', $property, $display );
893 }
894 ?></div>
895 <?php
896 }
897 }
898 ?>
899 </div>
900 </div>
901 <!--</div>-->
902
903 <script>
904 jQuery(document).ready(function()
905 {
906 jQuery('[data-widget_type=\'property-tabbed-details.default\']').each(function()
907 {
908 jQuery(this).attr('data-widget_type', 'tabs.default');
909 });
910 });
911
912 jQuery(window).on('load', function()
913 {
914 jQuery(window).trigger('resize');
915 });
916
917 jQuery(window).on('resize', function()
918 {
919 jQuery('.tabbed-gallery img').each(function()
920 {
921 var ratio = 3/4;
922 jQuery(this).height( jQuery(this).width() * ratio );
923 })
924 });
925 </script>
926 <?php
927
928 }
929
930 }
931