PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 8.5.68
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v8.5.68
9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 8.5.4 All 221 releases
wpvr / admin / helpers / class-wpvr-format.php

class-wpvr-format.php in WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress 8.5.68, at admin/helpers/class-wpvr-format.php

1,606 lines 60.0 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 WPVR data formation
5 *
6 * @link http://rextheme.com/
7 * @since 1.0.0
8 *
9 * @package Wpvr
10 * @subpackage Wpvr/admin/views
11 */
12
13 class WPVR_Format
14 {
15
16 /**
17 * Setup checkboxes values for meta fields
18 * @param string $arg
19 *
20 * @return bool
21 * @since 8.0.0
22 */
23 public function set_checkbox_value($arg)
24 {
25 $data = sanitize_text_field($arg);
26 if ($data == 'off') {
27 return $data = false;
28 } else {
29 return $data = true;
30 }
31 }
32
33
34 /**
35 * Setup checkboxes values for meta fields while default value is on
36 * @param string $arg
37 *
38 * @return bool
39 * @since 8.0.0
40 */
41 public function set_checkbox_on_value($arg)
42 {
43 $data = sanitize_text_field($arg);
44 if ($data == 'on') {
45 return $data = true;
46 } else {
47 return $data = false;
48 }
49 }
50
51
52 /**
53 * Setup checkboxes values for pro version meta fields
54 * @param string $arg
55 *
56 * @return bool
57 * @since 8.0.0
58 */
59 public function set_pro_checkbox_value($arg)
60 {
61 $data = sanitize_text_field($arg);
62 if ($data == 'on') {
63 return $data = 'on';
64 } else {
65 return $data = 'off';
66 }
67 }
68
69
70 /**
71 * Preapre default scene ID for Tour
72 * @param array $panodata
73 *
74 * @return string
75 * @since 8.0.0
76 */
77 public function prepare_default_scene($panodata)
78 {
79 $allsceneids = array();
80
81 foreach ($panodata["scene-list"] as $panoscenes) {
82 if (!empty($panoscenes['scene-id'])) {
83 array_push($allsceneids, $panoscenes['scene-id']);
84 }
85 if ($panoscenes['dscene'] == 'on') {
86 return $default_scene = $panoscenes['scene-id'];
87 }
88 }
89
90 if (empty($default_scene)) {
91 if ($allsceneids) {
92 return $default_scene = $allsceneids[0];
93 }
94 }
95 }
96
97
98 /**
99 * Prepare panaromic data for Tour
100 *
101 * @param string $panodata
102 *
103 * @return array
104 * @since 8.0.0
105 */
106 public function prepare_panodata($panodata)
107 {
108 $panolist = stripslashes($panodata);
109 $panodata = (array)json_decode($panolist);
110 $panolist = array();
111 if (is_array($panodata["scene-list"])) {
112 foreach ($panodata["scene-list"] as $scenes_data) {
113 $temp_array = array();
114 $temp_array = (array)$scenes_data;
115
116 if ($temp_array['hotspot-list']) {
117 $_hotspot_array = array();
118 foreach ($temp_array['hotspot-list'] as $temp_hotspot) {
119
120 $temp_hotspot = (array)$temp_hotspot;
121 $_hotspot_array[] = $temp_hotspot;
122 }
123 }
124
125 $temp_array['hotspot-list'] = $_hotspot_array;
126 $panolist['scene-list'][] = $temp_array;
127 }
128 }
129 $panodata = $panolist;
130 return $panodata;
131 }
132
133
134 /**
135 * Remove empty scene and hotspot from panaromic data list
136 *
137 * @param array $panodata
138 *
139 * @return array
140 * @since 8.0.0
141 */
142 public function remove_empty_scene_and_hotspot($panodata)
143 {
144 $panolength = count($panodata["scene-list"]);
145 for ($i = 0; $i < $panolength; $i++) {
146 if (empty($panodata["scene-list"][$i]['scene-id'])) {
147 unset($panodata["scene-list"][$i]);
148 } else {
149 $panohotspotlength = count($panodata["scene-list"][$i]['hotspot-list']);
150 for ($j = 0; $j < $panohotspotlength; $j++) {
151 if (empty($panodata["scene-list"][$i]['hotspot-list'][$j]['hotspot-title'])) {
152 unset($panodata["scene-list"][$i]['hotspot-list'][$j]);
153 }
154 }
155 }
156 }
157 return $panodata;
158 }
159
160
161 /**
162 * Prepare tour rotation wrapper data
163 *
164 * @param array $pano_array
165 * @param string $rotation
166 *
167 * @return array
168 * @since 8.0.0
169 */
170 public function prepare_rotation_wrapper_data($pano_array, $rotation)
171 {
172 if ($rotation == 'off') {
173 unset($pano_array['autoRotate']);
174 unset($pano_array['autoRotateInactivityDelay']);
175 unset($pano_array['autoRotateStopDelay']);
176 }
177 if (empty($pano_array['autoRotate'])) {
178 unset($pano_array['autoRotate']);
179 unset($pano_array['autoRotateInactivityDelay']);
180 unset($pano_array['autoRotateStopDelay']);
181 }
182 if (empty($pano_array['autoRotateInactivityDelay'])) {
183 unset($pano_array['autoRotateInactivityDelay']);
184 }
185 if (empty($pano_array['autoRotateStopDelay'])) {
186 unset($pano_array['autoRotateStopDelay']);
187 }
188 return $pano_array;
189 }
190
191
192 public function prepare_video_settings_data()
193 {
194 $autoplay = '';
195 if (isset($_POST['autoplay'])) {
196 $autoplay = sanitize_text_field($_POST['autoplay']);
197 }
198
199 $loop = '';
200 if (isset($_POST['loop'])) {
201 $loop = sanitize_text_field($_POST['loop']);
202 }
203
204 return array(
205 'autoplay' => $autoplay,
206 'loop' => $loop
207 );
208 }
209
210
211 /**
212 * Prepare meta data when video url has youtube
213 *
214 * @param string $videourl
215 *
216 * @return string
217 * @since 8.0.0
218 */
219 public function prepare_youtube_video_meta_data($videourl, $videodata)
220 {
221 $explodeid = '';
222 $explodeid = explode("=", $videourl);
223
224 if ($videodata['autoplay'] == 'on') {
225 $autoplay = '&autoplay=1';
226 } else {
227 $autoplay = '';
228 }
229
230 if ($videodata['loop'] == 'on') {
231 $loop = '&loop=1';
232 } else {
233 $loop = '';
234 }
235
236 $foundid = '';
237 $foundid = $explodeid[1] . '?' . $autoplay . $loop;
238 $html = '';
239 $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/' . $foundid . '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
240 return $html;
241 }
242
243 /**
244 * Prepare meta data when video url has youtu.be
245 *
246 * @param string $videourl
247 *
248 * @return string
249 * @since 8.0.0
250 */
251 public function prepare_youtu_be_video_meta_data($videourl, $videodata)
252 {
253 $explodeid = '';
254 $explodeid = explode("/", $videourl);
255
256 if ($videodata['autoplay'] == 'on') {
257 $autoplay = '&autoplay=1';
258 } else {
259 $autoplay = '';
260 }
261
262 if ($videodata['loop'] == 'on') {
263 $loop = '&loop=1';
264 } else {
265 $loop = '';
266 }
267
268 $foundid = '';
269 $foundid = $explodeid[3] . '?' . $autoplay . $loop;
270 $html = '';
271 $html .= '<iframe width="600" height="400" src="https://www.youtube.com/embed/' . $foundid . '" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>';
272 return $html;
273 }
274
275 /**
276 * Prepare meta data when video url has vimeo
277 *
278 * @param string $videourl
279 *
280 * @return string
281 * @since 8.0.0
282 */
283 public function prepare_vimeo_video_meta_data($videourl, $videodata)
284 {
285 $explodeid = '';
286 $explodeid = explode("/", $videourl);
287
288 if ($videodata['autoplay'] == 'on') {
289 $autoplay = '&autoplay=1&muted=1';
290 } else {
291 $autoplay = '';
292 }
293
294 if ($videodata['loop'] == 'on') {
295 $loop = '&loop=1';
296 } else {
297 $loop = '';
298 }
299
300 $foundid = '';
301 $foundid = $explodeid[3] . '?' . $autoplay . $loop;
302 $html = '';
303 $html .= '<iframe src="https://player.vimeo.com/video/' . $foundid . '" width="600" height="400" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
304 return $html;
305 }
306
307 /**
308 * Prepare meta data when video is selfhosted
309 *
310 * @param string $videourl
311 *
312 * @return string
313 * @since 8.0.0
314 */
315 public function prepare_selfhost_video_meta_data($videourl, $vidid, $videodata)
316 {
317 if ($videodata['autoplay'] == 'on') {
318 $autoplay = 'autoplay muted';
319 } else {
320 $autoplay = '';
321 }
322
323 if ($videodata['loop'] == 'on') {
324 $loop = 'loop';
325 } else {
326 $loop = '';
327 }
328
329 $html = '';
330 $html .= '<video id="' . $vidid . '" class="video-js vjs-default-skin vjs-big-play-centered" ' . $autoplay . ' ' . $loop . ' controls preload="auto" style="width:100%; height: 100%;" poster="" >';
331 $html .= '<source src="' . $videourl . '" type="video/mp4"/>';
332 $html .= '<p class="vjs-no-js">';
333 $html .= 'To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com html5-video-support/" target="_blank">supports HTML5 video</a>';
334 $html .= '</p>';
335 $html .= '</video>';
336 return $html;
337 }
338
339
340 /**
341 * Prepare scene data for Tour preview
342 *
343 * @param array $panodata
344 *
345 * @return array
346 * @since 8.0.0
347 */
348 public function prepare_scene_data_for_preview($panodata)
349 {
350 $scene_data = array();
351 foreach ($panodata["scene-list"] as $panoscenes) {
352 if (!empty($panoscenes['scene-id'])) {
353 $scene_ititle = sanitize_text_field(@$panoscenes["scene-ititle"]);
354 $scene_author = sanitize_text_field(@$panoscenes["scene-author"]);
355
356 $scene_vaov = isset($panoscenes["scene-vaov"]) ? (float)$panoscenes["scene-vaov"] : 180;
357 $scene_haov = isset($panoscenes["scene-vaov"]) ? (float)$panoscenes["scene-haov"] : 360;
358 $scene_vertical_offset = isset($panoscenes["scene-vertical-offset"]) ? (float)$panoscenes["scene-vertical-offset"] : 0;
359
360 $default_scene_pitch = isset($panoscenes["scene-pitch"]) ? (float)$panoscenes["scene-pitch"] : null;
361 $default_scene_yaw = isset($panoscenes["scene-yaw"]) ? (float)$panoscenes["scene-yaw"] : null;
362 $scene_max_pitch = isset($panoscenes["scene-maxpitch"]) ? (float)$panoscenes["scene-maxpitch"] : '';
363 $scene_min_pitch = isset($panoscenes["scene-minpitch"]) ? (float)$panoscenes["scene-minpitch"] : '';
364 $scene_max_yaw = isset($panoscenes["scene-maxyaw"]) ? (float)$panoscenes["scene-maxyaw"] : '';
365 $scene_min_yaw = isset($panoscenes["scene-minyaw"]) ? (float)$panoscenes["scene-minyaw"] : '';
366
367 $default_zoom = isset($panoscenes["scene-zoom"]) ? $panoscenes["scene-zoom"] : 100;
368 if (!empty($default_zoom)) {
369 $default_zoom = isset($panoscenes["scene-zoom"]) ? (int)$panoscenes["scene-zoom"] : (int)$default_zoom;
370 } else {
371 $default_zoom = 100;
372 }
373
374 $max_zoom = isset($panoscenes["scene-maxzoom"]) ? $panoscenes["scene-maxzoom"] : 120;
375 if (!empty($max_zoom)) {
376 $max_zoom = isset($panoscenes["scene-maxzoom"]) ? (int)$panoscenes["scene-maxzoom"] : (int)$max_zoom;
377 } else {
378 $max_zoom = 120;
379 }
380
381 $min_zoom = isset($panoscenes["scene-minzoom"]) ? $panoscenes["scene-minzoom"] : 50;
382 if (!empty($min_zoom)) {
383 $min_zoom = isset($panoscenes["scene-minzoom"]) ? (int)$panoscenes["scene-minzoom"] : (int)$min_zoom;
384 } else {
385 $min_zoom = 50;
386 }
387
388 $hotspot_datas = $panoscenes["hotspot-list"];
389
390 $hotspots = $this->prepare_hotspot_data_for_preview($hotspot_datas);
391
392 $scene_info = array();
393 if ($panoscenes["scene-type"] == 'cubemap') {
394 $pano_type = 'cubemap';
395 $pano_attachment = array(
396 $panoscenes["scene-attachment-url-face0"],
397 $panoscenes["scene-attachment-url-face1"],
398 $panoscenes["scene-attachment-url-face2"],
399 $panoscenes["scene-attachment-url-face3"],
400 $panoscenes["scene-attachment-url-face4"],
401 $panoscenes["scene-attachment-url-face5"]
402 );
403
404 $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, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
405 } else {
406 $scene_info = array("type" => $panoscenes["scene-type"], "panorama" => $panoscenes["scene-attachment-url"], "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, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
407 }
408
409 if (empty($panoscenes["scene-ititle"])) {
410 unset($scene_info['title']);
411 }
412 if (empty($panoscenes["scene-author"])) {
413 unset($scene_info['author']);
414 }
415
416 if (empty($scene_vaov)) {
417 unset($scene_info['vaov']);
418 }
419
420 if (empty($scene_haov)) {
421 unset($scene_info['haov']);
422 }
423
424 if (empty($scene_vertical_offset)) {
425 unset($scene_info['vOffset']);
426 }
427
428 if (isset($panoscenes["cvgscene"])) {
429 if ($panoscenes["cvgscene"] == "off") {
430 unset($scene_info['maxPitch']);
431 unset($scene_info['minPitch']);
432 }
433 }
434
435 if (empty($panoscenes["scene-maxpitch"])) {
436 unset($scene_info['maxPitch']);
437 }
438
439 if (empty($panoscenes["scene-minpitch"])) {
440 unset($scene_info['minPitch']);
441 }
442
443 if (isset($panoscenes["chgscene"])) {
444 if ($panoscenes["chgscene"] == "off") {
445 unset($scene_info['maxYaw']);
446 unset($scene_info['minYaw']);
447 }
448 }
449 if (empty($panoscenes["scene-maxyaw"])) {
450 unset($scene_info['maxYaw']);
451 }
452
453 if (empty($panoscenes["scene-minyaw"])) {
454 unset($scene_info['minYaw']);
455 }
456
457 $scene_array = array();
458 $scene_array = array(
459 $panoscenes["scene-id"] => $scene_info
460 );
461 $scene_data[$panoscenes["scene-id"]] = $scene_info;
462 }
463 }
464 return $scene_data;
465 }
466
467
468 /**
469 * Preapre hotspot data for Tour preview
470 *
471 * @param array $hotspot_datas
472 *
473 * @return array
474 * @since 8.0.0
475 */
476 private function prepare_hotspot_data_for_preview($hotspot_datas)
477 {
478 $hotspots = array();
479 foreach ($hotspot_datas as $hotspot_data) {
480
481 if (!empty($hotspot_data["hotspot-title"])) {
482
483 $hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
484 $hotspot_content = '';
485
486 ob_start();
487 do_action('wpvr_hotspot_content_admin', $hotspot_data);
488 $hotspot_content = ob_get_clean();
489
490
491 if (!$hotspot_content) $hotspot_content = $hotspot_data["hotspot-content"];
492
493
494 $hotspot_info = array(
495 "text" => $hotspot_data["hotspot-title"],
496 "pitch" => $hotspot_data["hotspot-pitch"],
497 "yaw" => $hotspot_data["hotspot-yaw"],
498 "type" => $hotspot_type,
499 "URL" => $hotspot_data["hotspot-url"],
500 "clickHandlerArgs" => $hotspot_content,
501 "createTooltipArgs" => $hotspot_data["hotspot-hover"],
502 "sceneId" => $hotspot_data["hotspot-scene"],
503 'hotspot_type' => $hotspot_data['hotspot-type']
504 );
505
506 array_push($hotspots, $hotspot_info);
507 if (empty($hotspot_data["hotspot-scene"])) {
508 unset($hotspot_info['targetPitch']);
509 unset($hotspot_info['targetYaw']);
510 }
511 }
512 }
513 return $hotspots;
514 }
515
516
517 /**
518 * Prepare youtube video for preview
519 *
520 * @param string $videourl
521 *
522 * @return string
523 * @since 8.0.0
524 */
525 public function prepare_youtube_video_preview($videourl, $videodata)
526 {
527 $explodeid = '';
528 $explodeid = explode("=", $videourl);
529
530 if ($videodata['autoplay'] == 'on') {
531 $autoplay = '&autoplay=1';
532 $muted = '&mute=1';
533 } else {
534 $autoplay = '';
535 $muted = '';
536 }
537
538 if ($videodata['loop'] == 'on') {
539 $loop = '&loop=1';
540 } else {
541 $loop = '';
542 }
543
544 $html = '';
545
546 $html .= '
547 <iframe src="https://www.youtube.com/embed/' . $explodeid[1] . '?rel=0&modestbranding=1' . $loop . '&autohide=1' . $muted . '&showinfo=0&controls=1' . $autoplay . '" width="600" height="400" frameborder="0" allowfullscreen></iframe>
548 ';
549 return $html;
550 }
551
552
553 /**
554 * Prepare shortcode data for youtube video url
555 *
556 * @param array $postdata
557 * @param mixed $width
558 * @param mixed $height
559 *
560 * @return string
561 * @since 8.0.0
562 */
563 public function preapre_youtube_video_shortcode_data($postdata, $width, $height, $autoplay, $loop, $radius)
564 {
565 $explodeid = '';
566 $explodeid = explode("=", $postdata['vidurl']);
567
568 $foundid = '';
569 $muted = '&mute=1';
570 $autoplay = ($autoplay == 'on') ? '&autoplay=1' : '';
571 $loop = ($loop == 'on') ? '&loop=1' : '';
572
573 if (strpos($postdata['vidurl'], 'youtu') > 0) {
574 $explodeid = explode("/", $postdata['vidurl']);
575 $foundid = $explodeid[3] . '?' . $autoplay . $loop;
576 $expdata = $explodeid[3];
577 } else {
578 $foundid = $explodeid[1] . '?' . $autoplay . $loop;
579 $expdata = $explodeid[1];
580 }
581
582 $playlist = '&playlist='. $expdata;
583 $playlist = str_replace("?feature=shared","",$playlist);
584
585 $html = '';
586 $html .= '<div style="text-align:center; max-width:100%; width:' . $width . '; height:' . $height . '; border-radius: ' . $radius . '; margin: 0 auto;">';
587
588 // Add browser compatibility detection script
589 $html .= '<script>
590 function wpvr_check_360_support() {
591 var support = {
592 supported: false,
593 fullySupported: false,
594 webgl: false,
595 orientation: false,
596 gyroscope: false,
597 touch: false,
598 browser: "unknown",
599 isMobile: false,
600 details: []
601 };
602
603 // Detect mobile devices
604 support.isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
605 if (support.isMobile) {
606 support.details.push("Mobile device detected");
607 }
608
609 // Browser detection
610 var ua = navigator.userAgent;
611 if (/^((?!chrome|android).)*safari/i.test(ua)) {
612 support.browser = "safari";
613 support.details.push("Safari browser detected");
614 } else if (ua.indexOf("Chrome") > -1) {
615 support.browser = "chrome";
616 support.details.push("Chrome browser detected");
617 } else if (ua.indexOf("Firefox") > -1) {
618 support.browser = "firefox";
619 support.details.push("Firefox browser detected");
620 } else if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) {
621 support.browser = "ie";
622 support.details.push("Internet Explorer detected");
623 } else if (ua.indexOf("Edge") > -1 || ua.indexOf("Edg") > -1) {
624 support.browser = "edge";
625 support.details.push("Edge browser detected");
626 } else if (ua.indexOf("Opera") > -1 || ua.indexOf("OPR") > -1) {
627 support.browser = "opera";
628 support.details.push("Opera browser detected");
629 }
630
631 // Check WebGL support
632 try {
633 var canvas = document.createElement("canvas");
634 support.webgl = !!(window.WebGLRenderingContext &&
635 (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
636
637 if (support.webgl) {
638 support.details.push("WebGL supported");
639 } else {
640 support.details.push("WebGL not supported");
641 }
642 } catch (e) {
643 support.webgl = false;
644 support.details.push("WebGL detection error: " + e.message);
645 }
646
647 // Check device orientation support
648 support.orientation = !!(window.DeviceOrientationEvent);
649 if (support.orientation) {
650 support.details.push("Device Orientation API supported");
651 } else {
652 support.details.push("Device Orientation API not supported");
653 }
654
655 // Check for gyroscope
656 if (window.Gyroscope) {
657 support.gyroscope = true;
658 support.details.push("Gyroscope supported");
659 } else {
660 support.details.push("Gyroscope not supported");
661 }
662
663 // Check touch support for mobile interaction
664 support.touch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
665 if (support.touch) {
666 support.details.push("Touch supported");
667 } else {
668 support.details.push("Touch not supported");
669 }
670
671 // Overall support determination
672 support.supported = support.webgl;
673
674 // Full support means WebGL + orientation on mobile or WebGL on desktop
675 support.fullySupported = support.webgl &&
676 ((support.isMobile && support.orientation) || !support.isMobile);
677
678 // Browser-specific warnings
679 if (support.browser === "safari" && /iPhone|iPad|iPod/.test(navigator.userAgent)) {
680 support.browserWarning = "iPhone has limited support for 360 videos in browser. The experience may not be optimal.";
681 support.fullySupported = false;
682 } else if (support.browser === "ie") {
683 support.browserWarning = "Internet Explorer has limited support for 360 videos. The experience may not be optimal.";
684 support.fullySupported = false;
685 } else if (!support.supported) {
686 support.browserWarning = "Your browser does not fully support 360° videos. For the best experience, please use a modern browser with WebGL support.";
687 }
688
689 return support;
690 }
691 </script>';
692
693 $random_id = 'video-container-' . rand(10000, 99999);
694 $html .= '<div id="' . $random_id . '-container" style="position:relative; width:100%; height:100%;">';
695
696 // First, always check browser compatibility before showing anything
697 $html .= '<div id="' . $random_id . '-compatibility-check" style="position:none; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:#f9f9f9; border-radius:' . $radius . ';">
698 <div style="margin-bottom:20px; text-align:center;">
699 <div class="wpvr-loading-spinner" style="border:5px solid #f3f3f3; border-top:5px solid #3498db; border-radius:50%; width:50px; height:50px; margin:0 auto 15px; animation:wpvr-spin 1s linear infinite;"></div>
700 <p style="margin:0;">Checking browser compatibility...</p>
701 </div>
702 </div>';
703
704 // Add animation for spinner
705 $html .= '<style>@keyframes wpvr-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>';
706
707 // Add the iframe (initially hidden)
708 $html .= '<div id="' . esc_attr( $random_id . '-frame' ) . '" style="text-align:center; max-width:100%; width:' . esc_attr( $width ) . '; height:' . esc_attr( $height ) . '; border-radius:' . esc_attr( $radius ) . '; margin: 0 auto; display:none;">';
709 $html .= '<iframe id="' . esc_attr( $random_id . '-iframe' ) . '" src="https://www.youtube.com/embed/' . rawurlencode( sanitize_text_field( $expdata ) ) . '?rel=0&modestbranding=1' . $loop . '&autohide=1' . $muted . '&showinfo=0&controls=1' . $autoplay . $playlist . '&enablejsapi=1" width="100%" height="100%" style="border-radius:' . esc_attr( $radius ) . ';" frameborder="0" allowfullscreen allow="accelerometer; gyroscope; picture-in-picture"></iframe>';
710 $html .= '</div>';
711
712 // Add permission request button (hidden by default) - Only shown for fully supported devices
713 $html .= '<div id="' . $random_id . '-permission-request" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.7); color:white; text-align:center; border-radius:' . $radius . ';">';
714 $html .= '<p style="font-size:16px; margin:0 20px 15px;">For the best 360° video experience on mobile</p>';
715 $html .= '<button id="' . $random_id . '-permission-button" style="padding:10px 15px; background-color:#0085ba; color:#fff; border:none; border-radius:4px; cursor:pointer;">Allow motion and orientation access</button>';
716 $html .= '</div>';
717
718 // Add browser compatibility warning message
719 $html .= '<div id="' . $random_id . '-browser-warning" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.7); color:white; text-align:center; border-radius:' . $radius . ';">';
720 $html .= '<p id="' . $random_id . '-warning-text" style="font-size:16px; margin:0 20px 5px;"></p>';
721 $html .= '<p style="font-size:14px; margin:5px 20px 15px;">For the best experience, consider using Chrome or Firefox.</p>';
722 $html .= '<button id="' . $random_id . '-browser-continue" style="padding:10px 15px; background-color:#0085ba; color:#fff; border:none; border-radius:4px; cursor:pointer;">Continue Anyway</button>';
723 $html .= '</div>';
724
725 // Main script for handling compatibility and permissions
726 $html .= '<script>
727 // Wait for DOM to be fully loaded
728 document.addEventListener("DOMContentLoaded", function() {
729 // Check compatibility first
730 var supportInfo = wpvr_check_360_support();
731 let compatibilityCheck = document.getElementById("' . $random_id . '-compatibility-check");
732 if(supportInfo.isMobile && !supportInfo.fullySupported) {
733 compatibilityCheck.style.display = "flex";
734 }
735 // Hide the compatibility check screen after a short delay
736 setTimeout(function() {
737 document.getElementById("' . $random_id . '-compatibility-check").style.display = "none";
738 // If browser doesn\'t support 360 videos well, show warning
739 if (!supportInfo.supported || supportInfo.browserWarning) {
740 document.getElementById("' . $random_id . '-warning-text").textContent =
741 supportInfo.browserWarning || "Your browser may not fully support 360° videos.";
742 document.getElementById("' . $random_id . '-browser-warning").style.display = "flex";
743
744 // Add continue anyway button handler
745 document.getElementById("' . $random_id . '-browser-continue").addEventListener("click", function() {
746 document.getElementById("' . $random_id . '-browser-warning").style.display = "none";
747 document.getElementById("' . $random_id . '-frame").style.display = "block";
748 initializeYouTubePlayer();
749 });
750 }
751 // If browser fully supports 360 and is mobile, show permission request
752 else if (supportInfo.fullySupported && supportInfo.isMobile) {
753 document.getElementById("' . $random_id . '-permission-request").style.display = "flex";
754
755 // Add permission request button handler
756 document.getElementById("' . $random_id . '-permission-button").addEventListener("click", function() {
757 requestDevicePermissions();
758 });
759 }
760 // Otherwise just show the video
761 else {
762 document.getElementById("' . $random_id . '-frame").style.display = "block";
763 initializeYouTubePlayer();
764 }
765 }, 1000); // Show compatibility check for at least 1 second
766
767 // Function to request device permissions on supported mobile devices
768 function requestDevicePermissions() {
769 try {
770 if (typeof DeviceOrientationEvent !== "undefined" &&
771 typeof DeviceOrientationEvent.requestPermission === "function") {
772
773 DeviceOrientationEvent.requestPermission()
774 .then(function(response) {
775 if (response === "granted") {
776 // Also request motion permission if available
777 if (typeof DeviceMotionEvent !== "undefined" &&
778 typeof DeviceMotionEvent.requestPermission === "function") {
779
780 DeviceMotionEvent.requestPermission()
781 .then(function() {
782 showVideo();
783 })
784 .catch(function() {
785 showVideo();
786 });
787 } else {
788 showVideo();
789 }
790 } else {
791 showVideo();
792 }
793 })
794 .catch(function() {
795 showVideo();
796 });
797 } else {
798 showVideo();
799 }
800 } catch (error) {
801 showVideo();
802 }
803 }
804
805 // Helper function to show video after permissions
806 function showVideo() {
807 document.getElementById("' . $random_id . '-permission-request").style.display = "none";
808 document.getElementById("' . $random_id . '-frame").style.display = "block";
809 initializeYouTubePlayer();
810 }
811
812 // Function to initialize YouTube player
813 function initializeYouTubePlayer() {
814 if (window.YT) {
815 initPlayer();
816 } else {
817 var tag = document.createElement("script");
818 tag.src = "https://www.youtube.com/iframe_api";
819 var firstScriptTag = document.getElementsByTagName("script")[0];
820 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
821 window.onYouTubeIframeAPIReady = initPlayer;
822 }
823
824 function initPlayer() {
825 var player = new YT.Player("' . $random_id . '-iframe", {
826 events: {
827 "onReady": function(event) {
828 }
829 }
830 });
831 }
832 }
833 });
834 </script>';
835 $html .= '</div>'; // Close container
836 $html .= '</div>'; // Close outer container
837 return $html;
838 }
839 /**
840 * Prepare shortcode data for Vimeo url
841 *
842 * @param array $postdata
843 * @param mixed $width
844 * @param mixed $height
845 *
846 * @return string
847 * @since 8.0.0
848 */
849 public function prepare_vimeo_video_shortcode_data($postdata, $width, $height, $autoplay, $loop, $radius)
850 {
851 $explodeid = '';
852 $explodeid = explode("/", $postdata['autoplay']);
853 $foundid = '';
854
855 $autoplay = ($autoplay == 'on') ? '&autoplay=1&muted=1' : '';
856 $loop = ($loop == 'on') ? '&loop=1' : '';
857 if(!isset($explodeid[3])){
858 $vidurl = explode('/',$postdata['vidurl']);
859 $foundid = end($vidurl);
860 }else{
861 $foundid = $explodeid[3] . '?' . $autoplay . $loop;
862 }
863 $html = '';
864 $html .= '<div style="text-align: center; max-width:100%; width:' . $width . '; height:' . $height . '; margin: 0 auto;">';
865 $html .= '<iframe src="https://player.vimeo.com/video/' . $foundid . '" width="' . trim($width, 'px') . '" height="' . trim($height, 'px') . '" style="border-radius: ' . $radius . ';" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>';
866 $html .= '</div>';
867 return $html;
868 }
869
870
871 /**
872 * Prepare shortcode data from regular postdata
873 *
874 * @param integer $id
875 * @param array $postdata
876 * @param string $width
877 * @param string $height
878 *
879 * @return string
880 * @since 8.0.0
881 */
882 public function prepare_regular_video_shortcode_data($id, $postdata, $width, $height, $radius)
883 {
884 $html = '';
885 $html .= '<div id="pano' . $id . '" class="pano-wrap" style="max-width:100%; width: ' . $width . '; height: ' . $height . '; border-radius: ' . $radius . '; margin: 0 auto;">';
886 $html .= '<div style="width:100%; height:100%; ">' . $postdata['panoviddata'] . '</div>';
887
888 $html .= '
889 <style>
890 .video-js {
891 border-radius:' . $radius . ';
892 }
893 .video-js canvas{
894 border-radius:' . $radius . ';
895 }
896 #pano' . $id . ' .vjs-poster {
897 border-radius: ' . $radius . ';
898 }
899 </style>
900
901 ';
902
903 $html .= '</div>';
904
905 //video js vr setup //
906 $html .= '<script>';
907 $html .= '
908 (function (window, videojs) {
909 var player = window.player = videojs("' . $postdata['vidid'] . '");
910 player.mediainfo = player.mediainfo || {};
911 player.mediainfo.projection = "equirectangular";
912
913 // AUTO is the default and looks at mediainfo
914 var vr = window.vr = player.vr({ projection: "AUTO", debug: true, forceCardboard: false, antialias: false });
915 }(window, window.videojs));
916
917 ';
918 $html .= '</script>';
919 //video js vr end //
920 return $html;
921 }
922
923
924 /**
925 * Prepare scene data for shortcode
926 *
927 * @param array $panodata
928 *
929 * @return array
930 * @since 8.0.0
931 */
932 public function prepare_shortcode_scene_data($panodata)
933 {
934 $scene_data = array();
935
936 if (!empty($panodata["scene-list"])) {
937 $scene_data = $this->prepare_shortcode_scene_list($panodata);
938 }
939
940 return $scene_data;
941 }
942
943
944 /**
945 * Prepare scene lists data for shortcode
946 *
947 * @param array $panodata
948 *
949 * @return array
950 * @since 8.0.0
951 */
952 private function prepare_shortcode_scene_list($panodata)
953 {
954 $scene_data = array();
955 foreach ($panodata["scene-list"] as $panoscenes) {
956 $hotspot_datas = array();
957 if (isset($panoscenes["hotspot-list"])) {
958 $hotspot_datas = $panoscenes["hotspot-list"];
959 }
960 $hotspots = $this->prepare_shortcode_hotspots_list($hotspot_datas);
961 $device_scene = $this->get_shortcode_device_scene($panoscenes['scene-attachment-url']);
962 $scene_info = $this->get_shortcode_scene_info($panoscenes, $hotspots, $device_scene);
963 $scene_data[$panoscenes["scene-id"]] = $scene_info;
964 }
965 return $scene_data;
966 }
967
968
969 /**
970 * Prepare hotspots list for shortcode
971 *
972 * @param array $hotspot_datas
973 *
974 * @return array
975 * @since 8.0.0
976 */
977 private function prepare_shortcode_hotspots_list($hotspot_datas)
978 {
979 $hotspots = array();
980 foreach ($hotspot_datas as $hotspot_data) {
981 $hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
982 $hotspot_content = $hotspot_data["hotspot-content"];
983 $hotspot_info = $this->get_shortcode_hotspot_info($hotspot_data, $hotspot_type, $hotspot_content);
984 array_push($hotspots, $hotspot_info);
985 }
986 return $hotspots;
987 }
988
989
990 /**
991 * Return hotspot info array to hotspot list
992 *
993 * @param array $hotspot_data
994 * @param string $hotspot_type
995 * @param string $hotspot_content
996 *
997 * @return array
998 * @since 8.0.0
999 */
1000 private function get_shortcode_hotspot_info($hotspot_data, $hotspot_type, $hotspot_content)
1001 {
1002 $hotspot_info = array(
1003 "text" => $hotspot_data["hotspot-title"],
1004 "pitch" => $hotspot_data["hotspot-pitch"],
1005 "yaw" => $hotspot_data["hotspot-yaw"],
1006 "type" => $hotspot_type,
1007 "cssClass" => $hotspot_data["hotspot-customclass"],
1008 "URL" => $hotspot_data["hotspot-url"],
1009 "wpvr_url_open" => isset($hotspot_data["wpvr_url_open"][0]) ? $hotspot_data["wpvr_url_open"][0] : 'off',
1010 "clickHandlerArgs" => $hotspot_content,
1011 "createTooltipArgs" => $hotspot_data["hotspot-hover"],
1012 "sceneId" => $hotspot_data["hotspot-scene"],
1013 'hotspot_type' => $hotspot_data['hotspot-type']
1014 );
1015
1016 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1017
1018 if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1019 unset($hotspot_info["cssClass"]);
1020 }
1021 if (empty($hotspot_data["hotspot-scene"])) {
1022 unset($hotspot_info['targetPitch']);
1023 unset($hotspot_info['targetYaw']);
1024 }
1025 return $hotspot_info;
1026 }
1027
1028
1029 /**
1030 * Return scene info array for scene list
1031 *
1032 * @param array $panoscenes
1033 * @param array $hotspots
1034 * @param string $device_scene
1035 *
1036 * @return array
1037 * @since 8.0.0
1038 */
1039 private function get_shortcode_scene_info($panoscenes, $hotspots, $device_scene)
1040 {
1041 $scene_info = array();
1042 if ($panoscenes["scene-type"] == 'cubemap') {
1043 $pano_attachment = array(
1044 $panoscenes["scene-attachment-url-face0"],
1045 $panoscenes["scene-attachment-url-face1"],
1046 $panoscenes["scene-attachment-url-face2"],
1047 $panoscenes["scene-attachment-url-face3"],
1048 $panoscenes["scene-attachment-url-face4"],
1049 $panoscenes["scene-attachment-url-face5"]
1050 );
1051 $scene_info = array("type" => $panoscenes["scene-type"], "cubeMap" => $pano_attachment, "hotSpots" => $hotspots);
1052 } else {
1053 $scene_info = array("type" => $panoscenes["scene-type"], "panorama" => $device_scene, "hotSpots" => $hotspots);
1054 }
1055 return $scene_info;
1056 }
1057
1058
1059 /**
1060 * Return device scene for shortcode
1061 *
1062 * @param string $device_scene
1063 *
1064 * @return string
1065 * @since 8.0.0
1066 */
1067 private function get_shortcode_device_scene($device_scene)
1068 {
1069 $mobile_media_resize = get_option('mobile_media_resize');
1070 $file_accessible = ini_get('allow_url_fopen');
1071
1072 if ($mobile_media_resize == "true" && $device_scene) {
1073 if ($file_accessible == "1") {
1074 $image_info = getimagesize($device_scene);
1075 if ($image_info[0] > 4096) {
1076 $src_to_id_for_mobile = '';
1077 $src_to_id_for_desktop = '';
1078 if (wpvr_isMobileDevice()) {
1079 $src_to_id_for_mobile = attachment_url_to_postid($device_scene);
1080 if ($src_to_id_for_mobile) {
1081 $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1082 if ($mobile_scene[3]) {
1083 $device_scene = $mobile_scene[0];
1084 }
1085 }
1086 } else {
1087 $src_to_id_for_desktop = attachment_url_to_postid($device_scene);
1088 if ($src_to_id_for_desktop) {
1089 $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1090 if ($desktop_scene[0]) {
1091 $device_scene = $desktop_scene[0];
1092 }
1093 }
1094 }
1095 }
1096 }
1097 }
1098 return $device_scene;
1099 }
1100
1101
1102 /**
1103 * Prepare json response for shortcode
1104 *
1105 * @param string $autorotation
1106 * @param array $pano_response
1107 * @param string $panoid
1108 * @param integer $autorotationinactivedelay
1109 * @param integer $autorotationstopdelay
1110 *
1111 * @return array
1112 * @since 8.0.0
1113 */
1114 public function prepare_shortcode_response($autorotation, $pano_response, $panoid, $autorotationinactivedelay, $autorotationstopdelay)
1115 {
1116 $pano_id_array = array("panoid" => $panoid);
1117 if (empty($autorotation)) {
1118 unset($pano_response['autoRotate']);
1119 unset($pano_response['autoRotateInactivityDelay']);
1120 unset($pano_response['autoRotateStopDelay']);
1121 }
1122 if (empty($autorotationinactivedelay)) {
1123 unset($pano_response['autoRotateInactivityDelay']);
1124 }
1125 if (empty($autorotationstopdelay)) {
1126 unset($pano_response['autoRotateStopDelay']);
1127 }
1128 $response = array();
1129 $response = array($pano_id_array, $pano_response);
1130 if (!empty($response)) {
1131 $response = json_encode($response);
1132 }
1133 return $response;
1134 }
1135
1136
1137 /**
1138 * Prepare HTML and script contents for scene shortcode
1139 *
1140 * @param mixed $width
1141 * @param mixed $panoid
1142 * @param mixed $hotspoticoncolor
1143 * @param mixed $foreground_color
1144 * @param mixed $hotspotblink
1145 * @param mixed $pulse_color
1146 * @param mixed $radius
1147 * @param mixed $id
1148 * @param mixed $height
1149 * @param mixed $scene_data
1150 * @param mixed $response
1151 * @param mixed $autoload
1152 * @param mixed $default_scene
1153 * @param mixed $postdata
1154 *
1155 * @return string
1156 * @since 8.0.0
1157 */
1158 public function prepare_scene_shortcode_html_content($width, $panoid, $hotspoticoncolor, $foreground_color, $hotspotblink, $pulse_color, $radius, $id, $height, $scene_data, $response, $autoload, $default_scene, $postdata, $mobile_height, $gyro)
1159 {
1160 $html = '';
1161 $html .= '<style>';
1162
1163 if ($width == 'embed') {
1164 $html .= 'body{overflow: hidden;}';
1165 }
1166 // Return ID and Classes for CSS styling //
1167 $html = $this->get_shortcode_content_classes($html, $panoid, $hotspoticoncolor, $foreground_color);
1168 // Return webkit keyframes CSS styling //
1169 if ($hotspotblink == 'on') {
1170 $html = $this->get_shortcode_webkit_keyframes($html, $panoid, $pulse_color);
1171 }
1172 $status = get_option('wpvr_edd_license_status');
1173 if ($status !== false && $status == 'valid') {
1174 if (!$gyro) {
1175 $html .= '#' . $panoid . ' div.pnlm-orientation-button {
1176 display: none;
1177 }';
1178 }
1179 } else {
1180 $html .= '#' . $panoid . ' div.pnlm-orientation-button {
1181 display: none;
1182 }';
1183 }
1184 $html .= '</style>';
1185
1186 // Render pano wrapper contents //
1187 $html = $this->get_shortcode_pano_wrap_content($width, $radius, $html, $id, $height, $mobile_height);
1188 // Render hotspots contents //
1189 $html = $this->render_shortcode_hotspot_content($html, $id, $scene_data);
1190 // Render custom iframe content //
1191 $html = $this->render_shortcode_custom_iframe_wrapper($html, $id);
1192
1193 $html .= '</div>';
1194
1195 //script started
1196 $html = $this->get_shortcode_script_content($html, $response, $id, $autoload, $default_scene, $postdata);
1197 //script end
1198 return $html;
1199 }
1200
1201
1202 /**
1203 * Return ID and Classes for CSS styling
1204 *
1205 * @param mixed $html
1206 * @param mixed $panoid
1207 * @param mixed $hotspoticoncolor
1208 * @param mixed $foreground_color
1209 *
1210 * @return string
1211 * @since 8.0.0
1212 */
1213 private function get_shortcode_content_classes($html, $panoid, $hotspoticoncolor, $foreground_color)
1214 {
1215 $html .= '#' . $panoid . ' div.pnlm-hotspot-base.fas,
1216 #' . $panoid . ' div.pnlm-hotspot-base.fab,
1217 #' . $panoid . ' div.pnlm-hotspot-base.fa,
1218 #' . $panoid . ' div.pnlm-hotspot-base.fa-solid,
1219 #' . $panoid . ' div.pnlm-hotspot-base.far {
1220 display: block !important;
1221 background-color: ' . $hotspoticoncolor . ';
1222 color: ' . $foreground_color . ';
1223 border-radius: 100%;
1224 width: 30px;
1225 height: 30px;
1226 animation: icon-pulse' . $panoid . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1227 }';
1228 return $html;
1229 }
1230
1231
1232 /**
1233 * Resturn webkit keyframes CSS styling
1234 *
1235 * @param mixed $html
1236 * @param mixed $panoid
1237 * @param mixed $pulse_color
1238 *
1239 * @return string
1240 * @since 8.0.0
1241 */
1242 private function get_shortcode_webkit_keyframes($html, $panoid, $pulse_color)
1243 {
1244 $html .= '@-webkit-keyframes icon-pulse' . $panoid . ' {
1245 0% {
1246 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1247 }
1248 100% {
1249 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1250 }
1251 }
1252 @keyframes icon-pulse' . $panoid . ' {
1253 0% {
1254 box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
1255 }
1256 100% {
1257 box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
1258 }
1259 }';
1260 return $html;
1261 }
1262
1263
1264 /**
1265 * Render pano wrapper content depending on Tour Width, Height and radius
1266 *
1267 * @param mixed $width
1268 * @param mixed $radius
1269 * @param mixed $html
1270 * @param mixed $id
1271 * @param mixed $height
1272 *
1273 * @return string
1274 * @since 8.0.0
1275 */
1276 private function get_shortcode_pano_wrap_content($width, $radius, $html, $id, $height, $mobile_height)
1277 {
1278 if ($width == 'fullwidth') {
1279
1280 if (wpvr_isMobileDevice()) {
1281 if ($radius) {
1282 $html .= '<div id="pano' . $id . '" class="pano-wrap" style="text-align:center; border-radius:' . $radius . '; direction:ltr;">';
1283 } else {
1284 $html .= '<div id="pano' . $id . '" class="pano-wrap" style="text-align:center;">';
1285 }
1286 } else {
1287 if ($radius) {
1288 $html .= '<div id="pano' . $id . '" class="pano-wrap vrfullwidth" style=" text-align:center; height: ' . $height . '; border-radius:' . $radius . '; direction:ltr;" >';
1289 } else {
1290 $html .= '<div id="pano' . $id . '" class="pano-wrap vrfullwidth" style=" text-align:center; height: ' . $height . '; direction:ltr;" >';
1291 }
1292 }
1293 } elseif ($width == 'embed') {
1294 $html .= '<div id="pano' . $id . '" class="pano-wrap vrembed" style=" text-align:center; direction:ltr;" >';
1295 } else {
1296 if (wpvr_isMobileDevice()) {
1297 if ($radius) {
1298 $html .= '<div id="pano' . $id . '" class="pano-wrap" style=" text-align:center; max-width:100%; width: ' . $width . '; height: ' . $mobile_height . '!important; margin: 0 auto; border-radius:' . $radius . '; direction:ltr;">';
1299 } else {
1300 $html .= '<div id="pano' . $id . '" class="pano-wrap" style=" text-align:center; max-width:100%; width: ' . $width . '; height: ' . $mobile_height . '!important; margin: 0 auto; direction:ltr;">';
1301 }
1302 } else {
1303 if ($radius) {
1304 $html .= '<div id="pano' . $id . '" class="pano-wrap" style=" text-align:center; max-width:100%; width: ' . $width . '; height: ' . $height . '; margin: 0 auto; border-radius:' . $radius . '; direction:ltr;">';
1305 } else {
1306 $html .= '<div id="pano' . $id . '" class="pano-wrap" style=" text-align:center; max-width:100%; width: ' . $width . '; height: ' . $height . '; margin: 0 auto; direction:ltr;">';
1307 }
1308 }
1309 }
1310 return $html;
1311 }
1312
1313
1314 /**
1315 * Render hotspot contents inside pano wrapper
1316 *
1317 * @param string $html
1318 * @param mixed $id
1319 * @param array $scene_data
1320 *
1321 * @return string
1322 * @since 8.0.0
1323 */
1324 private function render_shortcode_hotspot_content($html, $id, $scene_data)
1325 {
1326 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
1327 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
1328 $html .= '<div class="wpvr-hotspot-tweak-contents-flex">';
1329 $html .= '<div class="wpvr-hotspot-tweak-contents">';
1330 ob_start();
1331 do_action('wpvr_hotspot_tweak_contents', $scene_data);
1332 $hotspot_content = ob_get_clean();
1333 $html .= $hotspot_content;
1334 $html .= '</div>';
1335 $html .= '</div>';
1336 $html .= '</div>';
1337 return $html;
1338 }
1339
1340
1341 /**
1342 * Render custom iframe wrapper inside pano wrapper
1343 *
1344 * @param string $html
1345 * @param mixed $id
1346 *
1347 * @return string
1348 * @since 8.0.0
1349 */
1350 private function render_shortcode_custom_iframe_wrapper($html, $id)
1351 {
1352 $html .= '<div class="custom-ifram-wrapper" style="display: none;">';
1353 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
1354
1355 $html .= '<div class="custom-ifram-flex">';
1356 $html .= '<div class="custom-ifram">';
1357 $html .= '</div>';
1358 $html .= '</div>';
1359 $html .= '</div>';
1360 return $html;
1361 }
1362
1363
1364 /**
1365 * Return scripts contents for shortcode
1366 *
1367 * @param string $html
1368 * @param mixed $response
1369 * @param mixed $id
1370 * @param mixed $autoload
1371 * @param mixed $default_scene
1372 * @param mixed $postdata
1373 *
1374 * @return string
1375 * @since 8.0.0
1376 */
1377 private function get_shortcode_script_content($html, $response, $id, $autoload, $default_scene, $postdata)
1378 {
1379 $html .= '<script>';
1380 $html .= 'jQuery(document).ready(function() {';
1381 $html .= 'var response = ' . $response . ';';
1382 $html .= 'var scenes = response[1];';
1383 // Hotspot scripts content //
1384 $html = $this->get_shortcode_hotspot_script_content($html);
1385
1386 $html .= 'var panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);';
1387
1388 // Panaromic show scripts content //
1389 $html = $this->render_shortcode_panoshow_script_content($html, $id);
1390 // Auto rotation scripts content //
1391 $html = $this->render_shortcode_autoRotate_content($html, $id);
1392
1393 $html .= 'var touchtime = 0;';
1394
1395 // Return autoload scripts content //
1396 if (!$autoload) {
1397 $html = $this->render_shortcode_autoload_content($html, $id);
1398 }
1399
1400 // JQuery scripts for on-click content for elementor tab //
1401 $previeword = "Click to Load Panorama";
1402 if (isset($postdata['previewtext']) && $postdata['previewtext'] != '') {
1403 $previeword = $postdata['previewtext'];
1404 }
1405 $html = $this->render_elementor_tab_title_click_content($html, $id, $default_scene, $previeword);
1406 // JQuery scripts for on-click content for vr tour tab //
1407 $html = $this->render_vr_tour_tab_click_content($html, $id, $default_scene);
1408
1409 if (isset($previeword ) && $previeword != '') {
1410 $html .= 'jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")';
1411 }
1412
1413 $html .= '});';
1414 $html .= '</script>';
1415 return $html;
1416 }
1417
1418
1419 /**
1420 * Return scripts content for hotspot data on shortcode
1421 *
1422 * @param mixed $html
1423 *
1424 * @return string
1425 * @since 8.0.0
1426 */
1427 private function get_shortcode_hotspot_script_content($html)
1428 {
1429 $html .= 'if(scenes) {';
1430 $html .= 'var scenedata = scenes.scenes;';
1431 $html .= 'for(var i in scenedata) {';
1432 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
1433 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
1434 $html .= 'if(scenehotspot[i]["clickHandlerArgs"] != "") {';
1435 $html .= 'scenehotspot[i]["clickHandlerFunc"] = wpvrhotspot;';
1436 $html .= '}';
1437 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
1438 } else {
1439 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
1440 $html .= 'scenehotspot[i]["createTooltipFunc"] = wpvrtooltip;';
1441 $html .= '}';
1442 }
1443 $html .= '}';
1444 $html .= '}';
1445 $html .= '}';
1446 return $html;
1447 }
1448
1449
1450 /**
1451 * Render scripts content for panaromic show on shortcode
1452 *
1453 * @param mixed $html
1454 * @param mixed $id
1455 *
1456 * @return string
1457 * @since 8.0.0
1458 */
1459 private function render_shortcode_panoshow_script_content($html, $id)
1460 {
1461 $html .= 'panoshow' . $id . '.on("load", function (){
1462 setTimeout(() => {
1463 window.dispatchEvent(new Event("resize"));
1464 }, 200);
1465 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
1466 jQuery("#controls' . $id . '").css("bottom", "55px");
1467 }
1468 else {
1469 jQuery("#controls' . $id . '").css("bottom", "5px");
1470 }
1471 });';
1472 $html .= 'panoshow' . $id . '.on("render", function (){
1473 window.dispatchEvent(new Event("resize"));
1474 });';
1475 return $html;
1476 }
1477
1478
1479 /**
1480 * Return auto rotation scripts content on shortcode
1481 *
1482 * @param mixed $html
1483 * @param mixed $id
1484 *
1485 * @return string
1486 * @since 8.0.0
1487 */
1488 private function render_shortcode_autoRotate_content($html, $id)
1489 {
1490 $html .= 'if (scenes.autoRotate) {
1491 panoshow' . $id . '.on("load", function (){
1492 setTimeout(function(){ panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0); }, 3000);
1493 });
1494 panoshow' . $id . '.on("scenechange", function (){
1495 setTimeout(function(){ panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0); }, 3000);
1496 });
1497 }';
1498 return $html;
1499 }
1500
1501
1502 /**
1503 * Return autoload scripts content on shortcode
1504 *
1505 * @param mixed $html
1506 * @param mixed $id
1507 *
1508 * @return string
1509 * @since 8.0.0
1510 */
1511 private function render_shortcode_autoload_content($html, $id)
1512 {
1513 $html .= 'jQuery(document).ready(function(){
1514 jQuery("#controls' . $id . '").hide();
1515 jQuery("#zoom-in-out-controls' . $id . '").hide();
1516 jQuery("#adcontrol' . $id . '").hide();
1517 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").hide();
1518 });';
1519
1520 $html .= 'panoshow' . $id . '.on("load", function (){
1521 jQuery("#controls' . $id . '").show();
1522 jQuery("#zoom-in-out-controls' . $id . '").show();
1523 jQuery("#adcontrol' . $id . '").show();
1524 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").show();
1525 });';
1526 return $html;
1527 }
1528
1529
1530 /**
1531 * JQuery scripts for on-click content for elementor tab
1532 *
1533 * @param mixed $html
1534 * @param mixed $id
1535 * @param mixed $default_scene
1536 *
1537 * @return string
1538 * @since 8.0.0
1539 */
1540 private function render_elementor_tab_title_click_content($html, $id, $default_scene, $previeword)
1541 {
1542 $html .= 'jQuery(".elementor-tab-title").click(function(){
1543 var element_id;
1544 var pano_id;
1545 var element_id = this.id;
1546 element_id = element_id.split("-");
1547 element_id = element_id[3];
1548 jQuery("#elementor-tab-content-"+element_id).children("div").addClass("awwww");
1549 var pano_id = jQuery(".awwww").attr("id");
1550 jQuery("#elementor-tab-content-"+element_id).children("div").removeClass("awwww");
1551 if (pano_id != undefined) {
1552 pano_id = pano_id.split("o");
1553 pano_id = pano_id[1];
1554 if (pano_id == "' . $id . '") {
1555 jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
1556 jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
1557 panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
1558 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
1559 setTimeout(function() {
1560 // panoshow' . $id . '.loadScene("' . $default_scene . '");
1561 window.dispatchEvent(new Event("resize"));
1562 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
1563 jQuery("#controls' . $id . '").css("bottom", "55px");
1564 }
1565 else {
1566 jQuery("#controls' . $id . '").css("bottom", "5px");
1567 }
1568 }, 200);
1569 }
1570 }
1571 });';
1572 return $html;
1573 }
1574
1575
1576 /**
1577 * JQuery scripts for on-click content for vr tour tab
1578 *
1579 * @param mixed $html
1580 * @param mixed $id
1581 * @param mixed $default_scene
1582 *
1583 * @return string
1584 * @since 8.0.0
1585 */
1586 private function render_vr_tour_tab_click_content($html, $id, $default_scene)
1587 {
1588 $html .= 'jQuery(".geodir-tab-head dd, #vr-tour-tab").click(function(){
1589 jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
1590 jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
1591 panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
1592 setTimeout(function() {
1593 panoshow' . $id . '.loadScene("' . $default_scene . '");
1594 window.dispatchEvent(new Event("resize"));
1595 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
1596 jQuery("#controls' . $id . '").css("bottom", "55px");
1597 }
1598 else {
1599 jQuery("#controls' . $id . '").css("bottom", "5px");
1600 }
1601 }, 200);
1602 });';
1603 return $html;
1604 }
1605 }
1606