PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 9.1.4
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v9.1.4
9.2.0 9.1.4 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 All 224 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.1.4, at legacy/admin/classes/class-wpvr-scene.php

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