PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 9.0.3
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v9.0.3
9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 All 222 releases
wpvr / legacy / admin / classes / class-wpvr-scene.php

class-wpvr-scene.php in WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress 9.0.3, at legacy/admin/classes/class-wpvr-scene.php

3,674 lines 186.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) exit; // Exit if accessed directly
3 /**
4 * Responsible for managing Scene tab on Setup meta box
5 *
6 * @link http://rextheme.com/
7 * @since 8.0.0
8 *
9 * @package Wpvr
10 * @subpackage Wpvr/admin/classes
11 */
12
13 class WPVR_Scene {
14
15 /**
16 * Instance of WPVR_Hotspot class
17 *
18 * @var object
19 * @since 8.0.0
20 */
21 protected $hotspot;
22
23 /**
24 * Instance of WPVR_Format class
25 *
26 * @var object
27 * @since 8.0.0
28 */
29 protected $format;
30
31 /**
32 * Instance of WPVR_Validator class
33 *
34 * @var object
35 * @since 8.0.0
36 */
37 private $validator;
38
39 /**
40 * Number of scene or hotspot item
41 *
42 * @var integer
43 * @since 8.0.0
44 */
45 protected $data_limit;
46
47 /**
48 * Pro version license status
49 *
50 * @var string
51 * @since 8.0.0
52 */
53 protected $status;
54
55
56 function __construct()
57 {
58 $this->hotspot = new WPVR_Hotspot();
59 $this->format = new WPVR_Format();
60 $this->validator = new WPVR_Validator();
61
62 $this->status = apply_filters( 'check_pro_license_status', $this->status );
63
64 if ($this->status !== false && $this->status == 'valid') {
65 $this->data_limit = 999999999;
66 } else {
67 $this->data_limit = 5;
68 }
69 }
70
71 /**
72 * Render Scene Settings Content
73 *
74 * @param array $postdata
75 *
76 * @return void
77 * @since 8.0.0
78 */
79 public function render_scene($postdata)
80 {
81 ob_start();
82 ?>
83
84 <!-- Scene and Hotspot repeater -->
85 <div class="scene-setup rex-pano-sub-tabs" data-limit="<?php echo esc_attr( $this->data_limit + 1 ); ?>">
86 <?php $this->render_scene_repeater_list($postdata); ?>
87 </div>
88
89 <?php
90 // ob_end_flush();
91 }
92
93
94 /**
95 * Render scene setup data repeater list
96 *
97 * @param array $postdata
98 *
99 * @return void
100 * @since 8.0.0
101 */
102 private function render_scene_repeater_list($postdata)
103 {
104 ob_start();
105 ?>
106 <nav class="rex-pano-tab-nav rex-pano-nav-menu scene-nav">
107 <?php $this->render_nav_menu($postdata); // Will render scene navigation bar ?>
108 </nav>
109
110 <div data-repeater-list="scene-list" class="rex-pano-tab-content">
111
112 <!-- Default empty repeater -->
113 <div data-repeater-item class="single-scene rex-pano-tab" data-title="0" id="scene-0">
114 <?php $this->render_default_repeater_item(); ?>
115 </div>
116 <!-- Empty repeater end -->
117
118 <?php $s = 1; $firstvalue = reset($postdata['panodata']["scene-list"]);
119 foreach ($postdata['panodata']["scene-list"] as $pano_scene) { ?>
120
121 <div data-repeater-item class="single-scene rex-pano-tab <?php if($pano_scene['scene-id'] == $firstvalue['scene-id']) { echo esc_attr('active'); }; ?>" data-title="1" id="scene-<?php echo esc_attr( $s ); ?>">
122 <?php $this->render_repeater_item_with_panodata($pano_scene, $s); ?>
123 </div>
124
125 <?php $s++; } ?>
126 </div>
127 <?php
128 // ob_end_flush();
129 }
130
131
132 /**
133 * Render scene nav menu
134 *
135 * @param array $postdata
136 *
137 * @return void
138 * @since 8.0.0
139 */
140 private function render_nav_menu($postdata)
141 {
142 ob_start();
143 ?>
144 <ul>
145 <?php $i = 1; $firstvalue = reset($postdata['panodata']["scene-list"]);
146 foreach ($postdata['panodata']["scene-list"] as $pano_scene) { ?>
147
148 <li class="<?php if ($pano_scene['scene-id'] == $firstvalue['scene-id']) {echo 'active';};?>">
149 <span data-index="<?php echo esc_attr( $i ); ?>" data-href="#scene-<?php echo esc_attr( $i ); ?>">
150 <i class="fa fa-image"></i>
151 </span>
152 </li>
153
154 <?php $i++; } ?>
155 <li class="add" data-repeater-create><span><i class="fa fa-plus-circle"></i></span></li>
156 </ul>
157 <?php
158 ob_end_flush();
159 }
160
161
162 /**
163 * Render repeater item for default scene
164 *
165 * @param int $data_limit
166 *
167 * @return void
168 * @since 8.0.0
169 */
170 private function render_default_repeater_item()
171 {
172 ob_start();
173 ?>
174 <div class="active_scene_id"><p></p></div>
175 <div class="scene-content">
176 <?php $this->render_default_repeater_item_scene_content(); ?>
177 </div>
178
179 <!-- hotspot setup -->
180 <div class="hotspot-setup rex-pano-sub-tabs" data-limit="<?php echo esc_attr( $this->data_limit ); ?>">
181 <?php $this->hotspot->render_hotspot($s = 0, $h =1)?>
182 </div>
183 <button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>
184 <?php
185 ob_end_flush();
186 }
187
188
189 /**
190 * Render repeater items while scene has panaromic data
191 *
192 * @param array $pano_scene
193 * @param int $s scene number increment var
194 *
195 * @return void
196 * @since 8.0.0
197 */
198 private function render_repeater_item_with_panodata($pano_scene, $s)
199 {
200 ob_start();
201 ?>
202 <div class="active_scene_id"><p></p></div>
203 <div class="scene-content">
204 <!--
205 - Render repeater item scene content
206 - If scene has panaromic data
207 -->
208 <?php $this->render_repeater_scene_content_with_data($pano_scene); ?>
209 </div>
210 <!--
211 - Render repeater item hotspot content
212 -->
213 <?php $this->render_repeater_item_hotspot_content($pano_scene, $s); ?>
214
215 <button data-repeater-delete type="button" title="Delete Scene" class="delete-scene"><i class="far fa-trash-alt"></i></button>
216 <?php
217 ob_end_flush();
218 }
219
220
221 /**
222 * Render scene content for default repeater item
223 *
224 * @return void
225 * @since 8.0.0
226 */
227 private function render_default_repeater_item_scene_content()
228 {
229 ob_start();
230 ?>
231
232 <h6 class="title"><i class="fa fa-cog"></i> <?php esc_html_e('Scene Settings','wpvr'); ?> </h6>
233
234 <div class="scene-left">
235 <?php WPVR_Meta_Field::render_scene_left_fields_empty_panodata(); ?>
236 </div>
237
238 <div class="scene-right">
239 <?php do_action( 'wpvr_pro_scene_empty_right_fields' ) ?>
240 </div>
241
242 <?php
243 ob_end_flush();
244 }
245
246
247 /**
248 * Render repeater item scene content is scene has panaromic data
249 *
250 * @param mixed $dscene
251 * @param mixed $scene_id
252 * @param mixed $scene_photo
253 *
254 * @return void
255 * @since 8.0.0
256 */
257 private function render_repeater_scene_content_with_data($pano_scene)
258 {
259 ob_start();
260 ?>
261 <h6 class="title"><i class="fa fa-cog"></i> <?php esc_html_e('Scene Settings','wpvr'); ?> </h6>
262
263 <div class="scene-left">
264 <?php WPVR_Meta_Field::render_scene_left_fields_with_panodata($pano_scene) ;?>
265 </div>
266
267 <div class="scene-right">
268 <?php do_action( 'wpvr_pro_scene_right_fields', $pano_scene ) ?>
269 </div>
270
271
272 <?php
273 ob_end_flush();
274 }
275
276
277 /**
278 * Render repeater item hotspot content
279 *
280 * @param array $pano_hotspots
281 * @param int $data_limit
282 * @param int $s
283 *
284 * @return void
285 * @since 8.0.0
286 */
287 private function render_repeater_item_hotspot_content($pano_scene, $s)
288 {
289 if (!empty($pano_scene['hotspot-list'])) { ?>
290 <div class="hotspot-setup rex-pano-sub-tabs" data-limit="<?php echo esc_attr( $this->data_limit ); ?>">
291
292 <?php $this->hotspot->render_hotspot_with_panodata($pano_scene['hotspot-list'], $s); //Render hotspot while scene has hotspot data ?>
293
294 </div>
295 <?php } else { ?>
296 <div class="hotspot-setup rex-pano-sub-tabs" data-limit="<?php echo esc_attr( $this->data_limit ); ?>">
297
298 <?php $this->hotspot->render_hotspot($s, $h = 1); //Render hotspot while scene has no hotspot data ?>
299
300 </div>
301 <?php }
302 }
303
304
305 /**
306 * Update post meta data
307 *
308 * @param integer $postid
309 * @param integer $panoid
310 * @param boolean $is_publish_action
311 *
312 * @return void
313 * @since 8.0.0
314 */
315 public function wpvr_update_meta_box($postid, $panoid, $is_publish_action = false)
316 {
317 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
318 if ( ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
319 wp_die( 'Permission denied.' );
320 }
321 $panodata = $this->format->prepare_panodata(isset($_POST['panodata']) ? wp_unslash( $_POST['panodata'] ) : ''); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
322 $default_scene = $this->format->prepare_default_scene($panodata);
323 $previewtext = isset($_POST['previewtext']) ? $this->validator->preview_text_validation(wp_unslash( $_POST['previewtext'] )) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
324
325 $gzoom = $this->format->set_pro_checkbox_value(@wp_unslash( $_POST['gzoom'] ));
326 $default_global_zoom = '';
327 $max_global_zoom = '';
328 $min_global_zoom = '';
329 if ($gzoom == 'on') {
330 $default_global_zoom = isset($_POST['dzoom']) ? wp_unslash( $_POST['dzoom'] ) : '';
331 $max_global_zoom = isset($_POST['maxzoom']) ? wp_unslash( $_POST['maxzoom'] ) : '';
332 $min_global_zoom = isset($_POST['minzoom']) ? wp_unslash( $_POST['minzoom'] ) : '';
333 }
334
335 $custom_control = isset($_POST['customcontrol']) ? wp_unslash( $_POST['customcontrol'] ) : null;
336
337 $vrgallery = $this->format->set_checkbox_value(@wp_unslash( $_POST['vrgallery'] ));
338 $vrgallery_title = $this->format->set_checkbox_value(@wp_unslash( $_POST['vrgallery_title'] ));
339 $vrgallery_display = $this->format->set_checkbox_value(@wp_unslash( $_POST['vrgallery_display'] ));
340 $vrgallery_icon_size = $this->format->set_checkbox_value(@wp_unslash( $_POST['vrgallery_icon_size'] ));
341
342 $existing_panodata = get_post_meta( $postid, 'panodata', true );
343 $existing_panodata = is_array( $existing_panodata ) ? $existing_panodata : array();
344 $mouseZoom = isset( $_POST['mouseZoom'] )
345 ? $this->format->set_pro_checkbox_value( wp_unslash( $_POST['mouseZoom'] ) )
346 : ( $existing_panodata['mouseZoom'] ?? 'on' );
347 $draggable = isset( $_POST['draggable'] )
348 ? $this->format->set_pro_checkbox_value( wp_unslash( $_POST['draggable'] ) )
349 : ( $existing_panodata['draggable'] ?? 'on' );
350 $diskeyboard = $this->format->set_pro_checkbox_value(@wp_unslash( $_POST['diskeyboard'] ));
351 $keyboardzoom = $this->format->set_checkbox_value(@wp_unslash( $_POST['keyboardzoom'] ));
352 $compass = $this->format->set_checkbox_on_value(@wp_unslash( $_POST['compass'] ));
353 //===Gyroscopre control===//
354 $gyro = $this->format->set_pro_checkbox_value(@wp_unslash( $_POST['gyro'] ));
355 if ($gyro == 'on') {
356 if (!is_ssl()) {
357 wp_send_json_error('<p><span>Warning:</span> Please add SSL to enable Gyroscope for WP VR. </p>');
358 die();
359 }
360 $gyro = true;
361 $deviceorientationcontrol = $this->format->set_checkbox_value(@wp_unslash( $_POST['deviceorientationcontrol'] ));
362 } else {
363 $gyro = false;
364 $deviceorientationcontrol = false;
365 }
366 //===Gyroscopre control===//
367
368 $autoload = $this->format->set_checkbox_value(isset($_POST['autoload']) ? wp_unslash( $_POST['autoload'] ) : '');
369 $control = $this->format->set_checkbox_value(isset($_POST['control']) ? wp_unslash( $_POST['control'] ) : '');
370
371 $scene_fade_duration = isset($_POST['scenefadeduration']) ? sanitize_text_field(wp_unslash( $_POST['scenefadeduration'] )) : '';
372 $preview = isset($_POST['preview']) ? esc_url(wp_unslash( $_POST['preview'] )) : '';
373 $rotation = isset($_POST['rotation']) ? sanitize_text_field(wp_unslash( $_POST['rotation'] )) : '';
374 $autorotation = isset($_POST['autorotation']) ? sanitize_text_field(wp_unslash( $_POST['autorotation'] )) : '';
375
376 $autorotationinactivedelay = isset($_POST['autorotationinactivedelay']) ? sanitize_text_field(wp_unslash( $_POST['autorotationinactivedelay'] )) : '';
377 $autorotationstopdelay = isset($_POST['autorotationstopdelay']) ? sanitize_text_field(wp_unslash( $_POST['autorotationstopdelay'] )) : '';
378
379 //===generic form===//
380 $genericform = sanitize_text_field(isset($_POST['genericform']) ? wp_unslash( $_POST['genericform'] ) : 'off');
381 $genericformshortcode = isset($_POST['genericformshortcode']) ? sanitize_text_field(wp_unslash( $_POST['genericformshortcode'] )) : '' ;
382 $genericformicon = isset($_POST['genericformicon'])
383 ? sanitize_text_field(wp_unslash($_POST['genericformicon']))
384 : ($existing_panodata['genericformicon'] ?? 'fab fa-wpforms');
385 $genericformiconcolor = isset($_POST['genericformiconcolor'])
386 ? sanitize_hex_color(wp_unslash($_POST['genericformiconcolor']))
387 : ($existing_panodata['genericformiconcolor'] ?? '#f7fffb');
388 $genericformiconcolor = $genericformiconcolor ?: '#f7fffb';
389 //===generic form===//
390
391
392 if(isset($_POST['rotation']) && sanitize_text_field(wp_unslash( $_POST['rotation'] )) === 'on' ) {
393 $this->validator->basic_setting_validation($autorotationinactivedelay, $autorotationstopdelay); // Basic setting error control and validation //
394 }
395
396 //===Company Logo===//
397 $cpLogoSwitch = isset($_POST['cpLogoSwitch']) ? wp_unslash( $_POST['cpLogoSwitch'] ) : 'off';
398 $cpLogoImg = isset($_POST['cpLogoImg']) ? wp_unslash( $_POST['cpLogoImg'] ) : '';
399 $cpLogoContent = isset($_POST['cpLogoContent']) ? sanitize_text_field(wp_unslash( $_POST['cpLogoContent'] )) : '';
400 //===Company Logo===//
401
402 //===Explainer video===//
403 $explainerSwitch = isset($_POST['explainerSwitch']) ? wp_unslash( $_POST['explainerSwitch'] ) : 'off';
404 $explainerContent = '';
405 $explainerContent = isset($_POST['explainerContent']) ? wp_unslash( $_POST['explainerContent'] ) : '';
406 //===Explainer video===//
407
408
409 $scene_fade_duration = '';
410 $scene_fade_duration = isset($_POST['scenefadeduration']) ? sanitize_text_field(wp_unslash( $_POST['scenefadeduration'] )) : '';
411
412 // Only validate when publishing, not when saving drafts
413 if ($is_publish_action) {
414 $this->validator->scene_validation($panodata); // Scene content error control and validation //
415
416 $this->validator->empty_scene_validation($panodata); // Empty scene content error control and validation //
417
418 $this->validator->duplicate_hotspot_validation($panodata); // Duplicate error control and validation //
419 }
420
421 $panodata = $this->format->remove_empty_scene_and_hotspot($panodata); // Remove Empty scene and hotspot //
422
423 //===audio===//
424 $bg_music = isset($_POST['bg_music']) ? sanitize_text_field(wp_unslash( $_POST['bg_music'] )) : 'off';
425 $bg_music_url = isset($_POST['bg_music_url']) ? esc_url_raw(wp_unslash( $_POST['bg_music_url'] )) : '';
426 $autoplay_bg_music = isset($_POST['autoplay_bg_music']) ? sanitize_text_field(wp_unslash( $_POST['autoplay_bg_music'] )) : 'off';
427 $loop_bg_music = isset($_POST['loop_bg_music']) ? sanitize_text_field(wp_unslash( $_POST['loop_bg_music'] )) : 'off';
428 if ($bg_music == 'on') {
429 if (empty($bg_music_url)) {
430 wp_send_json_error('<p><span>Warning:</span> Please add an audio file as you enabled audio for this tour </p>');
431 die();
432 }
433 }
434 //===audio===//
435 $advanced_control = array(
436 'keyboardzoom' => $keyboardzoom,
437 'diskeyboard' => $diskeyboard,
438 'draggable' => $draggable,
439 'mouseZoom' => $mouseZoom,
440 'gyro' => $gyro,
441 'deviceorientationcontrol' => $deviceorientationcontrol,
442 'compass' => $compass,
443 'vrgallery' => $vrgallery,
444 'vrgallery_title' => $vrgallery_title,
445 'vrgallery_display' => $vrgallery_display,
446 'vrgallery_icon_size' => $vrgallery_icon_size,
447 'bg_music' => $bg_music,
448 'bg_music_url' => $bg_music_url,
449 'autoplay_bg_music' => $autoplay_bg_music,
450 'loop_bg_music' => $loop_bg_music,
451 'cpLogoSwitch' => $cpLogoSwitch,
452 'cpLogoImg' => $cpLogoImg,
453 'cpLogoContent' => $cpLogoContent,
454 'hfov' => $default_global_zoom,
455 'maxHfov' => $max_global_zoom,
456 'minHfov' => $min_global_zoom,
457 'explainerSwitch' => $explainerSwitch,
458 'explainerContent' => $explainerContent,
459 );
460
461 $pano_array = array();
462 $pano_array = array(
463 "panoid" => $panoid,
464 "autoLoad" => $autoload,
465 "showControls" => $control,
466 "customcontrol" => $custom_control,
467 "autoRotate" => $autorotation,
468 "autoRotateInactivityDelay" => $autorotationinactivedelay,
469 "autoRotateStopDelay" => $autorotationstopdelay,
470 "genericform" => $genericform,
471 "genericformshortcode" => $genericformshortcode,
472 "genericformicon" => $genericformicon,
473 "genericformiconcolor" => $genericformiconcolor,
474 "preview" => $preview,
475 "defaultscene" => $default_scene,
476 "scenefadeduration" => $scene_fade_duration,
477 "panodata" => $panodata,
478 "previewtext" => $previewtext);
479 $pano_array = apply_filters( 'prepare_scene_pano_array_with_pro_version', $pano_array, $_POST, $advanced_control );
480 $pano_array = $this->format->prepare_rotation_wrapper_data($pano_array, $rotation);
481 // Prepare tour rotation wrapper data /
482 update_post_meta($postid, 'panodata', $pano_array);
483 do_action( 'wpvr_hotspot_saved', $postid, $pano_array );
484 $response = array(
485 'success' => true,
486 'data' => array(
487 'post_ID' => $postid,
488 'post_status' => get_post_status($postid)
489 )
490 );
491
492 do_action( 'wpvr_tour_settings_saved', $postid );
493
494
495 /**
496 * Delete orphaned analytics data
497 *
498 * @param integer $postid POST ID
499 *
500 * @return void
501 * @since 8.5.16
502 */
503 do_action('wpvr_pro_delete_orphaned_analytics_data', $postid);
504
505 wp_send_json($response);
506 die();
507
508 }
509
510
511 /**
512 * Allow iframe but disallow script tags in user input
513 * @since 8.5.16
514 */
515 public function wpvr_sanitize_iframe_only( $input ) {
516 if ( function_exists( 'wpvr_sanitize_iframe_only' ) ) {
517 return wpvr_sanitize_iframe_only( $input );
518 }
519
520 // Start with standard allowed post HTML (p, a, strong, etc.)
521 $allowed_tags = wp_kses_allowed_html( 'post' );
522
523 // Explicitly allow <iframe> with specific safe attributes
524 $allowed_tags['iframe'] = array(
525 'src' => true,
526 'width' => true,
527 'height' => true,
528 'title' => true,
529 'frameborder' => true,
530 'allow' => true,
531 'allowfullscreen' => true,
532 'referrerpolicy' => true,
533 );
534
535 // Sanitize input
536 return wp_kses( $input, $allowed_tags );
537 }
538
539
540
541 /**
542 * Responsible for showing Scene Preview
543 *
544 * @param string $panoid
545 * @param string $panovideo
546 *
547 * @return wp_send_json_success
548 * @since 8.0.0
549 */
550 public function wpvr_scene_preview($panoid, $panovideo)
551 {
552 $nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
553 if ( ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
554 wp_die( 'Permission denied.' );
555 }
556 $panodata = $this->format->prepare_panodata( isset( $_POST['panodata'] ) ? wp_unslash( $_POST['panodata'] ) : '' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
557
558 $control = $this->format->set_checkbox_value(wp_unslash( $_POST['control'] ));
559 $autoload = $this->format->set_checkbox_value(wp_unslash( $_POST['autoload'] ));
560
561 $compass = $this->format->set_checkbox_on_value(@wp_unslash( $_POST['compass'] ));
562 $mouseZoom = $this->format->set_checkbox_value(@wp_unslash( $_POST['mouseZoom'] ));
563 $draggable = $this->format->set_checkbox_value(wp_unslash( $_POST['draggable'] ) ?? null);
564 $gzoom = $this->format->set_pro_checkbox_value(@wp_unslash( $_POST['gzoom'] ));
565 $diskeyboard = $this->format->set_checkbox_value(@wp_unslash( $_POST['diskeyboard'] ));
566 $keyboardzoom = $this->format->set_checkbox_value(@wp_unslash( $_POST['keyboardzoom'] ));
567
568 $gyro = $this->format->set_checkbox_on_value(@wp_unslash( $_POST['gyro'] ));
569 $deviceorientationcontrol = $this->format->set_checkbox_value(@wp_unslash( $_POST['deviceorientationcontrol'] ));
570
571 $floor_plan_enabler = $this->format->set_pro_checkbox_value(@wp_unslash( $_POST['wpvr_floor_plan_enabler'] ));
572 $floor_plan_image = isset($_POST['wpvr_floor_plan_image']) ? wp_unslash( $_POST['wpvr_floor_plan_image'] ) : '';
573
574 $scene_fade_duration = sanitize_text_field(wp_unslash( $_POST['scenefadeduration'] ));
575 $preview = esc_url(wp_unslash( $_POST['preview'] ));
576
577 $default_scene = '';
578
579 $rotation = sanitize_text_field(wp_unslash( $_POST['rotation'] ));
580 $autorotation = sanitize_text_field(wp_unslash( $_POST['autorotation'] ));
581 $autorotationinactivedelay = sanitize_text_field(wp_unslash( $_POST['autorotationinactivedelay'] ));
582 $autorotationstopdelay = sanitize_text_field(wp_unslash( $_POST['autorotationstopdelay'] ));
583
584 $default_global_zoom = '';
585 $max_global_zoom = '';
586 $min_global_zoom = '';
587 if ($gzoom == 'on') {
588 $default_global_zoom = wp_unslash( $_POST['dzoom'] );
589 $max_global_zoom = wp_unslash( $_POST['maxzoom'] );
590 $min_global_zoom = wp_unslash( $_POST['minzoom'] );
591 }
592
593 $default_scene = $this->format->prepare_default_scene($panodata);
594
595 if(isset($_POST['rotation']) && sanitize_text_field(wp_unslash( $_POST['rotation'] )) === 'on' ) {
596 $this->validator->basic_setting_validation($autorotationinactivedelay, $autorotationstopdelay); // Basic setting error control and validation //
597 }
598 $this->validator->scene_validation($panodata); // Scene content error control and validation //
599
600 $this->validator->empty_scene_validation($panodata); // Empty scene content error control and validation //
601
602 $this->validator->duplicate_hotspot_validation($panodata);
603 if($floor_plan_enabler == 'on'){
604 $this->validator->empty_floor_plan_image_validation($floor_plan_image);
605 }
606
607 $default_data = array();
608 if ($gzoom == 'on') {
609 $default_data = array("firstScene" => $default_scene, "sceneFadeDuration" => $scene_fade_duration, "hfov" => $default_global_zoom, "maxHfov" => $max_global_zoom, "minHfov" => $min_global_zoom);
610 } else {
611 $default_data = array("firstScene" => $default_scene, "sceneFadeDuration" => $scene_fade_duration);
612 }
613
614 $scene_data = $this->format->prepare_scene_data_for_preview($panodata);
615
616
617 $pano_id_array = array();
618 $pano_id_array = array("panoid" => $panoid);
619 $pano_response = array();
620 $pano_response = array("autoLoad" => $autoload, "defaultZoom" => $default_global_zoom, "minZoom" => $min_global_zoom, "maxZoom" => $max_global_zoom, "showControls" => $control, "compass" => $compass, "orientationOnByDefault" => $deviceorientationcontrol, "mouseZoom" => $mouseZoom, "draggable" => $draggable, "disableKeyboardCtrl" => $diskeyboard, 'keyboardZoom' => $keyboardzoom, "preview" => $preview, "autoRotate" => $autorotation, "autoRotateInactivityDelay" => $autorotationinactivedelay, "autoRotateStopDelay" => $autorotationstopdelay, "default" => $default_data, "scenes" => $scene_data);
621
622 $pano_response = $this->format->prepare_rotation_wrapper_data($pano_response, $rotation);
623
624 $is_pro = apply_filters('is_wpvr_pro_active',false);
625 $status = get_option('wpvr_edd_license_status');
626 $pano_floor_plan = array();
627 $call_to_action = array();
628 if ($status !== false && 'valid' == $status && $is_pro) {
629 $pano_floor_plan = array(
630 "floor_plan_tour_enabler" => $floor_plan_enabler,
631 "floor_plan_attachment_url" => $floor_plan_image
632 );
633 if ( 'on' === $floor_plan_enabler ) {
634 do_action( 'wpvr_floor_plan_configured', $postid, $pano_floor_plan );
635 }
636 $call_to_action = array(
637 'button_enable' =>sanitize_text_field(wp_unslash( $_POST['callToAction'] )),
638 'button_text' =>sanitize_text_field(wp_unslash( $_POST['buttontext'] )),
639 'button_url' =>sanitize_text_field(wp_unslash( $_POST['buttonurl'] ))
640 );
641 }
642
643 $response = array();
644 $response = array($pano_id_array, $pano_response, $panovideo,$pano_floor_plan,$call_to_action);
645 wp_send_json_success($response);
646 }
647
648
649 /**
650 * Render shortcode for scene and hotspot post data
651 *
652 * @param array $postdata
653 * @param string $panoid
654 * @param integer $id
655 * @param mixed $radius
656 * @param mixed $width
657 * @param mixed $height
658 *
659 * @return string
660 * @since 8.0.0
661 */
662 public function render_scene_shortcode($postdata, $panoid, $id, $radius, $width, $height, $mobile_height)
663 {
664 if ( function_exists( 'wpvr_enqueue_frontend_scripts' ) ) {
665 wpvr_enqueue_frontend_scripts( 'scene' );
666 }
667 $postdata = is_array( $postdata ) ? wpvr_get_effective_panodata( $postdata ) : [];
668 $show_scene_info = ( $postdata['scene-info-enabled'] ?? 'on' ) !== 'off';
669 $tour_layout = is_array( $postdata['tourLayout'] ?? null )
670 ? ( $postdata['tourLayout']['layout'] ?? 'default' )
671 : ( $postdata['tourLayout'] ?? 'default' );
672 $is_classic_layout = 'layout1' !== $tour_layout;
673
674 if (
675 ( isset( $_GET['bricks'] ) && wp_unslash( $_GET['bricks'] ) === 'run' ) ||
676 ( defined('DOING_AJAX') && DOING_AJAX && isset( $_REQUEST['action'] ) && wp_unslash( $_REQUEST['action'] ) === 'bricks_render_element' ) ||
677 ( defined('REST_REQUEST') && REST_REQUEST && isset($_SERVER['REQUEST_URI']) && strpos( sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ), '/wp-json/bricks/v1/render_element') !== false )
678 ) {
679 return esc_html__('Bricks Editor Mode - WPVR Preview is not available.', 'wpvr');
680 }
681
682 do_action('rex_wpvr_embadded_tour', $id);
683
684 $control = false;
685 if (isset($postdata['showControls'])) {
686 $control = $postdata['showControls'];
687 }
688
689 if ($control) {
690 if (isset($postdata['customcontrol']) && is_array($postdata['customcontrol'])) {
691 $custom_control = $postdata['customcontrol'];
692 $gyro_enabled = isset($postdata['gyro']) && in_array($postdata['gyro'], array(true, 1, '1', 'on'), true);
693 $custom_control['gyroSwitch'] = $gyro_enabled ? 'on' : 'off';
694 $gyro_button_enabled = wpvr_isMobileDevice() && $custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on";
695 if ($custom_control['panupSwitch'] == "on" || $custom_control['panDownSwitch'] == "on" || $custom_control['panLeftSwitch'] == "on" || $custom_control['panRightSwitch'] == "on" || $custom_control['panZoomInSwitch'] == "on" || $custom_control['panZoomOutSwitch'] == "on" || $custom_control['panFullscreenSwitch'] == "on" || $gyro_button_enabled || $custom_control['backToHomeSwitch'] == "on") {
696 $control = false;
697 }
698 }
699 }
700
701 $vrgallery = false;
702 if (isset($postdata['vrgallery'])) {
703 $vrgallery = $postdata['vrgallery'];
704 }
705
706 $vrgallery_title = false;
707 if (isset($postdata['vrgallery_title'])) {
708 $vrgallery_title = $postdata['vrgallery_title'];
709 }
710
711 $vrgallery_display = false;
712 if (isset($postdata['vrgallery_display'])) {
713 $vrgallery_display = $postdata['vrgallery_display'];
714 }
715 $vrgallery_icon_size = false;
716 if (isset($postdata['vrgallery_icon_size'])) {
717 $vrgallery_icon_size = $postdata['vrgallery_icon_size'];
718 }
719 $gyro = false;
720 $gyro_orientation = false;
721 if (isset($postdata['gyro'])) {
722 $gyro = in_array($postdata['gyro'], array(true, 1, '1', 'on'), true);
723 if ($gyro && isset($postdata['deviceorientationcontrol'])) {
724 $gyro_orientation = in_array($postdata['deviceorientationcontrol'], array(true, 1, '1', 'on'), true);
725 }
726 }
727 //== Floor plan handle ==//
728 $floor_plan_enable = 'off';
729 $floor_plan_image = '';
730 if (isset($postdata['floor_plan_tour_enabler']) && $postdata['floor_plan_tour_enabler'] == 'on'){
731 $floor_plan_enable = $postdata['floor_plan_tour_enabler'];
732 if(isset($postdata['floor_plan_attachment_url']) && !empty($postdata['floor_plan_attachment_url'])){
733 $floor_plan_image = $postdata['floor_plan_attachment_url'];
734 }
735 }
736
737 $compass = false;
738 $audio_right = "5px";
739 if (isset($postdata['compass'])) {
740 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
741 if ($compass) {
742 $audio_right = "60px";
743 }
744 }
745 $floor_map_right = "25px";
746 if((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')){
747 $floor_map_right = "85px";
748 }elseif(isset($postdata['compass']) && $postdata['compass'] == 'on'){
749 $floor_map_right = "55px";
750 }elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
751 $floor_map_right = "25px";
752 }
753
754
755 //===explainer handle===//
756
757 $explainer_right = "10px";
758 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ( $floor_plan_enable == 'on' && !empty($floor_plan_image) ) ) {
759 $explainer_right = "130px";
760 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on' && ($floor_plan_enable == 'on' && !empty($floor_plan_image) )) {
761 $explainer_right = "100px";
762 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image) )) {
763 $explainer_right = "55px";
764 } elseif((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') ) {
765 $explainer_right = "80px";
766 }elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
767 $explainer_right = "55px";
768 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
769 $explainer_right = "30px";
770 } elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image) ) {
771 $explainer_right = "70px";
772 }
773
774
775 $enable_cardboard = '';
776 $is_cardboard = get_option('wpvr_cardboard_disable');
777 if(wpvr_isMobileDevice() && $is_cardboard == 'true' ){
778 $enable_cardboard = 'enable-cardboard';
779 $audio_right = "73px";
780 if (isset($postdata['compass'])) {
781 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
782 if ($compass) {
783 $audio_right = "130px";
784 }
785 }
786 //===Floor plan handle===//
787 $floor_map_right = "60px";
788 if((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')){
789 $floor_map_right = "150px";
790 }elseif(isset($postdata['compass']) && $postdata['compass'] == 'on'){
791 $floor_map_right = "120px";
792 }elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
793 $floor_map_right = "90px";
794 }
795
796 //===explainer handle===//
797 $explainer_right = "65px";
798
799 if ((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
800 $explainer_right = "150px";
801 } elseif((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ($floor_plan_enable == 'on' && !empty($floor_plan_image) )) {
802 $explainer_right = "180px";
803 } elseif (isset($postdata['compass']) && $postdata['compass'] == true && ($floor_plan_enable == 'on' && !empty($floor_plan_image) )) {
804 $explainer_right = "150px";
805 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image) )) {
806 $explainer_right = "120px";
807 }elseif (isset($postdata['compass']) && $postdata['compass'] == true) {
808 $explainer_right = "130px";
809 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
810 $explainer_right = "90px";
811 }elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image) ) {
812 $explainer_right = "90px";
813 }
814 }
815
816 //===explainer handle===//
817
818 $mouseZoom = true;
819 if (isset($postdata['mouseZoom'])) {
820 if($postdata['mouseZoom'] == "off") {
821 $mouseZoom = false;
822 }
823 else {
824 $mouseZoom = true;
825 }
826 }
827
828 $draggable = true;
829 if (isset($postdata['draggable'])) {
830 $draggable = ! in_array( $postdata['draggable'], array( 'off', 'false', false ), true );
831 }
832
833 $diskeyboard = false;
834 if (isset($postdata['diskeyboard'])) {
835 $diskeyboard = ! in_array( $postdata['diskeyboard'], array( 'off', 'false', false ), true );
836 }
837
838 $keyboardzoom = true;
839 if (isset($postdata['keyboardzoom'])) {
840 $keyboardzoom = ! in_array( $postdata['keyboardzoom'], array( 'off', 'false', false ), true );
841 }
842
843 $autoload = false;
844
845 if (isset($postdata['autoLoad'])) {
846 $autoload = in_array( $postdata['autoLoad'], array( true, 1, '1', 'on', 'true' ), true );
847 }
848
849 $default_scene = '';
850 if (isset($postdata['defaultscene'])) {
851 $default_scene = $postdata['defaultscene'];
852 }
853
854 $default_global_zoom = '';
855 if (isset($postdata['hfov'])) {
856 $default_global_zoom = $postdata['hfov'];
857 }
858
859 $max_global_zoom = '';
860 if (isset($postdata['maxHfov'])) {
861 $max_global_zoom = $postdata['maxHfov'];
862 }
863
864 $min_global_zoom = '';
865 if (isset($postdata['minHfov'])) {
866 $min_global_zoom = $postdata['minHfov'];
867 }
868
869 $preview = '';
870 if (isset($postdata['preview'])) {
871 $preview = $postdata['preview'];
872 }
873
874 $autorotation = '';
875 if (isset($postdata["autoRotate"])) {
876 $autorotation = $postdata["autoRotate"];
877 }
878 $autorotationinactivedelay = '';
879 if (isset($postdata["autoRotateInactivityDelay"])) {
880 $autorotationinactivedelay = $postdata["autoRotateInactivityDelay"];
881 }
882 $autorotationstopdelay = '';
883 if (isset($postdata["autoRotateStopDelay"])) {
884 $autorotationstopdelay = $postdata["autoRotateStopDelay"];
885 }
886
887 $scene_fade_duration = '';
888 if (isset($postdata['scenefadeduration'])) {
889 $scene_fade_duration = $postdata['scenefadeduration'];
890 }
891
892 $panodata = '';
893 if (isset($postdata['panodata'])) {
894 $panodata = $postdata['panodata'];
895 }
896
897 $hotspoticoncolor = '#00b4ff';
898 $hotspotblink = 'on';
899 $default_data = array();
900 if ($default_global_zoom != '' && $max_global_zoom != '' && $min_global_zoom != '') {
901 $default_data = array("firstScene" => $default_scene, "sceneFadeDuration" => $scene_fade_duration, "hfov" => $default_global_zoom, "maxHfov" => $max_global_zoom, "minHfov" => $min_global_zoom);
902 } else {
903 $default_data = array("firstScene" => $default_scene, "sceneFadeDuration" => $scene_fade_duration);
904 }
905
906 $scene_data = array();
907
908 if (!empty($panodata["scene-list"])) {
909 foreach ($panodata["scene-list"] as $panoscenes) {
910 $scene_ititle = '';
911 if (isset($panoscenes["scene-ititle"])) {
912 $scene_ititle = sanitize_text_field($panoscenes["scene-ititle"]);
913 }
914
915 $scene_author = '';
916 if (isset($panoscenes["scene-author"])) {
917 $scene_author = sanitize_text_field($panoscenes["scene-author"]);
918 }
919
920 $scene_author_url = '';
921 if (isset($panoscenes["scene-author-url"])) {
922 $scene_author_url = esc_url($panoscenes["scene-author-url"]);
923 }
924
925 $scene_vaov = 180;
926 if (isset($panoscenes["scene-vaov"])) {
927 $scene_vaov = (float)$panoscenes["scene-vaov"];
928 }
929
930 $scene_haov = 360;
931 if (isset($panoscenes["scene-haov"])) {
932 $scene_haov = (float)$panoscenes["scene-haov"];
933 }
934
935
936 $scene_vertical_offset = 0;
937 if (isset($panoscenes["scene-vertical-offset"])) {
938 $scene_vertical_offset = (float)$panoscenes["scene-vertical-offset"];
939 }
940
941 $default_scene_pitch = null;
942 if (isset($panoscenes["scene-pitch"])) {
943 $default_scene_pitch = (float)$panoscenes["scene-pitch"];
944 }
945
946 $default_scene_yaw = null;
947 if (isset($panoscenes["scene-yaw"])) {
948 $default_scene_yaw = (float)$panoscenes["scene-yaw"];
949 }
950
951 $scene_max_pitch = '';
952 if (isset($panoscenes["scene-maxpitch"])) {
953 $scene_max_pitch = (float)$panoscenes["scene-maxpitch"];
954 }
955
956
957 $scene_min_pitch = '';
958 if (isset($panoscenes["scene-minpitch"])) {
959 $scene_min_pitch = (float)$panoscenes["scene-minpitch"];
960 }
961
962
963 $scene_max_yaw = '';
964 if (isset($panoscenes["scene-maxyaw"])) {
965 $scene_max_yaw = (float)$panoscenes["scene-maxyaw"];
966 }
967
968
969 $scene_min_yaw = '';
970 if (isset($panoscenes["scene-minyaw"])) {
971 $scene_min_yaw = (float)$panoscenes["scene-minyaw"];
972 }
973
974 $default_zoom = 100;
975 if (isset($panoscenes["scene-zoom"]) && $panoscenes["scene-zoom"] != "") {
976 $default_zoom = $panoscenes["scene-zoom"];
977 } else {
978 if ($default_global_zoom != '') {
979 $default_zoom = (int)$default_global_zoom;
980 }
981 }
982
983
984 $max_zoom = 120;
985 if (isset($panoscenes["scene-maxzoom"]) && $panoscenes["scene-maxzoom"] != '') {
986 $max_zoom = (int)$panoscenes["scene-maxzoom"];
987 } else {
988 if ($max_global_zoom != '') {
989 $max_zoom = (int)$max_global_zoom;
990 }
991 }
992
993
994
995 $min_zoom = 50;
996 if (isset($panoscenes["scene-minzoom"]) && $panoscenes["scene-minzoom"] != '') {
997 $min_zoom = (int)$panoscenes["scene-minzoom"];
998 } else {
999 if ($min_global_zoom != '') {
1000 $min_zoom = (int)$min_global_zoom;
1001 }
1002 }
1003
1004
1005 $hotspot_datas = array();
1006 if (isset($panoscenes["hotspot-list"])) {
1007 $hotspot_datas = $panoscenes["hotspot-list"];
1008 }
1009
1010 $hotspots = array();
1011
1012
1013 foreach ($hotspot_datas as $hotspot_data) {
1014 $status = get_option('wpvr_edd_license_status');
1015 if ($status !== false && $status == 'valid') {
1016 if (!empty($hotspot_data["hotspot-customclass-pro"]) && $hotspot_data["hotspot-customclass-pro"] != 'none') {
1017 $hotspot_data['hotspot-customclass'] = $hotspot_data["hotspot-customclass-pro"] . ' custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot_data['hotspot-title']);
1018 }
1019 if (isset($hotspot_data['hotspot-blink'])) {
1020 $hotspotblink = $hotspot_data['hotspot-blink'];
1021 }
1022 }
1023 $has_hotspot_scene_pitch = isset($hotspot_data["hotspot-scene-pitch"])
1024 && $hotspot_data["hotspot-scene-pitch"] !== '';
1025 $has_hotspot_scene_yaw = isset($hotspot_data["hotspot-scene-yaw"])
1026 && $hotspot_data["hotspot-scene-yaw"] !== '';
1027
1028 $hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
1029 $hotspot_content = '';
1030
1031 ob_start();
1032 do_action('wpvr_hotspot_content', $hotspot_data);
1033 $hotspot_content = ob_get_clean();
1034
1035 if (!$hotspot_content) {
1036 $hotspot_content = $hotspot_data["hotspot-content"];
1037 }
1038
1039 $hotspot_url = $this->normalize_hotspot_external_url($hotspot_data["hotspot-url"] ?? '');
1040
1041 if (isset($hotspot_data["hotspot-url-open"])) {
1042 // New UI: "on" means new tab; legacy renderer: "on" means same tab.
1043 $wpvr_url_open = $hotspot_data["hotspot-url-open"] === 'on' ? 'off' : 'on';
1044 } elseif (isset($hotspot_data["wpvr_url_open"][0])) {
1045 $wpvr_url_open = $hotspot_data["wpvr_url_open"][0];
1046 } else {
1047 $wpvr_url_open = "off";
1048 }
1049 $on_hover_content = preg_replace_callback(
1050 '/<p>\s*(<img[^>]*>)\s*<br>\s*<\/p>/i',
1051 function ($matches) {
1052 return $matches[1];
1053 },
1054 $hotspot_data['hotspot-hover'] ?? ''
1055 );
1056
1057
1058 $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1059 $on_hover_content = $this->sanitize_content_preserve_styles($on_hover_content ?? '', false);
1060 $on_click_content = preg_replace_callback('/<img[^>]*>/', "replace_callback", $hotspot_content ?? '');
1061 $on_click_content = $this->sanitize_content_preserve_styles($on_click_content ?? '', $is_fluent_form);
1062
1063 // Shape is independent of the optional custom icon in the
1064 // new editor, so it must always be included in the public
1065 // hotspot configuration.
1066 $hotspot_shape = isset( $hotspot_data['hotspot-shape'] )
1067 && in_array( $hotspot_data['hotspot-shape'], [ 'round', 'square', 'hexagon' ], true )
1068 ? $hotspot_data['hotspot-shape']
1069 : 'round';
1070 $hotspot_data_for_on_click=[];
1071 if( ('info' === $hotspot_type || 'fluent_form' === $hotspot_data["hotspot-type"]) && !empty($on_click_content)){
1072 $hotspot_data_for_on_click = [
1073 'on_click_content' => $on_click_content,
1074 'tour_id' => $id,
1075 'scene_id' => $panoscenes['scene-id'],
1076 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1077 ];
1078 } elseif('info' === $hotspot_type && !empty($hotspot_url)){
1079 $hotspot_data_for_on_click = [
1080 'on_click_content' => '',
1081 'tour_id' => $id,
1082 'scene_id' => $panoscenes['scene-id'],
1083 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1084 ];
1085 }
1086
1087 $hotspot_info = array(
1088 "text" => esc_html(sanitize_text_field($hotspot_data["hotspot-title"])),
1089 "pitch" => $hotspot_data["hotspot-pitch"],
1090 "yaw" => $hotspot_data["hotspot-yaw"],
1091 "type" => $hotspot_type,
1092 "cssClass" => $hotspot_data["hotspot-customclass"],
1093 "URL" => $hotspot_url,
1094 "wpvr_url_open" => $wpvr_url_open,
1095 "clickHandlerArgs" => $hotspot_data_for_on_click,
1096 'createTooltipArgs' => !empty(trim($on_hover_content)) ? trim($on_hover_content) : '',
1097 "sceneId" => $hotspot_data["hotspot-scene"],
1098 'hotspot_type' => $hotspot_data['hotspot-type'],
1099 'hotspot_target' => 'notBlank',
1100 'hotspot_shape' => $hotspot_shape,
1101 );
1102
1103 // An omitted entry angle lets Pannellum use the target
1104 // scene's own default face. Keep explicit zero values.
1105 if (!empty($hotspot_data["hotspot-scene"])) {
1106 if ($has_hotspot_scene_pitch) {
1107 $hotspot_info['targetPitch'] = (float)$hotspot_data["hotspot-scene-pitch"];
1108 }
1109 if ($has_hotspot_scene_yaw) {
1110 $hotspot_info['targetYaw'] = (float)$hotspot_data["hotspot-scene-yaw"];
1111 }
1112 }
1113 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1114
1115 if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1116 unset($hotspot_info["cssClass"]);
1117 }
1118 array_push($hotspots, $hotspot_info);
1119 }
1120
1121 $device_scene = $panoscenes['scene-attachment-url'];
1122 $mobile_media_resize = get_option('mobile_media_resize');
1123 $file_accessible = ini_get('allow_url_fopen');
1124 if ($mobile_media_resize == "true" && $device_scene ) {
1125 if ($file_accessible == "1") {
1126 $image_info = getimagesize($device_scene);
1127 if ( isset($image_info[0]) && $image_info[0] > 4096) {
1128 $src_to_id_for_mobile = '';
1129 $src_to_id_for_desktop = '';
1130 if (wpvr_isMobileDevice()) {
1131 $src_to_id_for_mobile = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1132 if ($src_to_id_for_mobile) {
1133 $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1134 if ($mobile_scene[3]) {
1135 $device_scene = $mobile_scene[0];
1136 }
1137 }
1138 } else {
1139 $src_to_id_for_desktop = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1140 if ($src_to_id_for_desktop) {
1141 $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1142 if (isset($desktop_scene[0])) {
1143 $device_scene = $desktop_scene[0];
1144 }
1145 }
1146 }
1147 }
1148 }
1149 }
1150
1151 $scene_info = array();
1152
1153 if ($panoscenes["scene-type"] == 'cubemap') {
1154 $pano_attachment = array(
1155 $panoscenes["scene-attachment-url-face0"],
1156 $panoscenes["scene-attachment-url-face1"],
1157 $panoscenes["scene-attachment-url-face2"],
1158 $panoscenes["scene-attachment-url-face3"],
1159 $panoscenes["scene-attachment-url-face4"],
1160 $panoscenes["scene-attachment-url-face5"]
1161 );
1162
1163 $scene_info = array("type" => $panoscenes["scene-type"], "cubeMap" => $pano_attachment, "pitch" => $default_scene_pitch, "maxPitch" => $scene_max_pitch, "minPitch" => $scene_min_pitch, "maxYaw" => $scene_max_yaw, "minYaw" => $scene_min_yaw, "yaw" => $default_scene_yaw, "hfov" => $default_zoom, "maxHfov" => $max_zoom, "minHfov" => $min_zoom, "title" => $scene_ititle, "author" => $scene_author, "authorURL" => $scene_author_url, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
1164 } else {
1165 $scene_info = array("type" => $panoscenes["scene-type"], "panorama" => $device_scene, "pitch" => $default_scene_pitch, "maxPitch" => $scene_max_pitch, "minPitch" => $scene_min_pitch, "maxYaw" => $scene_max_yaw, "minYaw" => $scene_min_yaw, "yaw" => $default_scene_yaw, "hfov" => $default_zoom, "maxHfov" => $max_zoom, "minHfov" => $min_zoom, "title" => $scene_ititle, "author" => $scene_author, "authorURL" => $scene_author_url, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
1166 }
1167
1168
1169 if (isset($panoscenes["ptyscene"])) {
1170 if ($panoscenes["ptyscene"] == "off") {
1171 unset($scene_info['pitch']);
1172 unset($scene_info['yaw']);
1173 }
1174 }
1175
1176 if (!$show_scene_info || empty($panoscenes["scene-ititle"])) {
1177 unset($scene_info['title']);
1178 }
1179 if (!$show_scene_info || empty($panoscenes["scene-author"])) {
1180 unset($scene_info['author']);
1181 }
1182 if (!$show_scene_info || empty($panoscenes["scene-author-url"])) {
1183 unset($scene_info['authorURL']);
1184 }
1185
1186 if (empty($scene_vaov)) {
1187 unset($scene_info['vaov']);
1188 }
1189
1190 if (empty($scene_haov)) {
1191 unset($scene_info['haov']);
1192 }
1193
1194 if (empty($scene_vertical_offset)) {
1195 unset($scene_info['vOffset']);
1196 }
1197
1198 if (isset($panoscenes["cvgscene"])) {
1199 if ($panoscenes["cvgscene"] == "off") {
1200 unset($scene_info['maxPitch']);
1201 unset($scene_info['minPitch']);
1202 }
1203 }
1204 if (empty($panoscenes["scene-maxpitch"])) {
1205 unset($scene_info['maxPitch']);
1206 }
1207
1208 if (empty($panoscenes["scene-minpitch"])) {
1209 unset($scene_info['minPitch']);
1210 }
1211
1212 if (isset($panoscenes["chgscene"])) {
1213 if ($panoscenes["chgscene"] == "off") {
1214 unset($scene_info['maxYaw']);
1215 unset($scene_info['minYaw']);
1216 }
1217 }
1218 if (empty($panoscenes["scene-maxyaw"])) {
1219 unset($scene_info['maxYaw']);
1220 }
1221
1222 if (empty($panoscenes["scene-minyaw"])) {
1223 unset($scene_info['minYaw']);
1224 }
1225
1226 // if (isset($panoscenes["czscene"])) {
1227 // if ($panoscenes["czscene"] == "off") {
1228 // unset($scene_info['hfov']);
1229 // unset($scene_info['maxHfov']);
1230 // unset($scene_info['minHfov']);
1231 // }
1232 // }
1233
1234 $scene_array = array();
1235 $scene_array = array(
1236 $panoscenes["scene-id"] => $scene_info
1237 );
1238 $scene_data[$panoscenes["scene-id"]] = $scene_info;
1239 }
1240 }
1241
1242 $pano_id_array = array();
1243 $pano_id_array = array("panoid" => $panoid);
1244 $pano_response = array();
1245 $pano_response = array("autoLoad" => $autoload, "showControls" => $control, "orientationSupport" => 'false', "compass" => $compass, 'orientationOnByDefault' => $gyro_orientation, "mouseZoom" => $mouseZoom, "draggable" => $draggable, 'disableKeyboardCtrl' => $diskeyboard, 'keyboardZoom' => $keyboardzoom, "preview" => $preview, "autoRotate" => $autorotation, "autoRotateInactivityDelay" => $autorotationinactivedelay, "autoRotateStopDelay" => $autorotationstopdelay, "default" => $default_data, "scenes" => $scene_data);
1246 if (empty($autorotation)) {
1247 unset($pano_response['autoRotate']);
1248 unset($pano_response['autoRotateInactivityDelay']);
1249 unset($pano_response['autoRotateStopDelay']);
1250 }
1251 if (empty($autorotationinactivedelay)) {
1252 unset($pano_response['autoRotateInactivityDelay']);
1253 }
1254 if (empty($autorotationstopdelay)) {
1255 unset($pano_response['autoRotateStopDelay']);
1256 }
1257 $response = array();
1258 $response = array($pano_id_array, $pano_response);
1259 if (!empty($response)) {
1260 $response = json_encode($response);
1261 }
1262
1263
1264 if (empty($width)) {
1265 $width = '600px';
1266 }
1267 if (empty($height)) {
1268 $height = '400px';
1269 }
1270 $foreground_color = '#fff';
1271 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1272 $rgb = wpvr_HTMLToRGB($hotspoticoncolor);
1273 $hsl = wpvr_RGBToHSL($rgb);
1274 if ($hsl->lightness > 200) {
1275 $foreground_color = '#000000';
1276 } else {
1277 $foreground_color = '#fff';
1278 }
1279 $html = '';
1280
1281 $html .= '<style>';
1282 if ($width == 'embed') {
1283 $html .= 'body{
1284 overflow: hidden;
1285 }';
1286 }
1287 $status = get_option('wpvr_edd_license_status');
1288 if ($status !== false && $status == 'valid') {
1289 if(isset($postdata['customcss_enable']) && $postdata['customcss_enable'] == 'on'){
1290 $html .= isset($postdata['customcss']) ? $postdata['customcss'] : '';
1291 }
1292 }
1293 $panoid2 = 'pano2'.$id;
1294 $status = get_option('wpvr_edd_license_status');
1295 if ($status !== false && $status == 'valid') {
1296 foreach ($panodata['scene-list'] as $panoscenes){
1297
1298 foreach($panoscenes['hotspot-list'] as $hotspot){
1299 if (isset($hotspot['hotspot-customclass-color-icon-value']) && !empty($hotspot['hotspot-customclass-color-icon-value'])) {
1300 $hotspoticoncolor = $hotspot['hotspot-customclass-color-icon-value'];
1301 } else {
1302 $hotspoticoncolor = "#00b4ff";
1303 }
1304 $hotspot_border = '';
1305 if(isset($hotspot['hotspot-border']) && $hotspot['hotspot-border'] == 'on'){
1306 $border_width = $hotspot['hotspot-border-width'];
1307 $border_color = $hotspot['hotspot-border-color'];
1308 $border_style = $hotspot['hotspot-border-style'];
1309 $hotspot_border = 'border: '.$border_width.'px '.$border_style.' '.$border_color.';';
1310 }
1311 $hotspot_background_color = 'background-color: ' . $hotspoticoncolor . ';';
1312 $hotspot_animation = ' animation: icon-pulse' . $panoid . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1313 '. $hotspot_border.'';
1314 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1315 if (!empty($hotspot["hotspot-customclass-pro"]) && $hotspot["hotspot-customclass-pro"] != 'none') {
1316 $border_radius = ' border-radius: 100%;';
1317 $hotspot_shape = isset($hotspot["hotspot-shape"]) ? $hotspot["hotspot-shape"] : 'round';
1318 if($hotspot_shape === 'square'){
1319 $border_radius = '';
1320 }
1321 if ($hotspot_shape === 'hexagon') {
1322 $border_radius = '';
1323 $hotspot_background_color = 'background-color: transparent;';
1324 $hotspot_animation = '';
1325 }
1326
1327 if(isset($hotspot['hotspot-custom-icon-color-value']) && !empty($hotspot['hotspot-custom-icon-color-value'])){
1328 $foreground_color = $hotspot['hotspot-custom-icon-color-value'];
1329 }
1330
1331 $html .= '#' . $panoid . ' div.pnlm-hotspot-base.fas.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1332 #' . $panoid . ' div.pnlm-hotspot-base.fab.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1333 #' . $panoid . ' div.pnlm-hotspot-base.fa-solid.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1334 #' . $panoid . ' div.pnlm-hotspot-base.fa.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1335 #' . $panoid . ' div.pnlm-hotspot-base.far.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).' {
1336 display: block !important;
1337 '.$hotspot_background_color.'
1338 color: ' . $foreground_color . ';
1339 '.$border_radius.'
1340 width: 30px;
1341 height: 30px;
1342 font-size: 16px;
1343 line-height: 30px;
1344 '.$hotspot_animation.'
1345 }';
1346
1347 if($hotspot_shape === 'hexagon'){
1348
1349 $html .= '#' . $panoid . ' .custom-' . $id . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' .hexagon-wrapper svg path {
1350 fill: ' . $hotspoticoncolor . ';
1351 }';
1352
1353 $html .= '#' . $panoid . ' .custom-' . $id . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . '.pnlm-tooltip:after{
1354 content: "";
1355 position: absolute;
1356 left: 50%;
1357 top: 50%;
1358 transform: translate(-50%, -50%);
1359 width: 85%;
1360 height: 85%;
1361 animation: icon-pulse' . $panoid . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1362 border-radius: 100%;
1363 z-index: -2;
1364 }';
1365
1366 }
1367
1368 $html .= '#' . $panoid2 . ' div.pnlm-hotspot-base.fas.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1369 #' . $panoid2 . ' div.pnlm-hotspot-base.fab.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1370 #' . $panoid2 . ' div.pnlm-hotspot-base.fa-solid.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1371 #' . $panoid2 . ' div.pnlm-hotspot-base.fa.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).',
1372 #' . $panoid2 . ' div.pnlm-hotspot-base.far.custom-' . $id.'-' . $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']).' {
1373 display: block !important;
1374 '.$hotspot_background_color.'
1375 color: ' . $foreground_color . ';
1376 '.$border_radius.'
1377 width: 30px;
1378 height: 30px;
1379 font-size: 16px;
1380 line-height: 30px;
1381 '.$hotspot_animation.'
1382 }';
1383 }
1384 if (isset($hotspot['hotspot-blink'])) {
1385 $hotspotblink = $hotspot['hotspot-blink'];
1386 if ($hotspotblink == 'on') {
1387 $html .= '@-webkit-keyframes icon-pulse' .$panoid .'-'. $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']) .' {
1388 0% {
1389 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1390 }
1391 100% {
1392 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1393 }
1394 }
1395 @keyframes icon-pulse' . $panoid . ' {
1396 0% {
1397 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1398 }
1399 100% {
1400 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1401 }
1402 }';
1403 $html .= '@-webkit-keyframes icon-pulse' .$panoid2 .'-'. $panoscenes['scene-id'] .'-'. sanitize_html_class($hotspot['hotspot-title']) .' {
1404 0% {
1405 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1406 }
1407 100% {
1408 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1409 }
1410 }
1411 @keyframes icon-pulse' . $panoid . ' {
1412 0% {
1413 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1414 }
1415 100% {
1416 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1417 }
1418 }';
1419 }
1420 }
1421
1422 }
1423
1424 }
1425
1426 }
1427
1428 $status = get_option('wpvr_edd_license_status');
1429 if ($status !== false && $status == 'valid') {
1430 if (!$gyro) {
1431 $html .= '#' . $panoid . ' div.pnlm-orientation-button {
1432 display: none;
1433 }';
1434 }
1435 } else {
1436 $html .= '#' . $panoid . ' div.pnlm-orientation-button {
1437 display: none;
1438 }';
1439 }
1440 $floor_plan_custom_color = isset($postdata['floor_plan_custom_color']) ? $postdata['floor_plan_custom_color'] : '#cca92c';
1441 $foreground_color_pointer = '#fff';
1442 if($floor_plan_custom_color != ''){
1443 $pointer_pulse = wpvr_hex2rgb($floor_plan_custom_color);
1444 $floor_rgb = wpvr_HTMLToRGB($floor_plan_custom_color);
1445 $floor_hsl = wpvr_RGBToHSL($floor_rgb);
1446 if ($floor_hsl->lightness > 200) {
1447 $foreground_color_pointer = '#000000';
1448 }
1449 $html .= '
1450 .wpvr-floor-map .floor-plan-pointer.add-pulse:before {
1451 border: 17px solid '.$floor_plan_custom_color.';
1452 }
1453 @-webkit-keyframes pulse {
1454 0% {
1455 -webkit-box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0.7);
1456 }
1457 70% {
1458 -webkit-box-shadow: 0 0 0 10px rgba('.$pointer_pulse[0].', 0);
1459 }
1460 100% {
1461 -webkit-box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0);
1462 }
1463 }
1464 @keyframes pulse {
1465 0% {
1466 -moz-box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0.7);
1467 box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0.7);
1468 }
1469 70% {
1470 -moz-box-shadow: 0 0 0 10px rgba('.$pointer_pulse[0].', 0);
1471 box-shadow: 0 0 0 10px rgba('.$pointer_pulse[0].', 0);
1472 }
1473 100% {
1474 -moz-box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0);
1475 box-shadow: 0 0 0 0 rgba('.$pointer_pulse[0].', 0);
1476 }
1477 }';
1478 }
1479
1480 $html .= '</style>';
1481
1482
1483 $scene_animation = isset($postdata['sceneAnimation']) ? $postdata['sceneAnimation'] : 'off';
1484 $scene_animation_enabled = in_array( $scene_animation, array( 'on', '1', 1, true ), true );
1485
1486 if( $scene_animation_enabled && is_plugin_active( 'wpvr-pro/wpvr-pro.php' ) ) {
1487 $animation_type = isset($postdata['sceneAnimationName']) ? $postdata['sceneAnimationName'] : 'none';
1488 $animation_type = $animation_type === 'fade' ? 'fade_in' : $animation_type;
1489 $animationDuration = isset($postdata['sceneAnimationTransitionDuration']) ? $postdata['sceneAnimationTransitionDuration'] : '500ms';
1490 $animationDelay = isset($postdata['sceneAnimationTransitionDelay']) ? $postdata['sceneAnimationTransitionDelay'] : '0ms';
1491 $animation_css = apply_filters('wpvr_tour_scene_animation',$animation_type,$animationDuration,$animationDelay,$postdata,$id);
1492 $html .= $animation_css;
1493 }
1494
1495 if ($width == 'fullwidth') {
1496 $width = "100%";
1497 }
1498
1499 if (wpvr_isMobileDevice()) {
1500 $html .= '<div id="master-container" class="wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $width . '; width: 100%; height: ' . $mobile_height . '; border-radius:' . $radius . '; direction:ltr; ">';
1501 } else {
1502 $html .= '<div id="master-container" class="wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $width . '; width: 100%; height: ' . $height . '; border-radius:' . $radius . '; direction:ltr; ">';
1503 }
1504 $is_pro = apply_filters('is_wpvr_pro_active',false);
1505 $status = get_option('wpvr_edd_license_status');
1506 $is_cardboard = get_option('wpvr_cardboard_disable');
1507 if ($status !== false && 'valid' == $status && $is_pro && wpvr_isMobileDevice() && $is_cardboard == 'true' ) {
1508 $html .= '<button class="fullscreen-button">';
1509 $html .= '<span class="expand">';
1510 $html .= '<i class="fas fa-expand" aria-hidden="true"></i>';
1511 $html .= '</span>';
1512
1513 $html .= '<span class="compress">';
1514 $html .= '<i class="fas fa-minimize" aria-hidden="true"></i>';
1515 $html .= '</span>';
1516 $html .= '</button>';
1517 $embed_mode = '';
1518 if($width == "embed"){
1519 $embed_mode = "vr-embade-mode";
1520 }
1521 $html .= '<label class="wpvr-cardboard-switcher '.$embed_mode.'">
1522 <input type="checkbox" class="vr_mode_change' . $id . '" name="vr_mode_change" value="off">
1523 <span class="switcher-box">
1524 <span class="normal-mode-tooltip">Normal VR Mode</span>
1525 <svg width="78" height="60" viewBox="0 0 78 60" fill="none" xmlns="http://www.w3.org/2000/svg">
1526 <path d="M42.25 21.4286C42.25 22.2811 41.9076 23.0986 41.2981 23.7014C40.6886 24.3042 39.862 24.6429 39 24.6429C38.138 24.6429 37.3114 24.3042 36.7019 23.7014C36.0924 23.0986 35.75 22.2811 35.75 21.4286C35.75 20.5761 36.0924 19.7585 36.7019 19.1557C37.3114 18.5529 38.138 18.2143 39 18.2143C39.862 18.2143 40.6886 18.5529 41.2981 19.1557C41.9076 19.7585 42.25 20.5761 42.25 21.4286ZM19.5 30C18.9254 30 18.3743 30.2258 17.9679 30.6276C17.5616 31.0295 17.3333 31.5745 17.3333 32.1429C17.3333 32.7112 17.5616 33.2562 17.9679 33.6581C18.3743 34.06 18.9254 34.2857 19.5 34.2857H28.1667C28.7413 34.2857 29.2924 34.06 29.6987 33.6581C30.1051 33.2562 30.3333 32.7112 30.3333 32.1429C30.3333 31.5745 30.1051 31.0295 29.6987 30.6276C29.2924 30.2258 28.7413 30 28.1667 30H19.5ZM47.6667 32.1429C47.6667 31.5745 47.8949 31.0295 48.3013 30.6276C48.7076 30.2258 49.2587 30 49.8333 30H58.5C59.0746 30 59.6257 30.2258 60.0321 30.6276C60.4384 31.0295 60.6667 31.5745 60.6667 32.1429C60.6667 32.7112 60.4384 33.2562 60.0321 33.6581C59.6257 34.06 59.0746 34.2857 58.5 34.2857H49.8333C49.2587 34.2857 48.7076 34.06 48.3013 33.6581C47.8949 33.2562 47.6667 32.7112 47.6667 32.1429ZM32.5 0C31.9254 0 31.3743 0.225765 30.9679 0.627629C30.5616 1.02949 30.3333 1.57454 30.3333 2.14286V8.57143H18.4167C14.8693 8.57183 11.4528 9.89617 8.84994 12.2798C6.24706 14.6634 4.64954 17.9306 4.37667 21.4286H2.16667C1.59203 21.4286 1.04093 21.6543 0.634602 22.0562C0.228273 22.4581 0 23.0031 0 23.5714V36.4286C0 36.9969 0.228273 37.5419 0.634602 37.9438C1.04093 38.3457 1.59203 38.5714 2.16667 38.5714H4.33333V46.0714C4.33333 49.7655 5.81711 53.3083 8.45825 55.9204C11.0994 58.5325 14.6815 60 18.4167 60H25.3933C29.1269 59.9986 32.7071 58.5311 35.347 55.92L37.921 53.3786C38.0618 53.2393 38.229 53.1288 38.4131 53.0534C38.5971 52.978 38.7943 52.9392 38.9935 52.9392C39.1927 52.9392 39.3899 52.978 39.5739 53.0534C39.758 53.1288 39.9252 53.2393 40.066 53.3786L42.6357 55.92C45.2766 58.5322 48.8586 59.9998 52.5937 60H59.5833C63.3185 60 66.9006 58.5325 69.5418 55.9204C72.1829 53.3083 73.6667 49.7655 73.6667 46.0714V38.5714H75.8333C76.408 38.5714 76.9591 38.3457 77.3654 37.9438C77.7717 37.5419 78 36.9969 78 36.4286V23.5714C78 23.0031 77.7717 22.4581 77.3654 22.0562C76.9591 21.6543 76.408 21.4286 75.8333 21.4286H73.6233C73.3505 17.9306 71.753 14.6634 69.1501 12.2798C66.5472 9.89617 63.1307 8.57183 59.5833 8.57143H47.6667V2.14286C47.6667 1.57454 47.4384 1.02949 47.0321 0.627629C46.6257 0.225765 46.0746 0 45.5 0H32.5ZM69.3333 22.5V46.0714C69.3333 48.6289 68.3061 51.0816 66.4776 52.89C64.6491 54.6983 62.1692 55.7143 59.5833 55.7143H52.5937C50.0093 55.7132 47.5311 54.6973 45.7037 52.89L43.1297 50.3486C42.5864 49.8108 41.9413 49.3842 41.2312 49.0931C40.5211 48.8021 39.76 48.6522 38.9913 48.6522C38.2227 48.6522 37.4616 48.8021 36.7515 49.0931C36.0414 49.3842 35.3963 49.8108 34.853 50.3486L32.2833 52.89C30.4559 54.6973 27.9777 55.7132 25.3933 55.7143H18.4167C15.8308 55.7143 13.3509 54.6983 11.5224 52.89C9.6939 51.0816 8.66667 48.6289 8.66667 46.0714V22.5C8.66667 19.9426 9.6939 17.4899 11.5224 15.6815C13.3509 13.8731 15.8308 12.8571 18.4167 12.8571H59.5833C62.1692 12.8571 64.6491 13.8731 66.4776 15.6815C68.3061 17.4899 69.3333 19.9426 69.3333 22.5Z" fill="#216DF0"/>
1527 </svg>
1528 </span>
1529 </label>';
1530
1531 }
1532
1533 if ($width == 'fullwidth') {
1534 if (wpvr_isMobileDevice()) {
1535 $html .= '<div class="cardboard-vrfullwidth vrfullwidth">';
1536 $html .= '<div id="pano2' . $id . '" class="pano-wrap pano-left cardboard-half" style="width: 49%!important; border-radius:' . $radius . ' text-align:center; direction:ltr;" ><div id="center-pointer2' . $id . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1537 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style="width: 100%; text-align:center; direction:ltr; border-radius:' . $radius . '" >';
1538 } else {
1539 $html .= '<div id="pano2' . $id . '" class="pano-wrap pano-left" style="width: 49%; border-radius:' . $radius . '"><div id="center-pointer2' . $id . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1540 if ($radius) {
1541 $html .= '<div id="pano' . $id . '" class="pano-wrap vrfullwidth" style=" text-align:center; height: ' . $height . '; border-radius:' . $radius . '; direction:ltr;" >';
1542 } else {
1543 $html .= '<div id="pano' . $id . '" class="pano-wrap vrfullwidth" style=" text-align:center; height: ' . $height . '; direction:ltr;" >';
1544 }
1545 }
1546 } elseif ($width == 'embed') {
1547 $html .= '<div class="cardboard-vrembed vrembed">';
1548 $html .= '<div id="pano2' . $id . '" class="pano-wrap pano-left" style=" width: 49%!important; text-align:center; direction:ltr;" ><div id="center-pointer2' . $id . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1549 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style=" text-align:center; direction:ltr;" >';
1550 } else {
1551 if (wpvr_isMobileDevice()) {
1552 $html .= '<div id="pano2' . $id . '" class="pano-wrap pano-left cardboard-half" style="width: 49%; border-radius:' . $radius . '"><div id="center-pointer2' . $id . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1553 if ($radius) {
1554 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style=" width: 100%; border-radius:' . $radius . ';">';
1555 } else {
1556 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style=" width: 100%; ">';
1557 }
1558 } else {
1559 $html .= '<div id="pano2' . $id . '" class="pano-wrap pano-left" style="width: 49%; border-radius:' . $radius . '"><div id="center-pointer2' . $id . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1560
1561 if ($radius) {
1562 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style="width: 100%; border-radius:' . $radius . ';">';
1563 } else {
1564 $html .= '<div id="pano' . $id . '" class="pano-wrap pano-right" style="width: 100%;">';
1565 }
1566 }
1567 }
1568 // Vr mode transction scene to scene
1569 if ($status !== false && 'valid' == $status && $is_pro) {
1570 $html .= '<div id="center-pointer' . $id . '" class="vr-pointer-container" style="display:none"><span class="center-pointer"></span></div>';
1571 }
1572 $social_logo_top = '';
1573 //===company logo===//
1574 if (isset($postdata['cpLogoSwitch'])) {
1575 $cpLogoImg = $postdata['cpLogoImg'] ?? '';
1576 $cpLogoContent = $postdata['cpLogoContent'] ?? '';
1577 if ($postdata['cpLogoSwitch'] == 'on' && 'valid' == $status && $is_pro) {
1578 $html .= '<div id="cp-logo-controls">';
1579 $html .= '<div class="cp-logo-ctrl" id="cp-logo">';
1580 if ($cpLogoImg) {
1581 $social_logo_top = '50px';
1582 $html .= '<img loading="lazy" src="' . $cpLogoImg . '" alt="Company Logo">';
1583 }
1584
1585 if ($cpLogoContent) {
1586 $html .= '<div class="cp-info">' . esc_attr($cpLogoContent) . '</div>';
1587 }
1588 $html .= '</div>';
1589 $html .= '</div>';
1590 }
1591 }
1592 //===company logo ends===//
1593
1594 //===Generic Form===//
1595 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on' && 'valid' == $status && $is_pro) {
1596 // Process shortcode with fallback handling
1597 $shortcode_content = '';
1598 if (isset($postdata["genericformshortcode"]) && !empty(trim($postdata["genericformshortcode"]))) {
1599 $shortcode_content = do_shortcode( $postdata["genericformshortcode"] );
1600 } else {
1601 $shortcode_content = '<p class="error-message">No shortcode found.</p>';
1602 }
1603
1604 // Generate the form trigger button
1605 $generic_form_icon = isset($postdata['genericformicon']) ? (string) $postdata['genericformicon'] : 'fab fa-wpforms';
1606 $generic_form_icon = implode(' ', array_filter(array_map('sanitize_html_class', preg_split('/\s+/', $generic_form_icon))));
1607 $generic_form_icon = $generic_form_icon ?: 'fab fa-wpforms';
1608 $generic_form_icon_color = sanitize_hex_color($postdata['genericformiconcolor'] ?? '') ?: '#f7fffb';
1609 $html .= '<div class="generic_form_button" id="generic_form_button_' . esc_attr($id) . '">';
1610 $html .= '<div class="generic-form-icon" title ="Generic Form" id="generic_form_target_' . esc_attr($id) . '"><i class="' . esc_attr($generic_form_icon) . '" style="color:' . esc_attr($generic_form_icon_color) . ';"></i></div>';
1611 $html .= '</div>';
1612
1613 // Generate the modal form container
1614 $html .= '<div class="wpvr-generic-form" id="wpvr-generic-form' . esc_attr($id) . '" style="display: none">';
1615 $html .= '<span class="close-generic-form"><i class="fa fa-times"></i></span>';
1616 $html .= '<div class="generic-form-container">' . $shortcode_content . '</div>';
1617 $html .= '</div>';
1618 }
1619 //===Generic Form ends===//
1620
1621 //===Background Tour===//
1622 if (isset($postdata['bg_tour_enabler'])) {
1623
1624 $bg_tour_enabler = $postdata['bg_tour_enabler'];
1625 if ($bg_tour_enabler == 'on') {
1626 $bg_tour_navmenu = $postdata['bg_tour_navmenu'] ?? 'off';
1627 $bg_tour_title = $postdata['bg_tour_title'] ?? '';
1628 $bg_tour_subtitle = $postdata['bg_tour_subtitle'] ?? '';
1629
1630 if ($bg_tour_navmenu == 'on') {
1631 $menuLocations = get_nav_menu_locations();
1632 if (!empty($menuLocations['primary'])) {
1633 $menuID = $menuLocations['primary'];
1634 $primaryNav = wp_get_nav_menu_items($menuID);
1635 $html .= '<ul class="wpvr-navbar-container">';
1636 foreach ($primaryNav as $primaryNav_key => $primaryNav_value) {
1637 if ($primaryNav_value->menu_item_parent == "0") {
1638 $html .= '<li>';
1639 $html .= '<a href="' . $primaryNav_value->url . '">' . $primaryNav_value->title . '</a>';
1640 $html .= '<ul class="wpvr-navbar-dropdown">';
1641 foreach ($primaryNav as $pm_key => $pm_value) {
1642 if ($pm_value->menu_item_parent == $primaryNav_value->ID) {
1643 $html .= '<li>';
1644 $html .= '<a href="' . $pm_value->url . '">' . $pm_value->title . '</a>';
1645 $html .= '</li>';
1646 }
1647 }
1648 $html .= '</ul>';
1649 $html .= '</li>';
1650 }
1651 }
1652 $html .= '</ul>';
1653 }
1654 }
1655 if($is_pro && 'valid' == $status ){
1656 $html .= '<div class="wpvr-home-content">';
1657 $html .= '<div class="wpvr-home-title">' . $bg_tour_title . '</div>';
1658 $html .= '<div class="wpvr-home-subtitle">' . $bg_tour_subtitle . '</div>';
1659 $html .= '</div>';
1660 }
1661 }
1662 }
1663 //===Background Tour End===//
1664
1665 //===Custom Control===//
1666 if (isset($custom_control)) {
1667 $gyro_button_enabled = wpvr_isMobileDevice() && $custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on";
1668 if ($custom_control['panZoomInSwitch'] == "on" || $custom_control['panZoomOutSwitch'] == "on" || $gyro_button_enabled || $custom_control['backToHomeSwitch'] == "on") {
1669 $html .= '<div id="zoom-in-out-controls' . $id . '" class="zoom-in-out-controls">';
1670
1671 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
1672 $html .= '<div class="ctrl" id="backToHome' . $id . '"><i class="' . $custom_control['backToHomeIcon'] . '" style="color:' . $custom_control['backToHomeColor'] . ';"></i></div>';
1673 }
1674
1675 if ($custom_control['panZoomInSwitch'] == "on" && 'valid' == $status && $is_pro) {
1676 $html .= '<div class="ctrl" id="zoom-in' . $id . '"><i class="' . $custom_control['panZoomInIcon'] . '" style="color:' . $custom_control['panZoomInColor'] . ';"></i></div>';
1677 }
1678
1679 if ($custom_control['panZoomOutSwitch'] == "on" && 'valid' == $status && $is_pro) {
1680 $html .= '<div class="ctrl" id="zoom-out' . $id . '"><i class="' . $custom_control['panZoomOutIcon'] . '" style="color:' . $custom_control['panZoomOutColor'] . ';"></i></div>';
1681 }
1682 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
1683 $html .= '<div class="ctrl" id="gyroscope' . $id . '" ><i class="' . $custom_control['gyroscopeIcon'] . '" style="color:' . $custom_control['gyroscopeColor'] . ';"></i></div>';
1684 }
1685 $html .= '</div>';
1686 }
1687 //===zoom in out Control===//
1688
1689 if (($custom_control['panupSwitch'] == "on" || $custom_control['panDownSwitch'] == "on" || $custom_control['panLeftSwitch'] == "on" || $custom_control['panRightSwitch'] == "on" || $custom_control['panFullscreenSwitch'] == "on" ) && 'valid' == $status && $is_pro) {
1690 //===Custom Control===//
1691 $html .= '<div class="controls" id="controls' . $id . '">';
1692
1693 if ($custom_control['panupSwitch'] == "on") {
1694 $html .= '<div class="ctrl pan-up" id="pan-up' . $id . '"><i class="' . $custom_control['panupIcon'] . '" style="color:' . $custom_control['panupColor'] . ';"></i></div>';
1695 }
1696
1697 if ($custom_control['panDownSwitch'] == "on") {
1698 $html .= '<div class="ctrl pan-down" id="pan-down' . $id . '"><i class="' . $custom_control['panDownIcon'] . '" style="color:' . $custom_control['panDownColor'] . ';"></i></div>';
1699 }
1700
1701 if ($custom_control['panLeftSwitch'] == "on") {
1702 $html .= '<div class="ctrl pan-left" id="pan-left' . $id . '"><i class="' . $custom_control['panLeftIcon'] . '" style="color:' . $custom_control['panLeftColor'] . ';"></i></div>';
1703 }
1704
1705 if ($custom_control['panRightSwitch'] == "on") {
1706 $html .= '<div class="ctrl pan-right" id="pan-right' . $id . '"><i class="' . $custom_control['panRightIcon'] . '" style="color:' . $custom_control['panRightColor'] . ';"></i></div>';
1707 }
1708
1709 if ($custom_control['panFullscreenSwitch'] == "on") {
1710 $html .= '<div class="ctrl fullscreen" id="fullscreen' . $id . '"><i class="' . $custom_control['panFullscreenIcon'] . '" style="color:' . $custom_control['panFullscreenColor'] . ';"></i></div>';
1711 }
1712 $html .= '</div>';
1713 }
1714 }
1715 //===Custom Control===//
1716
1717 //===explainer button===//
1718 $html .= wpvr_render_explainer_button(
1719 isset( $custom_control ) ? $custom_control : null,
1720 $postdata,
1721 $is_pro,
1722 $autoload,
1723 $explainer_right,
1724 $id
1725 );
1726 //===explainer button end===//
1727
1728 //===Floor map button===//
1729 $status = get_option('wpvr_edd_license_status');
1730 if ($status !== false && 'valid' == $status && $is_pro){
1731 if ($floor_plan_enable == "on" && !empty($floor_plan_image)) {
1732 $html .= '<div class="floor_map_button" id="floor_map_button_' . $id . '" style="right:'.$floor_map_right.'">';
1733 $html .= '<div class="ctrl" id="floor_map_target_' . $id . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
1734 $html .= '</div>';
1735 }
1736 }
1737 //===floor map button===//
1738
1739 if ($vrgallery && 'valid' == $status && $is_pro ) {
1740 //===Carousal setup===//
1741 $size = '';
1742 if($vrgallery_icon_size){
1743 $size = 'vrg-icon-size-large';
1744 }
1745 $html .= '<div id="vrgcontrols' . $id . '" class="vrgcontrols">';
1746
1747 $html .= '<div class="vrgctrl' . $id . ' vrbounce '.$size.'">';
1748 $html .= '</div>';
1749 $html .= '</div>';
1750
1751 $gallery_layout_class = isset($postdata['tourLayout']['layout']) && 'layout1' === $postdata['tourLayout']['layout']
1752 ? 'wpvr-gallery--modern'
1753 : 'wpvr-gallery--classic';
1754 $html .= '<div id="sccontrols' . $id . '" class="scene-gallery vrowl-carousel ' . esc_attr($gallery_layout_class) . '">';
1755 if (isset($panodata["scene-list"])) {
1756 foreach ($panodata["scene-list"] as $panoscenes) {
1757 $scene_key = $panoscenes['scene-id'];
1758
1759 if ($vrgallery_title == 'on') {
1760 $scene_key_title = isset($panoscenes['scene-ititle']) ? sanitize_text_field($panoscenes['scene-ititle']) : '';
1761 } else {
1762 $scene_key_title = "";
1763 }
1764
1765 if ($panoscenes['scene-type'] == 'cubemap') {
1766 $img_src_url = $panoscenes['scene-attachment-url-face0'];
1767 } else {
1768 $img_src_url = $panoscenes['scene-attachment-url'];
1769 }
1770
1771 $src_to_id = attachment_url_to_postid($img_src_url);
1772 $thumbnail_array = wp_get_attachment_image_src($src_to_id, 'thumbnail');
1773 if ($thumbnail_array) {
1774 $thumbnail = $thumbnail_array[0];
1775 } else {
1776 $thumbnail = $img_src_url;
1777 }
1778
1779 if( isset($postdata['tourLayout']['layout']) && 'layout1' !== $postdata['tourLayout']['layout']) {
1780 $html .= '<ul><li title="Click to view scene"><span class="scene-title" title="' . esc_attr($scene_key_title) . '">' . $scene_key_title . '</span><img loading="lazy" class="scctrl" id="' . $scene_key . '_gallery_' . $id . '" src="' . $thumbnail . '"></li></ul>';
1781 }else {
1782 $html .= '<ul><li title="Click to view scene"><img loading="lazy" class="scctrl" id="' . $scene_key . '_gallery_' . $id . '" src="' . $thumbnail . '"><span class="scene-title" title="' . esc_attr($scene_key_title) . '">' . $scene_key_title . '</span></li></ul>';
1783 }
1784 }
1785 }
1786
1787 $html .= '</div>';
1788
1789 $html .= '
1790 <div class="wpvr_slider_nav">
1791 <button type="button" role="presentation" class="wpvr_owl_prev">
1792 <div class="nav-btn prev-slide"><i class="fa fa-angle-left"></i></div>
1793 </button>
1794 <button type="button" role="presentation" class="wpvr_owl_next">
1795 <div class="nav-btn next-slide"><i class="fa fa-angle-right"></i></div>
1796 </button>
1797 </div>
1798 ';
1799
1800 //===Carousal setup end===//
1801 }
1802
1803 //===Call TO action Button===//
1804 $bg_music = isset($postdata['bg_music']) ? $postdata['bg_music'] : 'off';
1805 $bg_music_url = isset($postdata['bg_music_url']) ? $postdata['bg_music_url'] : '';
1806 $autoplay_bg_music = isset($postdata['autoplay_bg_music']) ? $postdata['autoplay_bg_music'] : 'off';
1807 $loop_bg_music = isset($postdata['loop_bg_music']) ? $postdata['loop_bg_music'] : 'off';
1808
1809 $bg_loop = ($loop_bg_music === 'on') ? 'loop' : '';
1810 $autoplay_attr = ($autoplay_bg_music === 'on') ? 'autoplay' : '';
1811 $audio_muted_attr = ($autoplay_bg_music === 'on') ? 'muted' : '';
1812 $audio_icon_class = 'fa-volume-mute'; // Always start with mute icon
1813
1814 if ($bg_music === 'on' && 'valid' == $status && $is_pro) {
1815 $html .= '<div id="adcontrol' . esc_attr( $id ) . '" class="adcontrol" style="right:' . esc_attr( $audio_right ) . '">';
1816 $html .= '<audio id="vrAudio' . esc_attr($id) . '" class="vrAudioDefault" data-autoplay="' . esc_attr($autoplay_bg_music) . '" onended="audionEnd' . esc_attr($id) . '()" ' . $autoplay_attr . ' ' . $audio_muted_attr . ' ' . $bg_loop . '>
1817 <source src="' . esc_url($bg_music_url) . '" type="audio/mpeg">
1818 Your browser does not support the audio element.
1819 </audio>';
1820 $html .= '<button onclick="playPause' . esc_attr($id) . '()" class="ctrl audio_control" id="audio_control' . esc_attr($id) . '">
1821 <i id="vr-volume' . esc_attr($id) . '" class="wpvrvolumeicon' . esc_attr($id) . ' fas ' . esc_attr($audio_icon_class) . '" style="color:#fff;"></i>
1822 </button>';
1823 $html .= '</div>';
1824 }
1825 //===Explainer video section===//
1826 $explainerContent = "";
1827 if (isset($postdata['explainerContent'])) {
1828 $explainerContent = $this->wpvr_sanitize_iframe_only($postdata['explainerContent']);
1829 }
1830 $html .= '<div class="explainer" id="explainer' . $id . '" style="display: none">';
1831 $html .= '<span class="close-explainer-video"><i class="fa fa-times"></i></span>';
1832 $html .= '' . $explainerContent . '';
1833 $html .= '</div>';
1834 //===Explainer video section End===//
1835
1836 //===Scene navigation Control===//
1837 if (isset($postdata['scene_navigation']) && $postdata['scene_navigation'] === 'on' && 'valid' == $status && $is_pro) {
1838 $scene_navigation_nav_class = 'custom-scene-navigation-nav' . ( $is_classic_layout ? ' wpvr-scene-navigation-nav--classic' : '' );
1839 $html .= '<style>
1840 #et-boc .et-l .pnlm-controls-container,
1841 .pnlm-controls-container{
1842 top: 33px;
1843 }
1844
1845 #et-boc .et-l .zoom-in-out-controls,
1846 .zoom-in-out-controls {
1847 top: 37px;
1848 }
1849 </style>';
1850 $html .= '<div id="custom-scene-navigation' . $id . '" class="custom-scene-navigation">
1851 <span class="hamburger-menu"><svg width="16" height="10" fill="none" viewBox="0 0 22 15" xmlns="http://www.w3.org/2000/svg"><rect width="21.177" height="2.647" fill="#f7fffb" rx="1.324"/><rect width="21.177" height="2.647" y="6.177" fill="#f7fffb" rx="1.324"/><rect width="21.177" height="2.647" y="12.352" fill="#f7fffb" rx="1.324"/></svg></span>
1852 </div>
1853
1854 <div id="custom-scene-navigation-nav' . $id . '" class="' . esc_attr( $scene_navigation_nav_class ) . '">
1855 <ul></ul>
1856 </div>
1857 ';
1858 }
1859 //===Scene navigation Control===//
1860
1861
1862 if( 'embed' === $width){
1863 if(WPVR_Helper::is_enable_social_share($postdata) === 'on'){
1864 $html .= '<div id="wpvr-social-share-bg-box'.$id.'" class="wpvr-social-share-bg-box" style="top:'.$social_logo_top.'">
1865 <span class="share-btn-svg"><svg fill="none" viewBox="0 0 24 24" width="24" height="24" ><path fill="#1F1CF4" d="M18.4 2.4a3.2 3.2 0 00-3.2 3.2 3.2 3.2 0 00.075.67L8.01 9.901A3.2 3.2 0 005.6 8.8a3.2 3.2 0 101.325 6.112 3.2 3.2 0 001.086-.812l7.261 3.632a3.2 3.2 0 101.803-2.242c-.415.189-.786.466-1.085.81l-7.261-3.63A3.2 3.2 0 008.8 12a3.2 3.2 0 00-.075-.667L15.991 7.7a3.2 3.2 0 002.41 1.1 3.2 3.2 0 100-6.4z"/></svg></span>
1866 <nav class="wpvr-share-nav">
1867 '.WPVR_Helper::social_media_share_links_display_in_embed(home_url().'/?embed_page='. $id).'
1868 </nav>
1869 </div>';
1870 }
1871 }
1872 //===Floor plan section===//
1873 $floor_map_image = "";
1874 $floor_map_pointer = array();
1875 $floor_map_scene_id = '';
1876 $floor_plan_custom_color = '#cca92c';
1877 $floor_plan_direction_indicator = isset($postdata['floor_plan_direction_indicator']) ? $postdata['floor_plan_direction_indicator'] : 'on';
1878
1879 if (isset($postdata['floor_plan_attachment_url'])) {
1880 $floor_map_image = $postdata['floor_plan_attachment_url'];
1881 $floor_map_pointer = $postdata['floor_plan_pointer_position'];
1882 $floor_map_scene_id = $postdata['floor_plan_data_list'];
1883 $floor_plan_custom_color = $postdata['floor_plan_custom_color'];
1884 }
1885 $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $id . '" style="display: none">';
1886 $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
1887 $html .= '<img loading="lazy" src="'.$floor_map_image.'">';
1888 foreach($floor_map_pointer as $key=> $pointer_position){
1889 $html .= '<div class="floor-plan-pointer ui-draggable ui-draggable-handle" scene_id = "'.$floor_map_scene_id[$key]->value.'" id="'.$pointer_position->id.'" data-top="'.$pointer_position->data_top.'" data-left="'.$pointer_position->data_left.'" style="'.$pointer_position->style.'">
1890 <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1891 <circle cx="12" cy="12" r="11.5" stroke="'.$floor_plan_custom_color.'"/>
1892 <circle cx="12" cy="12" r="5" fill="'.$foreground_color_pointer.'"/>
1893 </svg>';
1894
1895 // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
1896 if ($floor_plan_direction_indicator === "on") {
1897 $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
1898 <path d="M0.454054 1.32433L11.7683 34.3243C11.9069 34.7285 12.287 35 12.7143 35H41.2857C41.713 35 42.0931 34.7285 42.2317 34.3243L53.5459 1.32432C53.7685 0.675257 53.2862 0 52.6 0H1.4C0.713843 0 0.231517 0.675258 0.454054 1.32433Z" fill="url(#paint0_linear_1_10)"/>
1899 <defs>
1900 <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
1901 <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
1902 <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
1903 </linearGradient>
1904 </defs>
1905 </svg>';
1906 }
1907 $html .= '</div>';
1908 }
1909 $html .= '</div>';
1910 //===Floor plan section===//
1911
1912 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
1913 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
1914 $html .= '<div class="wpvr-hotspot-tweak-contents-flex">';
1915 $html .= '<div class="wpvr-hotspot-tweak-contents">';
1916 ob_start();
1917 do_action('wpvr_hotspot_tweak_contents', $scene_data);
1918 $hotspot_content = ob_get_clean();
1919 $html .= $hotspot_content;
1920 $html .= '</div>';
1921 $html .= '</div>';
1922 $html .= '</div>';
1923
1924 $html .= '<div class="custom-ifram-wrapper" style="display: none;">';
1925 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
1926
1927 $html .= '<div class="custom-ifram-flex">';
1928 $html .= '<div class="custom-ifram">';
1929 $html .= '</div>';
1930 $html .= '</div>';
1931 $html .= '</div>';
1932
1933 $html .= '</div>';
1934 $html .= '</div>';
1935 if( "embed" == $width ){
1936 $html .= '</div>';
1937 }
1938
1939
1940 if ($status !== false && 'valid' == $status && $is_pro) {
1941 $call_to_action = isset($postdata['calltoaction']) ? $postdata['calltoaction'] : 'off';
1942 if( 'on' == $call_to_action){
1943 $buttontext = isset($postdata['buttontext']) ? $postdata['buttontext'] : '';
1944 $buttonurl = isset($postdata['buttonurl']) ? $postdata['buttonurl'] : '';
1945 $cta_btn_style = isset($postdata['button_configuration']) ? $postdata['button_configuration'] : array();
1946
1947 $button_open_new_tab = isset($cta_btn_style['button_open_new_tab']) ? $cta_btn_style['button_open_new_tab'] : "off";
1948 $target = '_self';
1949 $button_position = isset($cta_btn_style['button_position']) ? $cta_btn_style['button_position'] : "";
1950 $background_color = isset($cta_btn_style['button_background_color']) ? $cta_btn_style['button_background_color'] : "";
1951 $color = isset($cta_btn_style['button_font_color']) ? $cta_btn_style['button_font_color'] : "";
1952 $font_size = isset($cta_btn_style['button_font_size']) ? $cta_btn_style['button_font_size'] : "";
1953 $font_weight = isset($cta_btn_style['button_font_weight']) ? $cta_btn_style['button_font_weight'] : "";
1954 $text_align = isset($cta_btn_style['button_alignment']) ? $cta_btn_style['button_alignment'] : "";
1955 $text_transform = isset($cta_btn_style['button_transform']) ? $cta_btn_style['button_transform'] : "";
1956 $font_style = isset($cta_btn_style['button_text_style']) ? $cta_btn_style['button_text_style'] : "";
1957 $text_decoration = isset($cta_btn_style['button_text_decoration']) ? $cta_btn_style['button_text_decoration'] : "";
1958 $line_height = isset($cta_btn_style['button_line_height']) ? $cta_btn_style['button_line_height'] : "";
1959 $letter_spacing = isset($cta_btn_style['button_letter_spacing']) ? $cta_btn_style['button_letter_spacing'] : "";
1960 $word_spacing = isset($cta_btn_style['button_word_spacing']) ? $cta_btn_style['button_word_spacing'] : "";
1961
1962 $border_width = isset($cta_btn_style['button_border_width']) ? $cta_btn_style['button_border_width'] : "";
1963 $border_style = isset($cta_btn_style['button_border_style']) ? $cta_btn_style['button_border_style'] : "";
1964 $border_color = isset($cta_btn_style['button_border_color']) ? $cta_btn_style['button_border_color'] : "";
1965 $border_radius = isset($cta_btn_style['button_border_radius']) ? $cta_btn_style['button_border_radius'] : "";
1966
1967 $button_pt = isset($cta_btn_style['button_pt']) ? $cta_btn_style['button_pt'] : "";
1968 $button_pr = isset($cta_btn_style['button_pr']) ? $cta_btn_style['button_pr'] : "";
1969 $button_pb = isset($cta_btn_style['button_pb']) ? $cta_btn_style['button_pb'] : "";
1970 $button_pl = isset($cta_btn_style['button_pl']) ? $cta_btn_style['button_pl'] : "";
1971
1972 if($button_open_new_tab == 'on'){
1973 $target = '_blank';
1974 }
1975 $style = 'background-color: '.$background_color.';
1976 color: '.$color.';
1977 font-size: '.$font_size.'px;
1978 font-weight: '.$font_weight.';
1979 text-align: center;
1980 display: inline-block;
1981 text-transform: '.$text_transform.';
1982 font-style: '.$font_style.';
1983 text-decoration: '.$text_decoration.';
1984 line-height: '.$line_height.';
1985 letter-spacing: '.$letter_spacing.'px;
1986 word-spacing: '.$word_spacing.'px;
1987 border: '.$border_width.'px '.$border_style.' '.$border_color.';
1988 border-radius: '.$border_radius.'px;
1989 padding: '.$button_pt.'px '.$button_pr.'px '.$button_pb.'px '.$button_pl.'px;
1990 ';
1991 $html .= '<div class="wpvr-call-to-action-button position-'.$text_align.'" style="max-width:' . $width.'">
1992 <a href="'.$buttonurl.'" style="'.$style.'" target="'.$target.'">'.$buttontext.'</a>
1993 </div>';
1994
1995 }
1996 }
1997
1998
1999 //script started
2000 $html .= '<script>';
2001 if (isset($postdata['bg_music']) && $bg_music == 'on' && 'valid' == $status && $is_pro) {
2002 $html .= '
2003 var x' . $id . ' = document.getElementById("vrAudio' . $id . '");
2004 var playing' . $id . ' = false;
2005 var autoplaySupported' . $id . ' = false;
2006 var alertShown' . $id . ' = false;
2007 var autoplayChecked' . $id . ' = false;
2008
2009 function playPause' . $id . '() {
2010 if (playing' . $id . ') {
2011 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2012 x' . $id . '.pause();
2013 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2014 playing' . $id . ' = false;
2015 } else {
2016 x' . $id . '.muted = false;
2017 x' . $id . '.play().then(function() {
2018 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2019 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2020 playing' . $id . ' = true;
2021 }).catch(function(e) {
2022 console.log("Play failed:", e);
2023 });
2024 }
2025 }
2026
2027 function audionEnd' . $id . '() {
2028 playing' . $id . ' = false;
2029 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2030 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2031 }
2032
2033 x' . $id . '.addEventListener("ended", audionEnd' . $id . ');';
2034
2035 if ($autoplay_bg_music == 'on') {
2036 $html .= '
2037
2038 x' . $id . '.addEventListener("loadeddata", function() {
2039 if (!autoplayChecked' . $id . ') {
2040 checkAutoplayStatus' . $id . '();
2041 }
2042 });
2043
2044 x' . $id . '.addEventListener("canplay", function() {
2045 if (!autoplayChecked' . $id . ') {
2046 checkAutoplayStatus' . $id . '();
2047 }
2048 });
2049
2050 x' . $id . '.addEventListener("canplaythrough", function() {
2051 if (!autoplayChecked' . $id . ') {
2052 checkAutoplayStatus' . $id . '();
2053 }
2054 });
2055
2056 setTimeout(function() {
2057 if (!autoplayChecked' . $id . ') {
2058 checkAutoplayStatus' . $id . '();
2059 }
2060 }, 1000);
2061
2062 x' . $id . '.addEventListener("play", function() {
2063 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2064 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2065 playing' . $id . ' = true;
2066 });
2067
2068 x' . $id . '.addEventListener("pause", function() {
2069 if (!playing' . $id . ') {
2070 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2071 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2072 }
2073 });
2074
2075 function checkAutoplayStatus' . $id . '() {
2076 autoplayChecked' . $id . ' = true;
2077
2078 x' . $id . '.muted = true;
2079 var playPromise = x' . $id . '.play();
2080
2081 if (playPromise !== undefined) {
2082 playPromise.then(function () {
2083 if (x' . $id . '.muted || x' . $id . '.volume === 0) {
2084 handleAutoplayBlocked' . $id . '();
2085 } else {
2086 autoplaySupported' . $id . ' = true;
2087 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2088 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2089 playing' . $id . ' = true;
2090 }
2091 }).catch(function () {
2092 handleAutoplayBlocked' . $id . '();
2093 });
2094 } else {
2095 setTimeout(function () {
2096 if (x' . $id . '.paused || x' . $id . '.currentTime === 0) {
2097 handleAutoplayBlocked' . $id . '();
2098 } else {
2099 autoplaySupported' . $id . ' = true;
2100 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2101 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2102 playing' . $id . ' = true;
2103 }
2104 }, 300);
2105 }
2106 }
2107
2108 function handleAutoplayBlocked' . $id . '() {
2109 autoplaySupported' . $id . ' = false;
2110 if (!alertShown' . $id . ') {
2111 alert("Autoplay is not supported in your browser. Please click the audio button to play music.");
2112 alertShown' . $id . ' = true;
2113 }
2114
2115 x' . $id . '.pause();
2116 x' . $id . '.currentTime = 0;
2117 x' . $id . '.muted = true;
2118
2119 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2120 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2121
2122 document.getElementById("pano' . $id . '").addEventListener("click", musicPlay' . $id . ');
2123 document.addEventListener("touchstart", musicPlay' . $id . ', { once: true });
2124 document.addEventListener("click", musicPlay' . $id . ', { once: true });
2125 }
2126
2127 function musicPlay' . $id . '() {
2128 x' . $id . '.muted = false;
2129 var playPromise = x' . $id . '.play();
2130
2131 if (playPromise !== undefined) {
2132 playPromise.then(function () {
2133 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2134 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2135 playing' . $id . ' = true;
2136 }).catch(function(e) {
2137 console.log("Play failed:", e);
2138 });
2139 } else {
2140 setTimeout(function () {
2141 if (!x' . $id . '.paused) {
2142 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2143 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2144 playing' . $id . ' = true;
2145 }
2146 }, 100);
2147 }
2148
2149 document.getElementById("pano' . $id . '").removeEventListener("click", musicPlay' . $id . ');
2150 document.removeEventListener("touchstart", musicPlay' . $id . ');
2151 document.removeEventListener("click", musicPlay' . $id . ');
2152 }
2153 ';
2154 }
2155 }
2156 $html .= '(function ($) {';
2157 $html .= 'jQuery(document).ready(function() {';
2158 $html .= 'var response = ' . $response . ';';
2159 $html .= 'var scenes = response[1];';
2160 $html .= 'if(scenes) {';
2161 $html .= 'var scenedata = scenes.scenes;';
2162 $html .= 'for(var i in scenedata) {';
2163 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2164 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2165 $html .= 'if(scenehotspot[i].type === "info") {';
2166 $html .= ' scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2167 $html .= '} else if(scenehotspot[i].type === "scene") {';
2168 $html .= ' scenehotspot[i]["clickHandlerArgs"] = scenehotspot[i]["text"];';
2169 $status = get_option('wpvr_edd_license_status');
2170 if ($status !== false && $status == 'valid') {
2171 $html .='if(typeof wpvr_public !== "undefined" && wpvr_public.is_pro_active) {';
2172 $html .= ' scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof wpvrhotspotscene === "function") { wpvrhotspotscene(div, args); } else if (typeof window.wpvrhotspotscene === "function") { window.wpvrhotspotscene(div, args); } };';
2173 $html .='}';
2174 }
2175 $html .= '}';
2176
2177 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2178 } else {
2179 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2180 $html .= 'scenehotspot[i]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2181 $html .= '}';
2182 }
2183
2184 $html .= '}';
2185 $html .= '}';
2186 $html .= '}';
2187 $html .= 'var panoshow' . $id . ';';
2188 $html .= 'var panoshow2' . $id . ';';
2189 $html .= 'function initWPVRViewer' . $id . '() {';
2190 $html .= 'if (typeof pannellum === "undefined" || typeof jQuery === "undefined") { setTimeout(initWPVRViewer' . $id . ', 50); return; }';
2191 $html .= 'panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);';
2192 $html .= '
2193 window.wpvrViewers = window.wpvrViewers || {};
2194 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $id . ';
2195 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
2196 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $id . ' }
2197 }));
2198 ';
2199 if ( (float) $scene_fade_duration > 0 ) {
2200 $html .= '
2201 panoshow' . $id . '.on("scenechange", function() {
2202 var fadeImage = document.querySelector("#pano' . $id . ' .pnlm-render-container > .pnlm-fade-img");
2203 if (fadeImage) {
2204 fadeImage.style.opacity = "1";
2205 void fadeImage.offsetWidth;
2206 }
2207 });';
2208 }
2209 $html .= '
2210
2211 if(typeof wpvr_public === "undefined" || !wpvr_public.is_pro_active || !wpvr_public.is_license_active) {
2212 panoshow' . $id . '.on("load", function() {
2213 jQuery(".pnlm-panorama-info").hide();
2214 jQuery(".pnlm-compass").hide();
2215 });
2216
2217 panoshow' . $id . '.on("scenechange", function() {
2218 jQuery(".pnlm-panorama-info").hide();
2219 jQuery(".pnlm-compass").hide();
2220 });
2221 }';
2222 $html .= '}';
2223 $html .= 'initWPVRViewer' . $id . '();';
2224 //===Dplicate mode only for vr mode===//
2225 $response2 = json_decode($response);
2226 $response2[1]->compass = false;
2227 $response2[1]->autoRotate = false;
2228 $response = json_encode($response2);
2229 $html .= 'var response_duplicate = ' . $response . ';';
2230 $html .= 'var scenes_duplicate = response_duplicate[1];';
2231
2232 $html .= 'if(scenes_duplicate) {';
2233 $html .= 'var scenedata = scenes_duplicate.scenes;';
2234 $html .= 'for(var i in scenedata) {';
2235 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2236 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2237 $html .= 'if(scenehotspot[i]["clickHandlerArgs"] != "") {';
2238 $html .= 'scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2239 $html .= '}';
2240 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2241 } else {
2242 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2243 $html .= 'scenehotspot[i]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2244 $html .= '}';
2245 }
2246 $html .= '}';
2247 $html .= '}';
2248 $html .= '}';
2249
2250 $is_pro = apply_filters('is_wpvr_pro_active',false);
2251 $status = get_option('wpvr_edd_license_status');
2252 $html .= 'var vr_mode = "off";';
2253 if ($status !== false && 'valid' == $status && $is_pro) {
2254 $html .= 'function initWPVRViewer2' . $id . '() {';
2255 $html .= 'if (typeof pannellum === "undefined" || typeof jQuery === "undefined") { setTimeout(initWPVRViewer2' . $id . ', 50); return; }';
2256 $html .= 'panoshow2' . $id . ' = pannellum.viewer("pano2' . $id . '", scenes_duplicate);';
2257 $html .= '
2258 window.wpvrViewers = window.wpvrViewers || {};
2259 window.wpvrViewers["pano2' . $id . '"] = panoshow2' . $id . ';
2260 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
2261 detail: { containerId: "pano2' . $id . '", viewer: panoshow2' . $id . ' }
2262 }));
2263 ';
2264 $html .= '}';
2265 $html .= 'initWPVRViewer2' . $id . '();';
2266 // Show Cardboard Mode in Tour
2267 $html .= '
2268 var tim;
2269 var im = 0;
2270 var active_scene = "'.$default_scene.'";
2271 var c_time;
2272 c_time = new Date();
2273 var timer = c_time.getTime() + 2000;
2274 function panoShowCardBoardOnTrigger(data){
2275 if(scenes_duplicate) {
2276 var scenedata = scenes_duplicate.scenes;
2277 for(var i in scenedata) {
2278 if(active_scene === i) {
2279 var scenehotspot = scenedata[i].hotSpots;
2280 for(var j in scenehotspot) {
2281 var plusFiveYaw = Math.round(scenehotspot[j].yaw) + 5;
2282 var minusFiveYaw = Math.round(scenehotspot[j].yaw) - 5;
2283 var plusFivePitch = Math.round(scenehotspot[j].pitch) + 5;
2284 var minusFivePitch = Math.round(scenehotspot[j].pitch) - 5;
2285 var firstCondition = ( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ;
2286 var secCondition = (Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw);
2287 if(( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ){
2288 if((Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw)){
2289 jQuery(".center-pointer").addClass("wpvr-pluse-effect")
2290 var getScene = scenehotspot[j].sceneId;
2291 if(scenehotspot[j].type == "scene"){
2292 panoshow' . $id . '.loadScene(getScene);
2293 panoshow2' . $id . '.loadScene(getScene);
2294 // var inside_current_time_object = new Date();
2295 // var inside_timer = inside_current_time_object.getTime();
2296 // if(inside_timer > timer) {
2297 // panoshow' . $id . '.loadScene(getScene);
2298 // panoshow2' . $id . '.loadScene(getScene);
2299 // jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2300 // }
2301 }else{
2302 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2303 }
2304 }
2305 else {
2306 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2307 c_time = new Date();
2308 timer = c_time.getTime() + 2000;
2309 }
2310 }
2311 else {
2312 c_time = new Date();
2313 timer = c_time.getTime() + 2000;
2314 }
2315 }
2316 }
2317 }
2318 }
2319 };
2320 function vrDeviseOrientation(){
2321 var data = {
2322 pitch: panoshow' . $id . '.getPitch(),
2323 yaw: panoshow' . $id . '.getYaw(),
2324 };
2325 panoShowCardBoardOnTrigger(data);
2326 }';
2327 $html .= '
2328 function requestFullScreen(){
2329 var elem = document.getElementById("master-container");
2330 if (elem.requestFullscreen) {
2331 elem.requestFullscreen();
2332 } else if (elem.webkitRequestFullscreen) { /* Safari */
2333 elem.webkitRequestFullscreen();
2334 } else if (elem.msRequestFullscreen) { /* IE11 */
2335 elem.msRequestFullscreen();
2336 }
2337 }
2338 function requestExitFullscreen(){
2339 var elem = document.getElementById("master-container");
2340 if (document.exitFullscreen) {
2341 document.exitFullscreen();
2342 } else if (document.webkitExitFullscreen) { /* Safari */
2343 document.webkitExitFullscreen();
2344 } else if (document.msExitFullscreen) { /* IE11 */
2345 document.msExitFullscreen();
2346 }
2347 }
2348 jQuery(document).on("click",".fullscreen-button .expand",function() {
2349 jQuery(this).hide()
2350 jQuery(this).parent().find(".compress").show()
2351 requestFullScreen()
2352 });
2353 jQuery(document).on("click",".fullscreen-button .compress",function() {
2354 jQuery(this).hide()
2355 jQuery(this).parent().find(".expand").show()
2356 requestExitFullscreen()
2357 screen.orientation.unlock();
2358 });
2359 let onLoadAnalytics = false;
2360 let sceneLoadAnalytics = false;
2361
2362 function storeAnalyticsData(data) {
2363 if (typeof wpvrAnalyticsObj !== "undefined" && typeof wpvr_public !== "undefined" && wpvr_public.is_pro_active) {
2364 jQuery.ajax({
2365 url: wpvrAnalyticsObj.ajaxUrl,
2366 type: "POST",
2367 data: {
2368 action: "store_scene_hotspot_data",
2369 scene_id: data.scene_id,
2370 tour_id: data.tour_id,
2371 type: data.type,
2372 hotspot_id: data.hotspot_id || "",
2373 user_agent: navigator.userAgent,
2374 device_type: getDeviceType() || "desktop",
2375 nonce: wpvrAnalyticsObj.nonce,
2376 },
2377 success: function (response) {
2378 console.log("Data stored successfully");
2379 },
2380 error: function (error) {
2381 console.log("Error in storing data");
2382 }
2383 });
2384 } else {
2385 console.warn("Analytics object not available or pro not active");
2386 }
2387 }
2388 function getDeviceType() {
2389 const userAgent = navigator.userAgent.toLowerCase();
2390 if (/mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent)) {
2391 return "mobile";
2392 } else if (/tablet|ipad/i.test(userAgent)) {
2393 return "tablet";
2394 } else {
2395 return "desktop";
2396 }
2397 }
2398 panoshow' . $id . '.on("scenechange", function(scene) {
2399 onLoadAnalytics = true;
2400 sceneLoadAnalytics = true;
2401 let scene_id = scene;
2402 let tour_id = ' . $id . ';
2403 let type = "scene";
2404 let hotspot_id = "";
2405 let user_agent = navigator.userAgent;
2406 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2407 storeAnalyticsData({
2408 scene_id: scene_id,
2409 tour_id: tour_id,
2410 type: type,
2411 hotspot_id: hotspot_id,
2412 user_agent: user_agent,
2413 device_type: device_type,
2414 });
2415 });
2416 panoshow' . $id . '.on("load", function() {
2417 let scene_id = panoshow' . $id . '.getScene();
2418 let tour_id = ' . $id . ';
2419 let type = "scene";
2420 let hotspot_id = "";
2421 let user_agent = navigator.userAgent;
2422 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2423 if(!onLoadAnalytics && !sceneLoadAnalytics) {
2424 storeAnalyticsData({
2425 scene_id: scene_id,
2426 tour_id: tour_id,
2427 type: type,
2428 hotspot_id: hotspot_id,
2429 user_agent: user_agent,
2430 device_type: device_type,
2431 });
2432 }
2433 });
2434 function wpvrhotspotscene(hotSpotDiv, args) {
2435 onLoadAnalytics = true;
2436 let scene_id = panoshow' . $id . '.getScene();
2437 let tour_id = ' . $id . ';
2438 let type = "hotspot";
2439 let hotspot_id = args;
2440 let user_agent = navigator.userAgent;
2441 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2442 storeAnalyticsData({
2443 scene_id: scene_id,
2444 tour_id: tour_id,
2445 type: type,
2446 hotspot_id: hotspot_id,
2447 user_agent: user_agent,
2448 device_type: device_type
2449 });
2450 }
2451 ';
2452 $html .= 'panoshow' . $id . '.on("scenechange", function (scene){
2453 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2454 active_scene = scene;
2455 // if(localStorage.getItem("vr_mode") == "on") {
2456 if(vr_mode == "on") {
2457 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2458 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2459 }
2460 });
2461 var compassBlock = "";
2462 var infoBlock = "";
2463 jQuery(document).on("click",".vr_mode_change' . $id . '",function (){
2464 jQuery("#pano2' . $id . ' .pnlm-load-button").trigger("click");
2465 jQuery("#pano' . $id . ' .pnlm-load-button").trigger("click");
2466 var getValue = jQuery(this).val();
2467 var getParent = jQuery(this).parent().parent();
2468 var compass = getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display");
2469 var panoInfo = getParent.find("#pano' . $id . ' .pnlm-panorama-info").css("display");
2470 if(compass == "block"){
2471 compassBlock = "block";
2472 }
2473 if(panoInfo == "block"){
2474 infoBlock = "block";
2475 }
2476 if (getValue == "off") {
2477 requestFullScreen()
2478 screen.orientation.lock("landscape-primary").then(function() {
2479 }).catch(function(error) {
2480 alert("VR Glass Mode not supported in this device");
2481 });
2482 // localStorage.setItem("vr_mode", "on");
2483 vr_mode = "on";
2484 jQuery(".vr-mode-title").show();
2485 jQuery(this).val("on");
2486 getParent.find("#pano2' . $id . '").css({
2487 "opacity": "1",
2488 "visibility": "visible",
2489 "position": "relative",
2490 });
2491 gyroSwitch = true;
2492 panoshow' . $id . '.startOrientation();
2493 panoshow2' . $id . '.startOrientation();
2494 panoshow2' . $id . '.setPitch(panoshow' . $id . '.getPitch(), 0);
2495 panoshow2' . $id . '.setYaw(panoshow' . $id . '.getYaw(), 0);
2496 getParent.find(".pano-wrap").addClass("wpvr-cardboard-disable-event");
2497 getParent.find("#pano' .$id. ' #zoom-in-out-controls'.$id.'").hide();
2498 getParent.find("#pano' .$id. ' #controls'.$id.'").hide();
2499 getParent.find("#pano' .$id. ' #explainer_button_'.$id. '").hide();
2500 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").hide();
2501 getParent.find("#pano' .$id. ' #floor_map_button_'.$id.'").hide();
2502 getParent.find("#pano' .$id. ' #vrgcontrols'.$id.'").hide();
2503 getParent.find("#pano' .$id. ' #sccontrols'.$id.'").hide();
2504 getParent.find("#pano' .$id. ' #adcontrol'.$id.'").hide();
2505 getParent.find("#pano' .$id. ' .wpvr_slider_nav").hide();
2506 getParent.find("#pano' .$id. ' #cp-logo-controls").hide();
2507 getParent.find("#pano' .$id. ' #wpvr-social-share-bg-box'.$id.'").hide();
2508 getParent.find("#pano2' . $id . ' .pnlm-controls-container").hide();
2509 getParent.find("#pano' . $id . ' .pnlm-controls-container").hide();
2510 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
2511 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
2512 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").hide();
2513 getParent.find("#pano' . $id . ' .pnlm-panorama-info").hide();
2514 getParent.find("#pano' . $id . '").addClass("cardboard-half");
2515 getParent.find("#center-pointer' . $id . '").show();
2516 getParent.find(".fullscreen-button").hide();
2517 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").hide();
2518 if (window.DeviceOrientationEvent) {
2519 window.addEventListener("deviceorientation", vrDeviseOrientation);
2520 }
2521 panoshow' . $id . '.on("zoomchange", function (data){
2522 panoshow2' . $id . '.setHfov(data, 0);
2523 });
2524 panoshow2' . $id . '.on("zoomchange", function (data){
2525 panoshow' . $id . '.setHfov(data, 0);
2526 });
2527 jQuery(document).on("click","#pano2' . $id . '",function(event) {
2528 panoshow' . $id . '.startOrientation();
2529 panoshow2' . $id . '.startOrientation();
2530 });
2531 jQuery(document).on("click","#pano' . $id . '",function(event) {
2532 panoshow' . $id . '.startOrientation();
2533 panoshow2' . $id . '.startOrientation();
2534 });
2535 panoshow' . $id . '.on("mousemove", function (data){
2536 panoshow2' . $id . '.setPitch(data.pitch, 0);
2537 panoshow2' . $id . '.setYaw(data.yaw, 0);
2538 panoShowCardBoardOnTrigger(data);
2539 });
2540 panoshow2' . $id . '.on("mousemove", function (data){
2541 panoshow' . $id . '.setPitch(data.pitch, 0);
2542 panoshow' . $id . '.setYaw(data.yaw, 0);
2543 panoShowCardBoardOnTrigger(data);
2544 });
2545 panoshow' . $id . '.on("touchmove", function (data){
2546 panoshow' . $id . '.stopOrientation();
2547 panoshow2' . $id . '.stopOrientation();
2548 panoshow2' . $id . '.setPitch(data.pitch, 0);
2549 panoshow2' . $id . '.setYaw(data.yaw, 0);
2550 panoShowCardBoardOnTrigger(data);
2551 });
2552 panoshow2' . $id . '.on("touchmove", function (data){
2553 panoshow' . $id . '.stopOrientation();
2554 panoshow2' . $id . '.stopOrientation();
2555 panoshow' . $id . '.setPitch(data.pitch, 0);
2556 panoshow' . $id . '.setYaw(data.yaw, 0);
2557 panoShowCardBoardOnTrigger(data);
2558 });
2559 } else if(getValue == "on") {
2560 screen.orientation.unlock();
2561 requestExitFullscreen();
2562 // localStorage.setItem("vr_mode", "off");
2563 vr_mode = "off";
2564 jQuery(".vr-mode-title").hide();
2565 jQuery(this).val("off");
2566 getParent.find("#pano2' . $id . '").css({
2567 "opacity": "0",
2568 "visibility": "hidden",
2569 "position": "absolute",
2570 });
2571 getParent.find(".pano-wrap").removeClass("wpvr-cardboard-disable-event");
2572 getParent.find("#pano' .$id. ' #zoom-in-out-controls'.$id.'").show();
2573 getParent.find("#pano' .$id. ' #controls'.$id.'").show();
2574 getParent.find("#pano' .$id. ' #explainer_button_'.$id. '").show();
2575 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").show();
2576 getParent.find("#pano' .$id. ' #floor_map_button_'.$id.'").show();
2577 getParent.find("#pano2' . $id . ' .pnlm-controls-container").show();
2578 getParent.find("#pano' . $id . ' .pnlm-controls-container").show();
2579 getParent.find("#pano' .$id. ' #vrgcontrols'.$id.'").show();
2580 getParent.find("#pano' .$id. ' #sccontrols'.$id.'").hide();
2581 getParent.find("#pano' .$id. ' #adcontrol'.$id.'").show();
2582 getParent.find("#pano' .$id. ' .wpvr_slider_nav").hide();
2583 getParent.find("#pano' .$id. ' #cp-logo-controls").show();
2584 getParent.find("#pano' .$id. ' #wpvr-social-share-bg-box'.$id.'").show();
2585 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").show();
2586 if(compassBlock == "block"){
2587 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
2588 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
2589 }
2590 if(infoBlock == "block"){
2591 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").show();
2592 getParent.find("#pano' . $id . ' .pnlm-panorama-info").show();
2593 }
2594 getParent.find("#pano' . $id . '").removeClass("cardboard-half");
2595 getParent.find("#center-pointer' . $id . '").hide();
2596 getParent.find(".fullscreen-button").hide();
2597 panoshow' . $id . '.off("mousemove");
2598 panoshow' . $id . '.off("touchmove");
2599 panoshow2' . $id . '.off("mousemove");
2600 panoshow2' . $id . '.off("touchmove");
2601 if (window.DeviceOrientationEvent) {
2602 window.removeEventListener("deviceorientation", vrDeviseOrientation);
2603 }
2604 }
2605 });';
2606 $html .= 'panoshow2' . $id . '.on("load", function (){
2607 // if(localStorage.getItem("vr_mode") == "off") {
2608 if( vr_mode == "off") {
2609 jQuery(".vr-mode-title").hide();
2610 }
2611 else {
2612 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2613 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2614 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
2615 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
2616 jQuery(".vr-mode-title").show();
2617 }
2618 });';
2619 }
2620 //=== end Dplicate mode only for vr mode===//
2621 $html .= 'jQuery("#pano' . $id . ' .wpvr-floor-map .floor-plan-pointer").on("click",function(){
2622 var scene_id = jQuery(this).attr("scene_id");
2623 panoshow' . $id . '.loadScene(scene_id)
2624 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2625 jQuery(this).addClass("add-pulse")
2626 });';
2627 if ($scene_animation_enabled && is_plugin_active('wpvr-pro/wpvr-pro.php')) {
2628 $animation_type = $postdata['sceneAnimationName'] ?? 'none';
2629 $animation_type = $animation_type === 'fade' ? 'fade_in' : $animation_type;
2630 $animationDuration = $postdata['sceneAnimationTransitionDuration'] ?? '500ms';
2631 $animationDelay = $postdata['sceneAnimationTransitionDelay'] ?? '0ms';
2632 $animation_js = apply_filters('wpvr_scene_animation_js', $id, $animation_type, $animationDuration, $animationDelay);
2633 if (!empty($animation_js)) {
2634 $html .= $animation_js;
2635 $html .= 'panoshow' . $id . '.on("load", function (scene){
2636 if (typeof changeScene === "function") {
2637 changeScene();
2638 } else {
2639 console.warn("changeScene function is not defined.");
2640 }
2641 });';
2642 }
2643 }
2644
2645 $html .= 'panoshow' . $id . '.on("mousemove", function (data){
2646 jQuery(".add-pulse").css({"transform":"rotate("+data.yaw+"deg)"});
2647 });
2648 ';
2649 $status = get_option('wpvr_edd_license_status');
2650 if ($status !== false && 'valid' == $status && $is_pro){
2651 $html .= 'panoshow' . $id . '.on("scenechange", function (scene){
2652 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2653 jQuery(".floor-plan-pointer").each(function(index ,element){
2654 var scene_id = jQuery(this).attr("scene_id");
2655 if( active_scene == scene_id ){
2656 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2657 jQuery(this).addClass("add-pulse")
2658 }
2659 });
2660 });';
2661 $html .= 'panoshow' . $id . '.on("load", function (){
2662 if(jQuery(".floor-plan-pointer").length > 0){
2663 jQuery(".floor-plan-pointer").each(function(index ,element){
2664 var scene_id = jQuery(this).attr("scene_id");
2665 if( active_scene == scene_id ){
2666 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2667 jQuery(this).addClass("add-pulse")
2668 }
2669 });
2670 }
2671 });';
2672 }
2673 if ($status !== false && 'valid' == $status && $is_pro){
2674 $scene_navigation_content_type = isset($postdata['scene_navigation_content_type']) ? $postdata['scene_navigation_content_type'] : 'scene_id';
2675 $html .= 'jQuery("#pano' . $id . ' .custom-scene-navigation").on("click", function() {
2676 jQuery("#custom-scene-navigation-nav' . $id . ' ul").empty();
2677 if (scenes) {
2678 var scene_navigation_content_type = "' . $scene_navigation_content_type . '";
2679 var sceneList = scenes.scenes;
2680 var getScene = panoshow' . $id . '.getScene();
2681 for (const key in sceneList) {
2682 let title;
2683 if (scene_navigation_content_type === "scene_title") {
2684 if (sceneList[key].title) {
2685 title = sceneList[key].title;
2686 } else {
2687 if (title == "" || title == undefined) {
2688 if (sceneList[key].panorama) {
2689 title = getImageNameWithoutExtension(sceneList[key].panorama);
2690 }
2691 }
2692 }
2693 } else if (scene_navigation_content_type === "scene_image_name") {
2694 if (sceneList[key].panorama) {
2695 title = getImageNameWithoutExtension(sceneList[key].panorama);
2696 }
2697 } else {
2698 title = key;
2699 }
2700 if (sceneList.hasOwnProperty(key)) {
2701 let ulElement = document.querySelector("#custom-scene-navigation-nav' . $id . ' ul");
2702 if (ulElement) {
2703 let liElement = document.createElement("li");
2704 liElement.className = "scene-navigation-list" + (key === getScene ? " active" : "");
2705 liElement.setAttribute("scene_id", key);
2706 liElement.textContent = title;
2707 ulElement.appendChild(liElement);
2708 }
2709 }
2710 }
2711 jQuery("#custom-scene-navigation-nav' . $id . '").toggleClass("visible");
2712 }
2713 });';
2714 $html .='function getImageNameWithoutExtension(imageUrl) {
2715 // Split the URL by "/"
2716 var parts = imageUrl.split("/");
2717 // Get the last part which contains the image name
2718 var imageNameWithExtension = parts[parts.length - 1];
2719 // Split the image name by period (.)
2720 var imageNameParts = imageNameWithExtension.split(".");
2721 // Remove the last part (which is the extension) and join the remaining parts
2722 var imageNameWithoutExtension = imageNameParts.slice(0, -1).join(".");
2723 // Return the image name without extension
2724 return imageNameWithoutExtension;
2725 }';
2726 $html .= 'jQuery("#pano' . $id . ' #custom-scene-navigation-nav' . $id . ' ul").on("click", "li.scene-navigation-list", function() {
2727 if (scenes) {
2728 jQuery(this).siblings("li").removeClass("active");
2729 jQuery(this).addClass("active");
2730 var scene_key = jQuery(this).attr("scene_id");
2731 panoshow' . $id . '.loadScene(scene_key);
2732 }
2733 });';
2734 }
2735 $html .= 'const node = document.querySelector(".add-pulse");
2736 panoshow' . $id . '.on("compasschange", function (data){
2737 // const node = document.querySelector(".add-pulse");
2738 // node.style.transform = data;
2739 // jQuery(".add-pulse").css({"transform":data});
2740 });';
2741 $html .= 'panoshow' . $id . '.on("load", function (){
2742 // if(localStorage.getItem("vr_mode") == "off") {
2743 if(vr_mode == "off") {
2744 jQuery(".vr-mode-title").hide();
2745 } else {
2746 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2747 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2748 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
2749 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
2750 jQuery(".vr-mode-title").show();
2751 }
2752 setTimeout(() => {
2753 window.dispatchEvent(new Event("resize"));
2754 }, 200);
2755 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
2756 jQuery("#controls' . $id . '").css("bottom", "80px");
2757 }
2758 else {
2759 jQuery("#controls' . $id . '").css("bottom", "5px");
2760 }
2761 });';
2762 $html .= 'panoshow' . $id . '.on("render", function (){
2763 window.dispatchEvent(new Event("resize"));
2764 });';
2765 $html .= 'if (scenes.autoRotate) {
2766 var wpvrAutoRotateTimer' . $id . ' = null;
2767 var wpvrAutoRotateStopDelay' . $id . ' = parseInt(scenes.autoRotateStopDelay, 10) || 0;
2768 var wpvrScheduleAutoRotate' . $id . ' = function () {
2769 clearTimeout(wpvrAutoRotateTimer' . $id . ');
2770 if (wpvrAutoRotateStopDelay' . $id . ' > 0) {
2771 wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
2772 panoshow' . $id . '.stopAutoRotate();
2773 }, wpvrAutoRotateStopDelay' . $id . ');
2774 } else {
2775 wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
2776 panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0);
2777 }, 3000);
2778 }
2779 };
2780 panoshow' . $id . '.on("load", wpvrScheduleAutoRotate' . $id . ');
2781 panoshow' . $id . '.on("scenechange", wpvrScheduleAutoRotate' . $id . ');
2782 }';
2783 $html .= 'var touchtime = 0;';
2784 $html .= '
2785 var wpvrHotspotRoot' . $id . ' = document.getElementById("pano' . $id . '");
2786 if (wpvrHotspotRoot' . $id . ') {
2787 wpvrHotspotRoot' . $id . '.addEventListener("click", function (event) {
2788 var hotspot = event.target.closest(".pnlm-hotspot-base");
2789
2790 if (!hotspot) {
2791 return;
2792 }
2793
2794 var hotspotLink = hotspot.closest("a[href]");
2795 if (!hotspotLink) {
2796 hotspotLink = hotspot.querySelector("a[href]");
2797 }
2798
2799 if (!hotspotLink) {
2800 return;
2801 }
2802
2803 event.preventDefault();
2804 event.stopImmediatePropagation();
2805
2806 if ((hotspotLink.getAttribute("target") || "_blank") === "_self") {
2807 window.location.assign(hotspotLink.href);
2808 } else {
2809 window.open(hotspotLink.href, "_blank", "noopener,noreferrer");
2810 }
2811 }, true);
2812 }
2813 ';
2814 if ($vrgallery) {
2815 $gallery_scene_ids = [];
2816 if (isset($panodata["scene-list"])) {
2817 foreach ($panodata["scene-list"] as $panoscenes) {
2818 $scene_key = $panoscenes['scene-id'];
2819 $gallery_scene_ids[] = (string) $scene_key;
2820 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $id;
2821 $html .= 'jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
2822 panoshow' . $id . '.loadScene("' . $scene_key . '");
2823 });';
2824 }
2825 }
2826
2827 $is_modern_gallery = isset($postdata['tourLayout']['layout']) && 'layout1' === $postdata['tourLayout']['layout'];
2828 $gallery_options = $is_modern_gallery
2829 ? '{
2830 loop: false,
2831 nav: false,
2832 dots: false,
2833 margin: 18,
2834 mouseDrag: false,
2835 responsive: {
2836 0: { items: 2 },
2837 320: { items: 3 },
2838 500: { items: 4 },
2839 690: { items: 5 }
2840 }
2841 }'
2842 : '{
2843 autoWidth: true,
2844 loop: false,
2845 nav: false,
2846 dots: false,
2847 margin: 10,
2848 stagePadding: 0
2849 }';
2850
2851 $html .= '
2852 var wpvrGallery' . $id . ' = jQuery("#sccontrols' . $id . '");
2853 var wpvrGalleryRoot' . $id . ' = jQuery("#pano' . $id . '");
2854 var wpvrGalleryScenes' . $id . ' = ' . wp_json_encode(array_values($gallery_scene_ids)) . ';
2855 var wpvrGalleryResizeTimer' . $id . ';
2856 var wpvrGalleryVisibilityTimer' . $id . ';
2857 var wpvrGalleryObserver' . $id . ';
2858
2859 function wpvrPrepareSceneNavigation' . $id . '() {
2860 var navigationDisabled = wpvrGalleryScenes' . $id . '.length < 2;
2861 var previousButtons = wpvrGalleryRoot' . $id . '.find(".wpvr_owl_prev");
2862 var nextButtons = wpvrGalleryRoot' . $id . '.find(".wpvr_owl_next");
2863
2864 wpvrGallery' . $id . '.removeClass("owl-theme");
2865 wpvrGalleryRoot' . $id . '.find(".wpvr_slider_nav").removeClass("owl-nav");
2866 previousButtons
2867 .removeClass("owl-prev")
2868 .prop("disabled", navigationDisabled)
2869 .toggleClass("disabled", navigationDisabled);
2870 nextButtons
2871 .removeClass("owl-next")
2872 .prop("disabled", navigationDisabled)
2873 .toggleClass("disabled", navigationDisabled);
2874 }
2875
2876 function wpvrRefreshGallery' . $id . '() {
2877 wpvrPrepareSceneNavigation' . $id . '();
2878
2879 if (!wpvrGallery' . $id . '.length || !wpvrGallery' . $id . '.hasClass("owl-loaded") || !wpvrGallery' . $id . '.is(":visible")) {
2880 return;
2881 }
2882
2883 if (wpvrGallery' . $id . '.css("display") === "flex") {
2884 wpvrGallery' . $id . '.css("display", "block");
2885 }
2886 wpvrGallery' . $id . '.trigger("refresh.owl.carousel");
2887 wpvrUpdateGalleryNavigation' . $id . '(panoshow' . $id . '.getScene());
2888 }
2889
2890 function wpvrGallerySceneIndex' . $id . '(sceneId) {
2891 return wpvrGalleryScenes' . $id . '.indexOf(String(sceneId));
2892 }
2893
2894 function wpvrUpdateGalleryNavigation' . $id . '(sceneId) {
2895 var currentIndex = wpvrGallerySceneIndex' . $id . '(sceneId);
2896 var activeThumbnailId = String(sceneId) + "_gallery_' . $id . '";
2897 var thumbnails = wpvrGallery' . $id . '.find("img.scctrl");
2898 var activeThumbnail = thumbnails.filter(function () {
2899 return this.id === activeThumbnailId;
2900 });
2901
2902 wpvrPrepareSceneNavigation' . $id . '();
2903 thumbnails.removeClass("wpvr-active-thumbnail");
2904 wpvrGallery' . $id . '.find(".owl-item").removeClass("clicked");
2905 activeThumbnail.addClass("wpvr-active-thumbnail");
2906 activeThumbnail.closest(".owl-item").addClass("clicked");
2907
2908 if (currentIndex >= 0) {
2909 if (wpvrGallery' . $id . '.hasClass("owl-loaded")) {
2910 wpvrGallery' . $id . '.trigger("to.owl.carousel", [currentIndex, 300, true]);
2911 window.setTimeout(wpvrPrepareSceneNavigation' . $id . ', 0);
2912 }
2913 }
2914 }
2915
2916 function wpvrLoadAdjacentGalleryScene' . $id . '(direction) {
2917 var currentIndex = wpvrGallerySceneIndex' . $id . '(panoshow' . $id . '.getScene());
2918
2919 if (currentIndex < 0 || wpvrGalleryScenes' . $id . '.length < 2) {
2920 return;
2921 }
2922
2923 var targetIndex = (currentIndex + direction + wpvrGalleryScenes' . $id . '.length) % wpvrGalleryScenes' . $id . '.length;
2924 panoshow' . $id . '.loadScene(wpvrGalleryScenes' . $id . '[targetIndex]);
2925 }
2926
2927 if (jQuery.fn.owlCarousel) {
2928 if (wpvrGallery' . $id . '.length) {
2929 if (!wpvrGallery' . $id . '.hasClass("owl-loaded")) {
2930 wpvrGallery' . $id . '.owlCarousel(' . $gallery_options . ');
2931 }
2932 }
2933 }
2934
2935 wpvrGalleryRoot' . $id . '
2936 .off("click.wpvrGalleryRefresh' . $id . '", "#vrgcontrols' . $id . '")
2937 .on("click.wpvrGalleryRefresh' . $id . '", "#vrgcontrols' . $id . '", function () {
2938 wpvrPrepareSceneNavigation' . $id . '();
2939 window.setTimeout(wpvrRefreshGallery' . $id . ', 450);
2940 });
2941
2942 if (wpvrGalleryRoot' . $id . '.length) {
2943 wpvrGalleryRoot' . $id . '[0].addEventListener("click", function (event) {
2944 var navigationButton = event.target.closest(".wpvr_owl_prev, .wpvr_owl_next");
2945
2946 if (!navigationButton) {
2947 return;
2948 }
2949
2950 if (!wpvrGalleryRoot' . $id . '[0].contains(navigationButton)) {
2951 return;
2952 }
2953
2954 event.preventDefault();
2955 event.stopImmediatePropagation();
2956
2957 if (navigationButton.classList.contains("wpvr_owl_prev")) {
2958 wpvrLoadAdjacentGalleryScene' . $id . '(-1);
2959 } else {
2960 wpvrLoadAdjacentGalleryScene' . $id . '(1);
2961 }
2962 }, true);
2963 }
2964
2965 jQuery(window)
2966 .off("resize.wpvrGallery' . $id . '")
2967 .on("resize.wpvrGallery' . $id . '", function () {
2968 window.clearTimeout(wpvrGalleryResizeTimer' . $id . ');
2969 wpvrGalleryResizeTimer' . $id . ' = window.setTimeout(wpvrRefreshGallery' . $id . ', 100);
2970 });
2971
2972 if (window.MutationObserver) {
2973 if (wpvrGallery' . $id . '.length) {
2974 wpvrGalleryObserver' . $id . ' = new MutationObserver(function () {
2975 window.clearTimeout(wpvrGalleryVisibilityTimer' . $id . ');
2976 wpvrGalleryVisibilityTimer' . $id . ' = window.setTimeout(wpvrRefreshGallery' . $id . ', 50);
2977 });
2978 wpvrGalleryObserver' . $id . '.observe(wpvrGallery' . $id . '[0], {
2979 attributes: true,
2980 attributeFilter: ["style"]
2981 });
2982 }
2983 }
2984
2985 panoshow' . $id . '.on("scenechange", function (sceneId) {
2986 wpvrUpdateGalleryNavigation' . $id . '(sceneId);
2987 });
2988
2989 window.setTimeout(wpvrRefreshGallery' . $id . ', 0);
2990 window.setTimeout(function () {
2991 wpvrUpdateGalleryNavigation' . $id . '(panoshow' . $id . '.getScene());
2992 }, 0);
2993 ';
2994 }
2995 //===Custom Control===//
2996 if (isset($custom_control)) {
2997 if ($custom_control['panupSwitch'] == "on" && 'valid' == $status && $is_pro) {
2998 $html .= 'document.getElementById("pan-up' . $id . '").addEventListener("click", function(e) {';
2999 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() + 10);';
3000 $html .= '});';
3001 }
3002 if ($custom_control['panDownSwitch'] == "on" && 'valid' == $status && $is_pro) {
3003 $html .= 'document.getElementById("pan-down' . $id . '").addEventListener("click", function(e) {';
3004 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() - 10);';
3005 $html .= '});';
3006 }
3007 if ($custom_control['panLeftSwitch'] == "on" && 'valid' == $status && $is_pro) {
3008 $html .= 'document.getElementById("pan-left' . $id . '").addEventListener("click", function(e) {';
3009 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() - 10);';
3010 $html .= '});';
3011 }
3012 if ($custom_control['panRightSwitch'] == "on" && 'valid' == $status && $is_pro) {
3013 $html .= 'document.getElementById("pan-right' . $id . '").addEventListener("click", function(e) {';
3014 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() + 10);';
3015 $html .= '});';
3016 }
3017 if ($custom_control['panZoomInSwitch'] == "on") {
3018 $html .= 'document.getElementById("zoom-in' . $id . '").addEventListener("click", function(e) {';
3019 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() - 10);';
3020 $html .= '});';
3021 }
3022 if ($custom_control['panZoomOutSwitch'] == "on") {
3023 $html .= 'document.getElementById("zoom-out' . $id . '").addEventListener("click", function(e) {';
3024 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() + 10);';
3025 $html .= '});';
3026 }
3027 if ($custom_control['panFullscreenSwitch'] == "on" && 'valid' == $status && $is_pro) {
3028 $html .= 'document.getElementById("fullscreen' . $id . '").addEventListener("click", function(e) {';
3029 $html .= 'panoshow' . $id . '.toggleFullscreen();';
3030 $html .= '});';
3031 $html .= '(function() {';
3032 $html .= 'function wpvrFsChange' . $id . '() {';
3033 $html .= 'var fsIcon = document.querySelector("#fullscreen' . $id . ' i");';
3034 $html .= 'if (!fsIcon) return;';
3035 $html .= 'if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {';
3036 $html .= 'fsIcon.classList.remove("fa-expand"); fsIcon.classList.add("fa-minimize");';
3037 $html .= '} else {';
3038 $html .= 'fsIcon.classList.remove("fa-minimize"); fsIcon.classList.add("fa-expand");';
3039 $html .= '}';
3040 $html .= '}';
3041 $html .= 'document.addEventListener("fullscreenchange", wpvrFsChange' . $id . ');';
3042 $html .= 'document.addEventListener("webkitfullscreenchange", wpvrFsChange' . $id . ');';
3043 $html .= 'document.addEventListener("mozfullscreenchange", wpvrFsChange' . $id . ');';
3044 $html .= 'document.addEventListener("MSFullscreenChange", wpvrFsChange' . $id . ');';
3045 $html .= '})();';
3046 }
3047 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
3048 $html .= 'document.getElementById("backToHome' . $id . '").addEventListener("click", function(e) {';
3049 $html .= 'panoshow' . $id . '.loadScene("' . $default_scene . '");';
3050 $html .= '});';
3051 }
3052 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
3053 $html .= '
3054 (function() {
3055 var gyroButton = document.getElementById("gyroscope' . $id . '");
3056 var gyroIcon = gyroButton ? gyroButton.querySelector("i") : null;
3057 var activeColor = ' . wp_json_encode($custom_control['gyroscopeColor']) . ';
3058 var permissionGranted = false;
3059
3060 if (!gyroButton || !gyroIcon) {
3061 return;
3062 }
3063
3064 function updateGyroscopeState() {
3065 gyroIcon.style.color = panoshow' . $id . '.isOrientationActive()
3066 ? activeColor
3067 : "red";
3068 }
3069
3070 function startGyroscope() {
3071 if (!panoshow' . $id . '.isOrientationSupported()) {
3072 updateGyroscopeState();
3073 return;
3074 }
3075
3076 panoshow' . $id . '.startOrientation();
3077 window.setTimeout(updateGyroscopeState, 0);
3078 }
3079
3080 function requestGyroscopePermission() {
3081 var orientationEvent = window.DeviceOrientationEvent;
3082 if (orientationEvent) {
3083 if (typeof orientationEvent.requestPermission === "function") {
3084 if (!permissionGranted) {
3085 orientationEvent.requestPermission()
3086 .then(function(state) {
3087 permissionGranted = state === "granted";
3088 if (permissionGranted) {
3089 startGyroscope();
3090 } else {
3091 updateGyroscopeState();
3092 }
3093 })
3094 .catch(updateGyroscopeState);
3095 return;
3096 }
3097 }
3098 }
3099
3100 startGyroscope();
3101 }
3102
3103 panoshow' . $id . '.on("load", updateGyroscopeState);
3104 panoshow' . $id . '.on("scenechange", updateGyroscopeState);
3105
3106 gyroButton.addEventListener("click", function() {
3107 if (panoshow' . $id . '.isOrientationActive()) {
3108 panoshow' . $id . '.stopOrientation();
3109 updateGyroscopeState();
3110 return;
3111 }
3112
3113 requestGyroscopePermission();
3114 });
3115 })();';
3116 }
3117 }
3118 $angle_up = '<i class="fa fa-angle-up"></i>';
3119 $angle_down = '<i class="fa fa-angle-down"></i>';
3120 $sin_qout = "'";
3121
3122 //===Explainer Script===//
3123
3124 if ($autoplay_bg_music == 'on') {
3125 $html .= 'jQuery(document).on("click","#explainer_button_' . $id . '",function() {
3126 jQuery("#explainer' . $id . '").slideToggle();
3127 playing' . $id . ' = false;
3128 var x' . $id . ' = document.getElementById("vrAudio' . $id . '");
3129 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up");
3130 jQuery("#vr-volume' . $id . '").addClass("fas fa-volume-mute");
3131 x' . $id . '.pause();
3132 });
3133 jQuery(document).on("click",".close-explainer-video",function() {
3134 jQuery(this).parent(".explainer").hide();
3135 var el_src = jQuery(".vr-iframe").attr("src");
3136 jQuery(".vr-iframe").attr("src", el_src);
3137 });';
3138 } else {
3139 $html .= 'jQuery(document).on("click","#explainer_button_' . $id . '",function() {
3140 jQuery("#explainer' . $id . '").slideToggle(function(){
3141 var $explainerVideoId = jQuery("#explainer' . $id . '");
3142 var $explainerVideoIframe = $explainerVideoId.find("iframe");
3143 var explainerVideoIframSrc = $explainerVideoIframe.attr("src");
3144 $explainerVideoIframe.attr("src", "");
3145 $explainerVideoIframe.attr("src", explainerVideoIframSrc);
3146 });
3147 });
3148 jQuery(document).on("click", ".close-explainer-video", function() {
3149 var $explainer = jQuery(this).parent(".explainer");
3150 var $iframe = $explainer.find("iframe");
3151 var el_src = $iframe.attr("src");
3152 $iframe.attr("src", "");
3153 $explainer.hide();
3154 $iframe.attr("src", el_src);
3155 });';
3156 }
3157
3158 $html .= '
3159 jQuery(document).on("click","#pano' . $id . '",function(event) {
3160 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3161 var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3162 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3163 if(isForm != null){
3164 jQuery(this).addClass("show-modal");
3165 }else if(isActiveModal == null){
3166 if(isHotspot == null){
3167 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3168 jQuery(".custom-ifram-wrapper").hide();
3169 jQuery(this).removeClass("show-modal");
3170 jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3171 }
3172 }
3173 });';
3174
3175 //===Explainer Script End===//
3176
3177 //===generic form script===//
3178 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on') {
3179 $html .= '
3180 jQuery(document).on("click","#generic_form_button_' . $id . '",function() {
3181 jQuery("#wpvr-generic-form' . $id . '").fadeToggle();
3182 });
3183
3184 jQuery(document).on("click",".close-generic-form",function() {
3185 jQuery(this).parent(".wpvr-generic-form").fadeOut()
3186 });
3187 ';
3188 }
3189 //===generic from script===//
3190
3191 //===Floor map Script===//
3192 $html .= 'jQuery(document).on("click","#floor_map_button_' . $id . '",function() {
3193 jQuery("#wpvr-floor-map' . $id . '").toggle().removeClass("fullwindow");
3194 });
3195 jQuery(document).on("dblclick","#wpvr-floor-map' . $id . '",function(){
3196 jQuery(this).addClass("fullwindow");
3197 jQuery(this).parents(".pano-wrap").addClass("show-modal");
3198 });
3199 jQuery(document).on("click",".close-floor-map-plan",function() {
3200 jQuery(this).parent(".wpvr-floor-map").hide();
3201 jQuery(this).parent(".wpvr-floor-map").removeClass("fullwindow");
3202 jQuery(this).parents(".pano-wrap").removeClass("show-modal");
3203 });';
3204 //===Floor map Script End===//
3205
3206 if ($vrgallery_display) {
3207
3208 if (!$autoload) {
3209 $html .= 'jQuery(document).ready(function($){
3210 jQuery("#sccontrols' . $id . '").hide();
3211 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3212 jQuery("#sccontrols' . $id . '").hide();
3213 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3214 });';
3215 $html .= 'var slide' . $id . ' = "down";
3216 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3217 if (slide' . $id . ' == "up") {
3218 jQuery(".vrgctrl' . $id . '").empty();
3219 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3220 slide' . $id . ' = "down";
3221 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3222 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3223 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3224 if (jQuery(this).is(":visible")) {
3225 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3226 "display": "flex",
3227 "justify-content": "center",
3228 "align-items": "center",
3229 "gap": "15px"
3230 });
3231 }
3232 }
3233 if (jQuery(".bricks-is-frontend").length) {
3234 if (jQuery(this).is(":visible")) {
3235 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3236 "display": "flex",
3237 "justify-content": "center",
3238 "align-items": "center"
3239 });
3240 }
3241 }
3242 });
3243 }
3244 else {
3245 jQuery(".vrgctrl' . $id . '").empty();
3246 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3247 slide' . $id . ' = "up";
3248 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3249 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3250 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3251 if (jQuery(this).is(":visible")) {
3252 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3253 "display": "flex",
3254 "justify-content": "center",
3255 "align-items": "center",
3256 "gap": "15px"
3257 });
3258 }
3259 }
3260 if (jQuery(".bricks-is-frontend").length) {
3261 if (jQuery(this).is(":visible")) {
3262 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3263 "display": "flex",
3264 "justify-content": "center",
3265 "align-items": "center"
3266 });
3267 }
3268 }
3269 });
3270 }
3271 });';
3272 } else {
3273 $html .= 'jQuery(document).ready(function($){
3274 jQuery("#sccontrols' . $id . '").show();
3275 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3276 jQuery("#pano' . $id . ' .wpvr_slider_nav").show();
3277 });';
3278 $html .= 'var slide' . $id . ' = "down";
3279 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3280 if (slide' . $id . ' == "up") {
3281 jQuery(".vrgctrl' . $id . '").empty();
3282 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3283 slide' . $id . ' = "down";
3284 } else {
3285 jQuery(".vrgctrl' . $id . '").empty();
3286 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3287 slide' . $id . ' = "up";
3288 }
3289 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3290 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3291 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3292 if (jQuery(this).is(":visible")) {
3293 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3294 "display": "flex",
3295 "justify-content": "center",
3296 "align-items": "center",
3297 "gap": "15px"
3298 });
3299 }
3300 }
3301 if (jQuery(".bricks-is-frontend").length) {
3302 if (jQuery(this).is(":visible")) {
3303 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3304 "display": "flex",
3305 "justify-content": "center",
3306 "align-items": "center"
3307 });
3308 }
3309 }
3310 });
3311 });';
3312 }
3313 } else {
3314 $html .= 'jQuery(document).ready(function($){
3315 jQuery("#sccontrols' . $id . '").hide();
3316 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3317 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3318 });';
3319 $html .= 'var slide' . $id . ' = "down";
3320 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3321 if (slide' . $id . ' == "up") {
3322 jQuery(".vrgctrl' . $id . '").empty();
3323 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3324 slide' . $id . ' = "down";
3325 }
3326 else {
3327 jQuery(".vrgctrl' . $id . '").empty();
3328 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3329 slide' . $id . ' = "up";
3330 }
3331 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3332 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3333 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3334 if (jQuery(this).is(":visible")) {
3335 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3336 "display": "flex",
3337 "justify-content": "center",
3338 "align-items": "center",
3339 "gap": "15px"
3340 });
3341 }
3342 }
3343 if (jQuery(".bricks-is-frontend").length) {
3344 if (jQuery(this).is(":visible")) {
3345 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3346 "display": "flex",
3347 "justify-content": "center",
3348 "align-items": "center"
3349 });
3350 }
3351 }
3352 });
3353 });';
3354 }
3355 if (!$autoload) {
3356 $html .= 'jQuery(document).ready(function(){
3357 jQuery("#controls' . $id . '").hide();
3358 jQuery("#zoom-in-out-controls' . $id . '").hide();
3359 jQuery("#adcontrol' . $id . '").hide();
3360 jQuery("#explainer_button_' . $id . '").hide();
3361 jQuery("#generic_form_button_' . $id . '").hide();
3362 jQuery("#floor_map_button_' . $id . '").hide();
3363 jQuery("#vrgcontrols' . $id . '").hide();
3364 jQuery("#cp-logo-controls").hide();
3365 jQuery(".custom-scene-navigation").hide();
3366 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").hide();
3367 });';
3368 if ($vrgallery_display) {
3369 $html .= 'var load_once = "true";';
3370 $html .= 'panoshow' . $id . '.on("load", function (){
3371 if (load_once == "true") {
3372 load_once = "false";
3373 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3374 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3375 if (jQuery(this).is(":visible")) {
3376 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css("display", "flex");
3377 }
3378 }
3379 if (jQuery(".bricks-is-frontend").length) {
3380 if (jQuery(this).is(":visible")) {
3381 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3382 "display": "flex",
3383 "justify-content": "center",
3384 "align-items": "center"
3385 });
3386 }
3387 }
3388 });
3389 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3390 }
3391 });';
3392 }
3393 $html .= 'panoshow' . $id . '.on("load", function (){
3394 jQuery("#controls' . $id . '").show();
3395 jQuery("#zoom-in-out-controls' . $id . '").show();
3396 jQuery("#adcontrol' . $id . '").show();
3397 jQuery("#explainer_button_' . $id . '").show();
3398 jQuery("#generic_form_button_' . $id . '").show();
3399 jQuery("#floor_map_button_' . $id . '").show();
3400 jQuery("#vrgcontrols' . $id . '").show();
3401 jQuery("#cp-logo-controls").show();
3402 jQuery(".custom-scene-navigation").show();
3403 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").show();
3404 });';
3405 }
3406
3407 //==Old code working properly==//
3408
3409 $previeword = "Click to Load Panorama";
3410 if (isset($postdata['previewtext']) && $postdata['previewtext'] != '') {
3411 $previeword = $postdata['previewtext'];
3412 }
3413 $html .= 'jQuery(".elementor-tab-title").click(function(){
3414 var element_id;
3415 var pano_id;
3416 var element_id = this.id;
3417 element_id = element_id.split("-");
3418 element_id = element_id[3];
3419 jQuery("#elementor-tab-content-"+element_id).find("#master-container").children("div").eq(1).addClass("awwww");
3420 var pano_id = jQuery(".awwww").attr("id");
3421 jQuery("#elementor-tab-content-"+element_id).find("#master-container").children("div").eq(1).removeClass("awwww");;
3422 if (pano_id != undefined) {
3423 pano_id = pano_id.split("o");
3424 pano_id = pano_id[1];
3425 if (pano_id == "' . $id . '") {
3426 jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
3427 jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
3428 panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
3429 window.wpvrViewers = window.wpvrViewers || {};
3430 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $id . ';
3431 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3432 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $id . ' }
3433 }));
3434 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3435 setTimeout(function() {
3436 // panoshow' . $id . '.loadScene("' . $default_scene . '");
3437 window.dispatchEvent(new Event("resize"));
3438 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3439 jQuery("#controls' . $id . '").css("bottom", "55px");
3440 } else {
3441 jQuery("#controls' . $id . '").css("bottom", "5px");
3442 }
3443 }, 200);
3444 }
3445 }
3446 });';
3447 $html .= 'jQuery(".geodir-tab-head dd, #vr-tour-tab").click(function(){
3448 jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
3449 jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
3450 panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
3451 window.wpvrViewers = window.wpvrViewers || {};
3452 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $id . ';
3453 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3454 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $id . ' }
3455 }));
3456 setTimeout(function() {
3457 panoshow' . $id . '.loadScene("' . $default_scene . '");
3458 window.dispatchEvent(new Event("resize"));
3459 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3460 jQuery("#controls' . $id . '").css("bottom", "55px");
3461 }
3462 else {
3463 jQuery("#controls' . $id . '").css("bottom", "5px");
3464 }
3465 }, 200);
3466 });';
3467 if (isset($previeword) && $previeword != '') {
3468 $html .= '
3469 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3470 ';
3471 }
3472 if ($default_global_zoom != '' || $max_global_zoom != '' || $min_global_zoom != '') {
3473 $html .= 'jQuery(".globalzoom").val("on").change();';
3474 }
3475
3476 $html .= 'jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseenter", function(){
3477 jQuery(this).attr("title", jQuery(this).text());
3478 });
3479 jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseleave", function(){
3480 jQuery(this).removeAttr("title");
3481 });';
3482 $html .= '});';
3483 $html .= '})(jQuery);';
3484 $html .= '</script>';
3485 $tour_data = [];
3486 if(defined("WPVR_PRO_VERSION")){
3487 $tour_data = array(
3488 'explainerControlSwitch' => (
3489 isset( $postdata['explainerSwitch'] )
3490 && in_array( $postdata['explainerSwitch'], array( true, 1, '1', 'on' ), true )
3491 ) ? 'on' : 'off',
3492 'floor_plan_enable' => $floor_plan_enable ?? '',
3493 'floor_plan_image' => $floor_plan_image ?? '',
3494 'custom_control' => $custom_control ?? '',
3495 );
3496 }
3497 ob_start();
3498 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
3499 echo $html;
3500 $output = ob_get_clean();
3501 return apply_filters('wpvr_generate_tour_layout_html', $output ,$postdata ,$id, $tour_data);
3502 }
3503
3504 function replace_callback($matches){
3505 foreach ($matches as $match){
3506 return str_replace('<img','<img decoding="async"',$match);
3507 }
3508
3509 }
3510
3511 private function sanitize_content_preserve_styles($content, $allow_forms = false) {
3512 // Decode HTML entities first (in case content was encoded in database)
3513 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3514
3515 // Escape <script> blocks to display as text instead of removing them
3516 $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3517 return esc_html($matches[0]); // Convert to plain text
3518 }, $content);
3519
3520 // Strip dangerous URL-based attributes
3521 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3522
3523 // Escape inline event handlers (onclick, onhover, etc.) to display as text
3524 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*(["\'])([^"\']*)\2/i', function($matches) {
3525 // Escape the attribute value but keep the attribute name visible as text
3526 return ' ' . esc_html($matches[1]) . '=' . $matches[2] . esc_html($matches[3]) . $matches[2];
3527 }, $content);
3528 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*([^>\s]+)/i', function($matches) {
3529 // Handle unquoted event handlers
3530 return ' ' . esc_html($matches[1]) . '=' . esc_html($matches[2]);
3531 }, $content);
3532
3533 // Remove unsafe embedded/interactive elements
3534 if ($allow_forms) {
3535 $content = preg_replace('/<(object|embed|applet|frame|frameset|meta|link|base)\b[^>]*>/i', '', $content);
3536 $content = preg_replace('/<\/(object|embed|applet|frame|frameset|meta|link|base)>/i', '', $content);
3537 } else {
3538 $content = preg_replace('/<(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)\b[^>]*>/i', '', $content);
3539 $content = preg_replace('/<\/(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)>/i', '', $content);
3540 }
3541
3542 // Clean style attributes safely
3543 $content = preg_replace_callback('/style\s*=\s*["\']([^"\']*)["\']/', function($matches) {
3544 $style = $matches[1];
3545 $style = preg_replace('/expression\s*\(/i', '', $style);
3546 $style = preg_replace('/(javascript|vbscript|data|about)\s*:/i', '', $style);
3547 $style = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $style);
3548 $style = preg_replace('/behavior\s*:/i', '', $style);
3549 $style = preg_replace('/-moz-binding\s*:/i', '', $style);
3550 return 'style="' . esc_attr($style) . '"';
3551 }, $content);
3552
3553 // Sanitize <style> blocks
3554 $content = preg_replace_callback('/<style\b[^>]*>(.*?)<\/style>/si', function($matches) {
3555 $css = $matches[1];
3556 $css = preg_replace('/(expression|javascript|vbscript|data|about)\s*:/i', '', $css);
3557 $css = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $css);
3558 $css = preg_replace('/behavior\s*:/i', '', $css);
3559 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3560 return '<style>' . esc_html($css) . '</style>';
3561 }, $content);
3562
3563 // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3564 $allowed_tags = wp_kses_allowed_html('post');
3565 $allowed_tags['iframe'] = [
3566 'src' => true,
3567 'width' => true,
3568 'height' => true,
3569 'frameborder' => true,
3570 'allowfullscreen' => true,
3571 'class' => true,
3572 'style' => true,
3573 'title' => true,
3574 'allow' => true,
3575 'name' => true,
3576 'referrerpolicy' => true,
3577 'loading' => true,
3578 'sandbox' => true,
3579 ];
3580 $allowed_tags['img'] = [
3581 'src' => true,
3582 'alt' => true,
3583 'title' => true,
3584 'width' => true,
3585 'height' => true,
3586 'class' => true,
3587 'id' => true,
3588 'style' => true,
3589 'loading' => true,
3590 'srcset' => true,
3591 'sizes' => true,
3592 ];
3593
3594 if ($allow_forms) {
3595 $form_attributes = [
3596 'id' => true,
3597 'class' => true,
3598 'style' => true,
3599 'name' => true,
3600 'value' => true,
3601 'type' => true,
3602 'placeholder' => true,
3603 'action' => true,
3604 'method' => true,
3605 'target' => true,
3606 'enctype' => true,
3607 'disabled' => true,
3608 'readonly' => true,
3609 'required' => true,
3610 'checked' => true,
3611 'selected' => true,
3612 'multiple' => true,
3613 'size' => true,
3614 'rows' => true,
3615 'cols' => true,
3616 'maxlength' => true,
3617 'minlength' => true,
3618 'min' => true,
3619 'max' => true,
3620 'step' => true,
3621 'pattern' => true,
3622 'autocomplete'=> true,
3623 'autofocus' => true,
3624 'for' => true,
3625 ];
3626 $allowed_tags['form'] = $form_attributes;
3627 $allowed_tags['input'] = $form_attributes;
3628 $allowed_tags['button'] = $form_attributes;
3629 $allowed_tags['textarea'] = $form_attributes;
3630 $allowed_tags['select'] = $form_attributes;
3631 $allowed_tags['option'] = $form_attributes;
3632 $allowed_tags['optgroup'] = $form_attributes;
3633 $allowed_tags['label'] = $form_attributes;
3634 $allowed_tags['fieldset'] = $form_attributes;
3635 $allowed_tags['legend'] = $form_attributes;
3636 }
3637
3638 // Apply wp_kses() to keep only allowed tags/attributes
3639 $content = wp_kses($content, $allowed_tags);
3640
3641 // Finally, validate iframe src for security (allow https only, block javascript: etc.)
3642 $content = preg_replace_callback('/<iframe[^>]+src=["\']([^"\']+)["\'][^>]*>(?:<\/iframe>)?/i', function($matches) {
3643 $src = $matches[1];
3644 // Allow any https:// or http:// URL, but block javascript:, data:, vbscript:, etc.
3645 if (preg_match('/^(https?:)?\/\//i', $src) && !preg_match('/^(javascript|data|vbscript|about):/i', $src)) {
3646 return $matches[0]; // keep safe iframe
3647 }
3648 // Strip unsafe iframe
3649 return '';
3650 }, $content);
3651
3652 return $content;
3653 }
3654
3655 private function normalize_hotspot_external_url($url) {
3656 $url = trim((string) $url);
3657
3658 if (
3659 $url === '' ||
3660 preg_match('/^[a-z][a-z0-9+.-]*:/i', $url) ||
3661 preg_match('/^[\/#?]/', $url)
3662 ) {
3663 return $url;
3664 }
3665
3666 if (preg_match('/^[^\s\/]+\.[^\s\/]+(?:[\/?#]|$)/i', $url)) {
3667 return 'https://' . $url;
3668 }
3669
3670 return $url;
3671 }
3672
3673 }
3674