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

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

4,411 lines 204.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Legacy bootstrap for WP VR plugin
3 // This file is a direct copy of the original wpvr.php before architecture migration.
4 // Do not edit legacy logic here; only update if the legacy code itself changes.
5
6 if (!defined('WPINC')) {
7 die;
8 }
9
10 require WPVR_PLUGIN_LEGACY_DIR_PATH . 'elementor/elementor.php';
11 if ( file_exists( dirname( WPVR_PLUGIN_LEGACY_DIR_PATH ) . '/vendor/autoload.php' ) ) {
12 require_once dirname( WPVR_PLUGIN_LEGACY_DIR_PATH ) . '/vendor/autoload.php';
13 } elseif ( file_exists( WPVR_PLUGIN_LEGACY_DIR_PATH . 'vendor/autoload.php' ) ) {
14 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'vendor/autoload.php';
15 }
16
17 if ( wp_get_theme('bricks')->exists() && 'bricks' === get_template()) {
18 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'bricks/bricks.php';
19 }
20
21
22 /**
23 * Currently plugin version.
24 * Start at version 1.0.0 and use SemVer - https://semver.org
25 * Rename this for your plugin and update it as you release new versions.
26 */
27 define( 'WPVR_WEBHOOK_URL', sanitize_url( 'https://rextheme.com/?mailmint=1&route=webhook&topic=contact&hash=bbd19901-6d42-4ae5-a7a8-01eb1013c553' ) );
28 if ( ! defined( 'WPVR_TELEMETRY_API_KEY' ) ) {
29 define( 'WPVR_TELEMETRY_API_KEY', 'phc_amk3VQz1P5ZqZOMRRoWM1B41QMFpf3hu8pg7yRfzSXW' );
30 }
31 if ( ! defined( 'WPVR_TELEMETRY_API_SECRET' ) ) {
32 define( 'WPVR_TELEMETRY_API_SECRET', 'sec_dfb2ab8e84391ae7a0f9' );
33 }
34 if ( ! defined( 'WPVR_TELEMETRY_HOST' ) ) {
35 define( 'WPVR_TELEMETRY_HOST', 'https://eu.i.posthog.com' );
36 }
37
38
39 if ( ! function_exists( 'activate_wpvr' ) ) {
40 /**
41 * The code that runs during plugin activation.
42 * This action is documented in includes/class-wpvr-activator.php
43 */
44 function activate_wpvr()
45 {
46 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'includes/class-wpvr-activator.php';
47 Wpvr_Activator::activate();
48
49 // Trigger plugin activation tracking
50 do_action( 'wpvr_plugin_activated' );
51 }
52 }
53
54 if ( ! function_exists( 'deactivate_wpvr' ) ) {
55 /**
56 * The code that runs during plugin deactivation.
57 * This action is documented in includes/class-wpvr-deactivator.php
58 */
59 function deactivate_wpvr()
60 {
61 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'includes/class-wpvr-deactivator.php';
62 Wpvr_Deactivator::deactivate();
63
64 // Trigger plugin deactivation tracking
65 do_action( 'wpvr_plugin_deactivated' );
66 }
67 }
68
69 register_activation_hook( WPVR_FILE, 'activate_wpvr' );
70 register_deactivation_hook( WPVR_FILE, 'deactivate_wpvr' );
71
72 /**
73 * The core plugin class that is used to define internationalization,
74 * admin-specific hooks, and public-facing site hooks.
75 */
76 require WPVR_PLUGIN_LEGACY_DIR_PATH . 'includes/class-wpvr.php';
77
78 // Include banner classes
79 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/classes/class-wpvr-occasion-banner.php';
80 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/classes/class-wpvr-sells-notification-bar.php';
81 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/classes/class-wpvr-first-tour-banner.php';
82 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/classes/class-wpvr-onboarding-notice.php';
83 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'admin/classes/class-wpvr-new-user-tour.php';
84
85 if ( defined( 'WPB_VC_VERSION' ) ) {
86 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'builders/wpbakery/wpvr-loader.php';
87 if ( class_exists( 'Vc_Manager' ) ) {
88 require_once WPVR_PLUGIN_LEGACY_DIR_PATH . 'builders/wpbakery/wpvr-element.php';
89 }
90 }
91
92
93 /**
94 * Begins execution of the plugin.
95 *
96 * Since everything within the plugin is registered via hooks,
97 * then kicking off the plugin from this point in the file does
98 * not affect the page life cycle.
99 *
100 * @since 7.3.6
101 */
102 function run_wpvr()
103 {
104
105 $plugin = new Wpvr();
106 $plugin->run();
107 // new Tracker();
108
109 // black friday banner class initialization
110 // new WPVR_Special_Occasion_Banner(
111 // 'halloween_deal_2025',
112 // '2025-10-01 00:00:01',
113 // '2025-11-05 23:59:59'
114 // );
115
116 if (!defined('WPVR_PRO_VERSION') && 'no' === get_option('wpvr_sell_eid_ul_fitr_2026_notification_bar', 'no')) {
117 new WPVR_Notification_Bar(
118 'Eid_Ul_Fitr_2026',
119 '2026-03-16 00:00:00',
120 '2026-03-24 23:59:59'
121 );
122 }
123
124 // Initialize first tour banner
125 new WPVR_First_Tour_Banner();
126
127 // Initialize listing-page onboarding notice ("Remind me later" flow)
128 new WPVR_Onboarding_Notice();
129
130 // Auto-launch guided tour for truly-new users on the Add New Tour page.
131 new WPVR_New_User_Tour();
132
133 // Pro preview banner (shown via JS when free user toggles Advanced Controls)
134 if (!defined('WPVR_PRO_VERSION')) {
135 add_action('admin_notices', 'wpvr_render_pro_preview_banner', 11);
136 }
137
138 }
139 run_wpvr();
140
141 /**
142 * Render Pro preview banner as admin notice.
143 * Hidden by default; shown via JS when free user toggles Advanced Controls.
144 *
145 * @since 8.5.44
146 */
147 function wpvr_render_pro_preview_banner() {
148 $screen = get_current_screen();
149 if (!$screen || $screen->id !== 'wpvr_item') {
150 return;
151 }
152 ?>
153 <div class="wpvr-pro-preview-banner" id="wpvr-pro-preview-banner" style="display:none;">
154 <div class="wpvr-pro-preview-banner__left">
155 <span class="wpvr-pro-preview-banner__icon">
156 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M12 4.5C7 4.5 2.73 7.61 1 12c1.73 4.39 6 7.5 11 7.5s9.27-3.11 11-7.5c-1.73-4.39-6-7.5-11-7.5zm0 12.5c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5zm0-8c-1.66 0-3 1.34-3 3s1.34 3 3 3 3-1.34 3-3-1.34-3-3-3z"/></svg>
157 </span>
158 <span class="wpvr-pro-preview-banner__text"><?php esc_html_e('You are previewing Pro features in action.', 'wpvr'); ?></span>
159 </div>
160 <div class="wpvr-pro-preview-banner__pricing">
161 <div class="wpvr-pro-preview-banner__pricing-top">
162 <span class="wpvr-pro-preview-banner__old-price"><?php esc_html_e('Normally $99.99/year', 'wpvr'); ?></span>
163 <span class="wpvr-pro-preview-banner__badge"><?php esc_html_e('SAVE 20%', 'wpvr'); ?></span>
164 </div>
165 <span class="wpvr-pro-preview-banner__new-price"><?php esc_html_e('Starting at $79.99/year', 'wpvr'); ?></span>
166 </div>
167 <a href="<?php echo esc_url('https://rextheme.com/wpvr/wpvr-pricing/?utm_source=plugin&utm_medium=pro-preview-banner&utm_campaign=advanced-controls'); ?>" class="wpvr-pro-preview-banner__btn" target="_blank" rel="noopener noreferrer">
168 <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="currentColor" stroke="none"><path d="M5 16L3 5l5.5 5L12 4l3.5 6L21 5l-2 11H5zm0 2h14v1c0 .55-.45 1-1 1H6c-.55 0-1-.45-1-1v-1z"/></svg>
169 <?php esc_html_e('Upgrade to save changes', 'wpvr'); ?>
170 </a>
171 </div>
172 <?php
173 }
174
175
176 /**
177 * Array information checker
178 *
179 * @param mixed $needle
180 * @param mixed $haystack
181 * @param bool $strict
182 *
183 * @return bool
184 * @since 7.3.6
185 */
186 function wpvr_in_array_r($needle, $haystack, $strict = false)
187 {
188 foreach ($haystack as $item) {
189 if ((($strict ? $item === $needle : $item == $needle)) || is_array($item) && wpvr_in_array_r($needle, $item, $strict)) {
190 return true;
191 }
192 }
193 return false;
194 }
195
196 if ( ! function_exists( 'wpvr_parse_custom_control' ) ) {
197 /**
198 * Normalize custom control data into an array.
199 *
200 * @param mixed $custom_control Raw custom control value from meta.
201 *
202 * @return array
203 * @since 8.5.63
204 */
205 function wpvr_parse_custom_control( $custom_control ) {
206 if ( is_array( $custom_control ) ) {
207 return $custom_control;
208 }
209
210 if ( is_object( $custom_control ) ) {
211 return (array) $custom_control;
212 }
213
214 if ( ! is_string( $custom_control ) || '' === trim( $custom_control ) ) {
215 return array();
216 }
217
218 $unserialized = maybe_unserialize( $custom_control );
219 if ( is_array( $unserialized ) ) {
220 return $unserialized;
221 }
222
223 $decoded = json_decode( wp_unslash( $custom_control ), true );
224 if ( is_array( $decoded ) ) {
225 return $decoded;
226 }
227
228 return array();
229 }
230 }
231
232 if ( ! function_exists( 'wpvr_restore_modern_layout_default_controls' ) ) {
233 /**
234 * Restore Pannellum's default controls after WP VR Pro adds Modern layout CSS.
235 *
236 * The Modern layout stylesheet is added by WP VR Pro at filter priority 10.
237 * Running at priority 20 keeps this compatibility rule in the Free plugin while
238 * ensuring it is output after the Pro stylesheet, regardless of plugin load order.
239 *
240 * @param string $html Generated tour HTML.
241 * @param array $postdata Saved tour settings.
242 * @param int $id Tour post ID.
243 *
244 * @return string
245 * @since 9.0.0
246 */
247 function wpvr_restore_modern_layout_default_controls( $html, $postdata, $id ) {
248 $tour_layout = is_array( $postdata['tourLayout'] ?? null )
249 ? ( $postdata['tourLayout']['layout'] ?? 'default' )
250 : ( $postdata['tourLayout'] ?? 'default' );
251
252 if (
253 ! defined( 'WPVR_PRO_VERSION' )
254 || 'layout1' !== $tour_layout
255 || empty( $postdata['showControls'] )
256 ) {
257 return $html;
258 }
259
260 $custom_control = wp_parse_args(
261 wpvr_parse_custom_control( $postdata['customcontrol'] ?? array() ),
262 array(
263 'panupSwitch' => 'off',
264 'panDownSwitch' => 'off',
265 'panLeftSwitch' => 'off',
266 'panRightSwitch' => 'off',
267 'panZoomInSwitch' => 'off',
268 'panZoomOutSwitch' => 'off',
269 'panFullscreenSwitch' => 'off',
270 'gyroscopeSwitch' => 'off',
271 'backToHomeSwitch' => 'off',
272 )
273 );
274
275 $gyro_enabled = isset( $postdata['gyro'] )
276 && in_array( $postdata['gyro'], array( true, 1, '1', 'on' ), true );
277 $gyro_button_enabled = function_exists( 'wpvr_isMobileDevice' )
278 && wpvr_isMobileDevice()
279 && $gyro_enabled
280 && 'on' === $custom_control['gyroscopeSwitch'];
281
282 $custom_navigation_enabled = $gyro_button_enabled;
283 foreach (
284 array(
285 'panupSwitch',
286 'panDownSwitch',
287 'panLeftSwitch',
288 'panRightSwitch',
289 'panZoomInSwitch',
290 'panZoomOutSwitch',
291 'panFullscreenSwitch',
292 'backToHomeSwitch',
293 ) as $switch
294 ) {
295 if ( 'on' === $custom_control[ $switch ] ) {
296 $custom_navigation_enabled = true;
297 break;
298 }
299 }
300
301 if ( $custom_navigation_enabled ) {
302 return $html;
303 }
304
305 $pano_id = 'pano' . absint( $id );
306 $sprites_url = esc_url( WPVR_PLUGIN_PUBLIC_DIR_URL . 'lib/pannellum/src/css/img/sprites.svg' );
307
308 $html .= '<style id="wpvr-modern-default-controls-' . esc_attr( $id ) . '">
309 #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-zoom-controls.pnlm-controls {
310 display: block !important;
311 width: 28px !important;
312 height: 52px !important;
313 right: auto !important;
314 bottom: auto !important;
315 margin-top: 4px !important;
316 border: 1px solid rgba(0, 0, 0, 0.4) !important;
317 border-radius: 3px !important;
318 background-color: #fff !important;
319 background-image: none !important;
320 background-position: 0 0 !important;
321 background-repeat: repeat !important;
322 background-size: auto !important;
323 }
324
325 #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-fullscreen-toggle-button {
326 display: block !important;
327 width: 28px !important;
328 height: 26px !important;
329 right: auto !important;
330 bottom: auto !important;
331 margin-top: 4px !important;
332 border: 1px solid rgba(0, 0, 0, 0.4) !important;
333 border-radius: 3px !important;
334 background-color: #fff !important;
335 background-image: url("' . $sprites_url . '") !important;
336 background-repeat: repeat !important;
337 background-size: auto !important;
338 }
339
340 #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-fullscreen-toggle-button-inactive {
341 background-position: 1px -52px !important;
342 }
343
344 #et-boc .et-l #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-fullscreen-toggle-button-inactive {
345 background-position: -1px -53px !important;
346 }
347
348 #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-fullscreen-toggle-button-active {
349 background-position: 0 -78px !important;
350 }
351
352 #' . esc_attr( $pano_id ) . ' .pnlm-controls-container .pnlm-control:hover {
353 background-color: #f8f8f8 !important;
354 }
355 </style>';
356
357 return $html;
358 }
359 }
360
361 add_filter( 'wpvr_generate_tour_layout_html', 'wpvr_restore_modern_layout_default_controls', 20, 3 );
362
363 if ( ! function_exists( 'wpvr_render_scene_info_row' ) ) {
364 /**
365 * Keep scene title and author metadata aligned for every tour layout.
366 *
367 * WP VR Pro can replace the Pannellum asset registered by the Free plugin and
368 * adds Modern layout CSS at priority 10. This late, tour-scoped layer keeps
369 * both Pannellum copies and both layouts consistent without modifying Pro.
370 *
371 * @param string $html Generated tour HTML.
372 * @param array $postdata Saved tour settings.
373 * @param int $id Tour post ID.
374 *
375 * @return string
376 * @since 9.0.0
377 */
378 function wpvr_render_scene_info_row( $html, $postdata, $id ) {
379 $pano_id = 'pano' . absint( $id );
380 $pano_id_json = wp_json_encode( $pano_id );
381 $by_label = wp_json_encode( __( 'By', 'wpvr' ) );
382 $tour_layout = is_array( $postdata['tourLayout'] ?? null )
383 ? ( $postdata['tourLayout']['layout'] ?? 'default' )
384 : ( $postdata['tourLayout'] ?? 'default' );
385 $is_classic_layout = wp_json_encode( 'layout1' !== $tour_layout );
386
387 $html .= '<style id="wpvr-scene-info-' . esc_attr( $id ) . '">
388 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row {
389 display: flex !important;
390 align-items: center !important;
391 justify-content: center !important;
392 gap: 10px !important;
393 box-sizing: border-box !important;
394 min-width: 0 !important;
395 overflow: hidden !important;
396 text-align: center !important;
397 z-index: 2147483647 !important;
398 -webkit-transform: translateZ(10000px) !important;
399 transform: translateZ(10000px) !important;
400 }
401
402 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row .pnlm-title-box {
403 flex: 0 1 auto !important;
404 min-width: 0 !important;
405 max-width: calc(70% - 5px) !important;
406 width: auto !important;
407 margin: 0 !important;
408 padding: 0 !important;
409 display: block !important;
410 overflow: hidden !important;
411 text-overflow: ellipsis !important;
412 white-space: nowrap !important;
413 }
414
415 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row .pnlm-author-box {
416 flex: 0 1 auto !important;
417 min-width: 0 !important;
418 max-width: calc(30% - 5px) !important;
419 margin: 0 !important;
420 border-left: 1px solid rgba(255, 255, 255, 0.45) !important;
421 padding: 0 0 0 10px !important;
422 display: block !important;
423 overflow: hidden !important;
424 line-height: 1.2 !important;
425 text-overflow: ellipsis !important;
426 white-space: nowrap !important;
427 }
428
429 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info .wpvr-author-label {
430 flex: none !important;
431 margin-right: 4px !important;
432 font-size: 10px !important;
433 font-weight: 700 !important;
434 letter-spacing: 0.06em !important;
435 opacity: 0.8 !important;
436 text-transform: uppercase !important;
437 }
438
439 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info .pnlm-author-box a {
440 color: inherit !important;
441 text-decoration: underline !important;
442 text-underline-offset: 2px !important;
443 }
444
445 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-has-title:not(.wpvr-has-author) .pnlm-title-box,
446 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-has-author:not(.wpvr-has-title) .pnlm-author-box {
447 max-width: 100% !important;
448 border-left: 0 !important;
449 padding-left: 0 !important;
450 }
451
452 #' . esc_attr( $pano_id ) . '.wpvr-layout-classic.wpvr-has-scene-info .scene-gallery.wpvr-gallery--classic {
453 bottom: calc(var(--wpvr-scene-info-height, 34px) + 8px) !important;
454 }
455
456 #' . esc_attr( $pano_id ) . '.wpvr-layout-classic.wpvr-has-scene-info .vrgcontrols {
457 bottom: calc(var(--wpvr-scene-info-height, 34px) + 4px) !important;
458 }
459
460 #' . esc_attr( $pano_id ) . '.wpvr-layout-classic.wpvr-has-scene-info .wpvr_slider_nav {
461 bottom: calc(var(--wpvr-scene-info-height, 34px) + 15px) !important;
462 }
463
464 #' . esc_attr( $pano_id ) . '.wpvr-layout-classic.wpvr-has-scene-info .controls {
465 bottom: calc(var(--wpvr-scene-info-height, 34px) + 6px) !important;
466 }
467
468 @media (max-width: 767px) {
469 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row {
470 gap: 7px !important;
471 padding-right: 10px !important;
472 padding-left: 10px !important;
473 }
474
475 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row .pnlm-title-box {
476 max-width: calc(65% - 4px) !important;
477 }
478
479 #' . esc_attr( $pano_id ) . ' .pnlm-panorama-info.wpvr-scene-info-row .pnlm-author-box {
480 max-width: calc(35% - 4px) !important;
481 padding-left: 7px !important;
482 }
483 }
484 </style>
485 <script id="wpvr-scene-info-script-' . esc_attr( $id ) . '">
486 (function () {
487 var pano = document.getElementById(' . $pano_id_json . ');
488 var byLabel = ' . $by_label . ';
489
490 if (!pano || !window.MutationObserver) {
491 return;
492 }
493
494 function addAuthorLabel(author) {
495 if (!author || !author.textContent.trim() || author.querySelector(".wpvr-author-label")) {
496 return;
497 }
498
499 var firstNode = author.firstChild;
500 if (firstNode && firstNode.nodeType === 3) {
501 var prefix = byLabel + " ";
502 if (firstNode.nodeValue.indexOf(prefix) === 0) {
503 firstNode.nodeValue = firstNode.nodeValue.slice(prefix.length);
504 }
505 }
506
507 var label = document.createElement("span");
508 label.className = "wpvr-author-label";
509 label.textContent = byLabel;
510 author.insertBefore(label, author.firstChild);
511 }
512
513 function syncSceneInfo() {
514 var info = pano.querySelector(".pnlm-panorama-info");
515 if (!info) {
516 return;
517 }
518
519 // Keep the Pannellum full-screen drag layer in its original
520 // stacking order so hotspots remain clickable. Promote only
521 // the compact metadata bar to the tour root instead.
522 if (info.parentNode !== pano) {
523 pano.appendChild(info);
524 }
525
526 var title = info.querySelector(".pnlm-title-box");
527 var author = info.querySelector(".pnlm-author-box");
528 var hasTitle = !!(title && title.textContent.trim());
529 var hasAuthor = !!(author && author.textContent.trim());
530
531 if (hasTitle) {
532 title.setAttribute("title", title.textContent.trim());
533 } else if (title) {
534 title.removeAttribute("title");
535 }
536
537 if (hasAuthor) {
538 addAuthorLabel(author);
539 var authorName = author.textContent.replace(byLabel, "").trim();
540 author.setAttribute("aria-label", byLabel + " " + authorName);
541 author.setAttribute("title", authorName);
542 } else if (author) {
543 author.removeAttribute("aria-label");
544 author.removeAttribute("title");
545 }
546
547 info.classList.toggle("wpvr-scene-info-row", hasTitle || hasAuthor);
548 info.classList.toggle("wpvr-has-title", hasTitle);
549 info.classList.toggle("wpvr-has-author", hasAuthor);
550 info.style.display = hasTitle || hasAuthor ? "flex" : "none";
551
552 var hasSceneInfo = hasTitle || hasAuthor;
553 var isClassicLayout = ' . $is_classic_layout . ';
554 pano.classList.toggle("wpvr-has-scene-info", hasSceneInfo);
555 pano.classList.toggle("wpvr-layout-classic", isClassicLayout);
556
557 if (hasSceneInfo) {
558 pano.style.setProperty("--wpvr-scene-info-height", info.offsetHeight + "px");
559 } else {
560 pano.style.removeProperty("--wpvr-scene-info-height");
561 }
562 }
563
564 var observer = new MutationObserver(syncSceneInfo);
565 observer.observe(pano, { childList: true, subtree: true, characterData: true });
566 syncSceneInfo();
567 }());
568 </script>';
569
570 return $html;
571 }
572 }
573
574 add_filter( 'wpvr_generate_tour_layout_html', 'wpvr_render_scene_info_row', 30, 3 );
575
576 if ( ! function_exists( 'wpvr_render_explainer_button' ) ) {
577 /**
578 * Render the WPVR explainer button independently.
579 *
580 * @param array|null $custom_control
581 * @param array $postdata
582 * @param bool $is_pro
583 * @param bool $autoload
584 * @param string $explainer_right
585 * @param int|string $id
586 *
587 * @return string
588 * @since 8.5.63
589 */
590 function wpvr_render_explainer_button( $custom_control, $postdata, $is_pro, $autoload, $explainer_right, $id ) {
591 $html = '';
592 $explainer_enabled = isset( $postdata['explainerSwitch'] )
593 && in_array( $postdata['explainerSwitch'], array( true, 1, '1', 'on' ), true );
594 $explainer_icon = 'fa fa-video';
595 $explainer_color = '#f7fffb';
596
597 if ( isset( $custom_control ) ) {
598 $explainer_icon = isset( $custom_control['explainerIcon'] ) ? $custom_control['explainerIcon'] : $explainer_icon;
599 $explainer_color = isset( $custom_control['explainerColor'] ) ? $custom_control['explainerColor'] : $explainer_color;
600 } elseif ( isset( $postdata['customcontrol'] ) ) {
601 $raw_control = wpvr_parse_custom_control( $postdata['customcontrol'] );
602 $explainer_icon = isset( $raw_control['explainerIcon'] ) ? $raw_control['explainerIcon'] : $explainer_icon;
603 $explainer_color = isset( $raw_control['explainerColor'] ) ? $raw_control['explainerColor'] : $explainer_color;
604 }
605
606 $pro_license_status = get_option( 'wpvr_edd_license_status' );
607 if ( $explainer_enabled && $pro_license_status === 'valid' && $is_pro ) {
608 $explainer_style = empty( $postdata['explainerContent'] )
609 ? 'pointer-events: none; opacity: 0.5;'
610 : '';
611
612 // Initial display:none to prevent flash for non-autoload tours.
613 $initial_display = ! $autoload ? 'display:none; ' : '';
614
615 $html .= '<div class="explainer_button" id="explainer_button_' . esc_attr( $id ) . '" style="' . $initial_display . 'right:' . esc_attr( $explainer_right ) . '; ' . esc_attr( $explainer_style ) . '">';
616 $html .= '<div class="ctrl" id="explainer_target_' . esc_attr( $id ) . '"><i class="' . esc_attr( $explainer_icon ) . '" style="color:' . esc_attr( $explainer_color ) . ';"></i></div>';
617 $html .= '</div>';
618 }
619
620 return $html;
621 }
622 }
623
624 // Linno telemetry integration
625 function wpvr_block()
626 {
627 wp_register_script(
628 'wpvr-block',
629 plugins_url('build/index.build.js', __FILE__),
630 array('wp-blocks', 'wp-element', 'wp-components', 'wp-editor')
631 );
632
633 if (is_admin()) {
634 wp_enqueue_style(
635 'gutyblocks/guty-block',
636 plugins_url('src/view.css', __FILE__),
637 array()
638 );
639 }
640
641
642 if (function_exists('register_block_type')) {
643 register_block_type('wpvr/wpvr-block', array(
644 'attributes' => array(
645 'id' => array(
646 'type' => 'string',
647 'default' => '0',
648 ),
649 'width' => array(
650 'type' => 'string',
651 'default' => '600',
652 ),
653 'width_unit' => array(
654 'type' => 'string',
655 'default' => 'px',
656 ),
657 'height' => array(
658 'type' => 'string',
659 'default' => '400',
660 ),
661 'height_unit' => array(
662 'type' => 'string',
663 'default' => 'px',
664 ),
665 'mobile_height' => array(
666 'type' => 'string',
667 'default' => '300',
668 ),
669 'mobile_height_unit' => array(
670 'type' => 'string',
671 'default' => 'px',
672 ),
673 'radius' => array(
674 'type' => 'string',
675 'default' => '0',
676 ),
677 'border_width' => array(
678 'type' => 'string',
679 'default' => '0px',
680 ),
681 'border_style' => array(
682 'type' => 'string',
683 'default' => 'none',
684 ),
685 'border_color' => array(
686 'type' => 'string',
687 'default' => 'none',
688 ),
689 'radius_unit' => array(
690 'type' => 'string',
691 'default' => 'px',
692 ),
693 'content' => array(
694 'type' => 'string',
695 'source' => 'html',
696 'default' => '<script> </script>'
697 ),
698 ),
699 'editor_script' => 'wpvr-block',
700 'render_callback' => 'wpvr_block_render',
701 ));
702 }
703 }
704
705 add_action('init', 'wpvr_block');
706
707 function wpvr_block_render($attributes)
708 {
709 if ( function_exists( 'wpvr_enqueue_frontend_scripts' ) ) {
710 wpvr_enqueue_frontend_scripts( 'scene' );
711 }
712 if (isset($attributes['id'])) {
713 $id = $attributes['id'];
714 } else {
715 $id = 0;
716 }
717
718 do_action('rex_wpvr_embadded_tour', $id);
719
720 $memberpress_active = defined('MEPR_VERSION');
721 $rcp_active = is_plugin_active( 'restrict-content-pro/restrict-content-pro.php' );
722
723 if (($memberpress_active || $rcp_active ) && apply_filters('is_wpvr_pro_active', false)) {
724
725 if (!is_user_logged_in()) {
726 return esc_html__('You need to log in to access this content.', 'wpvr');
727 }
728
729 $user_id = get_current_user_id();
730 $allowed_access = false;
731
732 // Get saved membership levels from post meta
733 $allowed_membership_levels = get_post_meta($id, '_wpvr_allowed_roles_levels', true);
734 if ( isset($allowed_membership_levels) && 'none' !== $allowed_membership_levels ) {
735 if (!is_array($allowed_membership_levels)) {
736 $allowed_membership_levels = array($allowed_membership_levels);
737 }
738
739 // Check MemberPress Access
740 if ($memberpress_active) {
741 $user = new MeprUser($user_id);
742 $active_memberships = $user->active_product_subscriptions();
743 if (array_intersect($allowed_membership_levels, $active_memberships) ) {
744 $allowed_access = true;
745 }
746 }
747
748 // Check Restrict Content Pro Access
749 if ($rcp_active) {
750 $user_rcp_memberships = rcp_get_customer_memberships($user_id);
751 foreach ($user_rcp_memberships as $membership) {
752 $rcp_access_level = array(
753 $membership->get_object_id()
754 );
755 if (array_intersect($allowed_membership_levels, $rcp_access_level) ) {
756 $allowed_access = true;
757 break;
758 }
759 }
760 }
761 } else {
762 // If no membership restriction is set, allow access by default
763 $allowed_access = true;
764 }
765
766 if (!$allowed_access) {
767 return esc_html__('You do not have access to this content.', 'wpvr');
768 }
769 }
770
771
772 if (isset($attributes['width'])) {
773 $width = $attributes['width'];
774 }
775 if (isset($attributes['width_unit'])) {
776 $width_unit = $attributes['width_unit'];
777 }
778 if (isset($attributes['height'])) {
779 $height = $attributes['height'];
780 }
781 if (isset($attributes['height_unit'])) {
782 $height_unit = $attributes['height_unit'];
783 }
784 if (isset($attributes['mobile_height'])) {
785 $mobile_height = $attributes['mobile_height'];
786 }
787 if (isset($attributes['mobile_height_unit'])) {
788 $mobile_height_unit = $attributes['mobile_height_unit'];
789 }
790 if (isset($attributes['radius']) && isset($attributes['radius_unit'])) {
791 $radius = $attributes['radius'] . $attributes['radius_unit'];
792 }
793 $border_style = '';
794 if (isset($attributes['border_width'], $attributes['border_style'], $attributes['border_color'])) {
795 $border_style = $attributes['border_width'] . 'px ' . $attributes['border_style'] . ' ' . $attributes['border_color'];
796 }
797
798 if (isset($attributes['className'])) {
799 $className = $attributes['className'];
800 } else {
801 $className = '';
802 }
803 $get_post = get_post_status($id);
804 if ($get_post !== 'publish') {
805 return esc_html__('Oops! It seems like this post isn\'t published yet. Stay tuned for updates!', 'wpvr');
806 }
807 if (post_password_required($id)) {
808 return get_the_password_form();
809 }
810 $postdata = get_post_meta($id, 'panodata', true);
811 $postdata = is_array( $postdata ) ? wpvr_get_effective_panodata( $postdata ) : [];
812 $panoid = 'pano' . $id;
813 $panoid2 = 'pano2' . $id;
814 if (!isset($postdata) || empty($postdata)) {
815 return wp_kses(
816 __('Oops! It seems that you have not selected any tour yet. Please select a tour from the dropdown of WPVR block.<br>', 'wpvr'),
817 ['br' => []]
818 );
819 }
820 if (isset($postdata['streetviewdata'])) {
821 if (empty($width)) {
822 $width = '600px';
823 }
824 if (empty($height)) {
825 $height = '400px';
826 }
827 $streetviewurl = $postdata['streetviewurl'];
828 $html = '';
829 $html .= '<div class="vr-streetview ' . esc_attr( $className ) . '" style="text-align: center; max-width:100%; width:' . esc_attr( $width ) . esc_attr( $width_unit ) . '; height:' . esc_attr( $height ) . esc_attr( $height_unit ) . '; margin: 0 auto;">';
830 $html .= '<iframe src="' . esc_url( $streetviewurl ) . '" frameborder="0" style="border:0; width:100px; height:100%;" allowfullscreen=""></iframe>';
831 $html .= '</div>';
832
833 return $html;
834 }
835 $is_pro = apply_filters('is_wpvr_pro_active', false);
836
837 if (isset($postdata['vidid'])) {
838 if (empty($width)) {
839 $width = '600';
840 }
841 if (empty($height)) {
842 $height = '400';
843 }
844 $videourl = $postdata['vidurl'];
845
846 $videourl = $postdata['vidurl'];
847 $autoplay = 'off';
848 if (isset($postdata['autoplay'])) {
849 $autoplay = $postdata['autoplay'];
850 }
851 $loop = 'off';
852 if (isset($postdata['loop'])) {
853 $loop = $postdata['loop'];
854 }
855
856 if (strpos($videourl, 'youtube') > 0 || strpos($videourl, 'youtu') > 0) {
857 $explodeid = '';
858 $explodeid = explode("=", $videourl);
859 $foundid = '';
860 $muted = '&mute=1';
861
862 if ($autoplay == 'on') {
863 $autoplay = '&autoplay=1';
864 } else {
865 $autoplay = '';
866 }
867
868 if ($loop == 'on') {
869 $loop = '&loop=1';
870 } else {
871 $loop = '';
872 }
873
874 if (strpos($videourl, 'youtu') > 0) {
875 $explodeid = explode("/", $videourl);
876 $foundid = $explodeid[3] . '?' . $autoplay . $loop;
877 $expdata = $explodeid[3];
878 } else {
879 $foundid = $explodeid[1] . '?' . $autoplay . $loop;
880 $expdata = $explodeid[1];
881 }
882
883 $playlist = '&playlist=' . $expdata;
884 $playlist = str_replace("?feature=shared", "", $playlist);
885
886
887 $html = '';
888 $html .= '<div class="' . esc_attr($className) . '" style="text-align:center; max-width:100%; width:' . esc_attr($width) . esc_attr($width_unit) . '; height:' . esc_attr($height) . esc_attr($height_unit) . '; border-radius: ' . esc_attr($radius) . '; margin: 0 auto;">';
889
890 // Compatibility check script
891 $html .= '<script>
892 function wpvr_check_360_support() {
893 var support = {
894 supported: false,
895 fullySupported: false,
896 webgl: false,
897 orientation: false,
898 gyroscope: false,
899 touch: false,
900 browser: "unknown",
901 isMobile: false,
902 isIPhone: false,
903 details: []
904 };
905
906 support.isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
907 support.isIPhone = /iPhone/i.test(navigator.userAgent);
908 if (support.isMobile) support.details.push("Mobile device detected");
909 if (support.isIPhone) support.details.push("iPhone detected");
910
911 var ua = navigator.userAgent;
912 if (/^((?!chrome|android).)*safari/i.test(ua)) {
913 support.browser = "safari";
914 support.details.push("Safari browser detected");
915 } else if (ua.indexOf("Chrome") > -1) {
916 support.browser = "chrome";
917 support.details.push("Chrome browser detected");
918 } else if (ua.indexOf("Firefox") > -1) {
919 support.browser = "firefox";
920 support.details.push("Firefox browser detected");
921 } else if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) {
922 support.browser = "ie";
923 support.details.push("Internet Explorer detected");
924 } else if (ua.indexOf("Edge") > -1 || ua.indexOf("Edg") > -1) {
925 support.browser = "edge";
926 support.details.push("Edge browser detected");
927 } else if (ua.indexOf("Opera") > -1 || ua.indexOf("OPR") > -1) {
928 support.browser = "opera";
929 support.details.push("Opera browser detected");
930 }
931
932 try {
933 var canvas = document.createElement("canvas");
934 support.webgl = !!(window.WebGLRenderingContext &&
935 (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
936 support.details.push(support.webgl ? "WebGL supported" : "WebGL not supported");
937 } catch (e) {
938 support.webgl = false;
939 support.details.push("WebGL detection error: " + e.message);
940 }
941
942 support.orientation = !!(window.DeviceOrientationEvent);
943 support.details.push(support.orientation ? "Device Orientation API supported" : "Device Orientation API not supported");
944
945 support.gyroscope = !!window.Gyroscope;
946 support.details.push(support.gyroscope ? "Gyroscope supported" : "Gyroscope not supported");
947
948 support.touch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
949 support.details.push(support.touch ? "Touch supported" : "Touch not supported");
950
951 support.supported = support.webgl;
952 support.fullySupported = support.webgl && ((support.isMobile && support.orientation) || !support.isMobile);
953
954 if (support.browser === "safari" && support.isIPhone) {
955 support.browserWarning = "iPhone has limited support for 360 videos in browser. The experience may not be optimal.";
956 support.fullySupported = false;
957 } else if (support.browser === "ie") {
958 support.browserWarning = "Internet Explorer has limited support for 360 videos.";
959 support.fullySupported = false;
960 } else if (!support.supported) {
961 support.browserWarning = "Your browser does not support 360° videos. Use Chrome or Firefox with WebGL.";
962 }
963
964 return support;
965 }
966 </script>';
967
968 $random_id = 'video-container-' . rand(10000, 99999);
969 $html .= '<div id="' . $random_id . '-container" style="position:relative; width:100%; height:100%;">';
970
971 // Compatibility check screen (initially hidden for all, will show only for iPhone)
972 $html .= '<div id="' . $random_id . '-compatibility-check" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:#f9f9f9; border-radius:' . esc_attr( $radius ) . ';">
973 <div style="margin-bottom:20px; text-align:center;">
974 <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>
975 <p style="margin:0;">Checking browser compatibility...</p>
976 </div>
977 </div>';
978
979 // Spinner animation
980 $html .= '<style>@keyframes wpvr-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>';
981
982 // Iframe (initial display set to block)
983 $html .= '<div id="' . $random_id . '-frame" class="' . esc_attr($className) . '" style="display:block; max-width:100%; width:' . esc_attr($width) . esc_attr($width_unit) . '; height:' . esc_attr($height) . esc_attr($height_unit) . '; border-radius: ' . esc_attr($radius) . '; margin: 0 auto;">';
984 $html .= '<iframe id="' . $random_id . '-iframe" src="https://www.youtube.com/embed/' . rawurlencode(sanitize_text_field($expdata)) . '?rel=0&modestbranding=1' . esc_attr($loop) . '&autohide=1' . esc_attr($muted) . '&showinfo=0&controls=1' . esc_attr($autoplay) . esc_attr($playlist) . '&enablejsapi=1" width="100%" height="100%" style="border-radius: ' . esc_attr($radius) . ';" frameborder="0" allowfullscreen allow="accelerometer; gyroscope; picture-in-picture"></iframe>';
985 $html .= '</div>';
986
987 // Permission request (mobile only)
988 $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:' . esc_attr( $radius ) . ';">';
989 $html .= '<p style="font-size:16px; margin:0 20px 15px;">For the best 360° video experience on mobile</p>';
990 $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>';
991 $html .= '</div>';
992
993 // Browser warning
994 $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:' . esc_attr( $radius ) . ';">';
995 $html .= '<p id="' . $random_id . '-warning-text" style="font-size:16px; margin:0 20px 5px;"></p>';
996 $html .= '<p style="font-size:14px; margin:5px 20px 15px;">For the best experience, use Chrome or Firefox.</p>';
997 $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>';
998 $html .= '</div>';
999
1000 // Main script
1001 $html .= '<script>
1002 document.addEventListener("DOMContentLoaded", function() {
1003 var supportInfo = wpvr_check_360_support();
1004 var compatibilityCheck = document.getElementById("' . $random_id . '-compatibility-check");
1005 var frameContainer = document.getElementById("' . $random_id . '-frame");
1006 var warning = document.getElementById("' . $random_id . '-browser-warning");
1007 var warningText = document.getElementById("' . $random_id . '-warning-text");
1008 var continueBtn = document.getElementById("' . $random_id . '-browser-continue");
1009
1010 // Only show compatibility check and warning for iPhone
1011 if (supportInfo.isIPhone) {
1012 // Hide the iframe initially for iPhone
1013 frameContainer.style.display = "none";
1014
1015 // Show compatibility check for iPhone
1016 compatibilityCheck.style.display = "flex";
1017
1018 // After delay, hide compatibility check and show warning
1019 setTimeout(function() {
1020 compatibilityCheck.style.display = "none";
1021 warningText.textContent = supportInfo.browserWarning || "Your browser may not fully support 360° videos.";
1022 warning.style.display = "flex";
1023
1024 continueBtn.addEventListener("click", function() {
1025 warning.style.display = "none";
1026
1027 if (supportInfo.fullySupported && supportInfo.isMobile) {
1028 document.getElementById("' . $random_id . '-permission-request").style.display = "flex";
1029 document.getElementById("' . $random_id . '-permission-button").addEventListener("click", function() {
1030 requestDevicePermissions();
1031 });
1032 } else {
1033 showVideo();
1034 }
1035 });
1036 }, 1000);
1037 } else {
1038 // For non-iPhone devices, directly initialize the player
1039 initializeYouTubePlayer();
1040 }
1041
1042 function requestDevicePermissions() {
1043 try {
1044 if (typeof DeviceOrientationEvent !== "undefined" &&
1045 typeof DeviceOrientationEvent.requestPermission === "function") {
1046 DeviceOrientationEvent.requestPermission().then(function(response) {
1047 if (response === "granted") {
1048 if (typeof DeviceMotionEvent !== "undefined" &&
1049 typeof DeviceMotionEvent.requestPermission === "function") {
1050 DeviceMotionEvent.requestPermission().then(showVideo).catch(showVideo);
1051 } else {
1052 showVideo();
1053 }
1054 } else {
1055 showVideo();
1056 }
1057 }).catch(showVideo);
1058 } else {
1059 showVideo();
1060 }
1061 } catch (e) {
1062 showVideo();
1063 }
1064 }
1065
1066 function showVideo() {
1067 document.getElementById("' . $random_id . '-permission-request").style.display = "none";
1068 frameContainer.style.display = "block";
1069 initializeYouTubePlayer();
1070 }
1071
1072 function initializeYouTubePlayer() {
1073 if (window.YT) {
1074 initPlayer();
1075 } else {
1076 var tag = document.createElement("script");
1077 tag.src = "https://www.youtube.com/iframe_api";
1078 var firstScriptTag = document.getElementsByTagName("script")[0];
1079 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
1080 window.onYouTubeIframeAPIReady = initPlayer;
1081 }
1082
1083 function initPlayer() {
1084 new YT.Player("' . $random_id . '-iframe", {
1085 events: {
1086 "onReady": function(event) {}
1087 }
1088 });
1089 }
1090 }
1091 });
1092 </script>';
1093
1094 $html .= '</div>'; // Close container
1095 $html .= '</div>'; // Close outer wrapper
1096 } else {
1097 $html = '';
1098 $html .= '<div id="pano' . esc_attr($id) . '" class="pano-wrap ' . esc_attr($className) . '" style="max-width:100%; width:' . esc_attr($width) . esc_attr($width_unit) . '; height: ' . esc_attr($height) . esc_attr($height_unit) . '; border-radius:' . esc_attr($radius) . '; margin: 0 auto;">';
1099 $html .= '<div style="width:100%; height:100%; border-radius: ' . esc_attr($radius) . ';">' . wp_kses(
1100 $postdata['panoviddata'],
1101 array(
1102 'video' => array(
1103 'id' => array(),
1104 'class' => array(),
1105 'src' => array(),
1106 'controls' => array(),
1107 'autoplay' => array(),
1108 'loop' => array(),
1109 'muted' => array(),
1110 'poster' => array(),
1111 'preload' => array(),
1112 'width' => array(),
1113 'height' => array(),
1114 'style' => array(),
1115 'playsinline' => array(),
1116 'crossorigin' => array(),
1117 'data-*' => true,
1118 ),
1119 'source' => array(
1120 'src' => array(),
1121 'type' => array(),
1122 ),
1123 'track' => array(
1124 'kind' => array(),
1125 'src' => array(),
1126 'srclang' => array(),
1127 'label' => array(),
1128 'default' => array(),
1129 ),
1130 'div' => array(
1131 'id' => array(),
1132 'class' => array(),
1133 'style' => array(),
1134 'data-*' => true,
1135 ),
1136 'span' => array(
1137 'id' => array(),
1138 'class' => array(),
1139 'style' => array(),
1140 ),
1141 'button' => array(
1142 'id' => array(),
1143 'class' => array(),
1144 'style' => array(),
1145 'type' => array(),
1146 'title' => array(),
1147 ),
1148 )
1149 ) . '</div>';
1150
1151 $html .= '
1152 <style>
1153 .video-js {
1154 border-radius:' . esc_attr($radius) . ';
1155 }
1156 .video-js canvas{
1157 border-radius:' . esc_attr($radius) . ';
1158 }
1159 #pano' . esc_attr($id) . ' .vjs-poster {
1160 border-radius: ' . esc_attr($radius) . ';
1161 }
1162 </style>
1163
1164 ';
1165
1166 // $html .= '<script>';
1167 // $html .= 'videojs(' . $postdata['vidid'] . ', {';
1168 // $html .= 'plugins: {';
1169 // $html .= 'pannellum: {}';
1170 // $html .= '}';
1171 // $html .= '});';
1172 // $html .= '</script>';
1173 $html .= '</div>';
1174
1175 //video js vr setup //
1176 $html .= '<script>';
1177 $html .= '
1178 (function (window, videojs) {
1179 var player = window.player = videojs("' . $postdata['vidid'] . '");
1180 player.mediainfo = player.mediainfo || {};
1181 player.mediainfo.projection = "equirectangular";
1182
1183 // AUTO is the default and looks at mediainfo
1184 var vr = window.vr = player.vr({ projection: "AUTO", debug: true, forceCardboard: false, antialias: false });
1185 }(window, window.videojs));
1186
1187 ';
1188 $html .= '</script>';
1189 //video js vr end //
1190 }
1191 return $html;
1192 }
1193
1194 $control = false;
1195 if (isset($postdata['showControls'])) {
1196 $control = $postdata['showControls'];
1197 }
1198
1199 if ($control) {
1200 if (isset($postdata['customcontrol'])) {
1201 $custom_control = wpvr_parse_custom_control($postdata['customcontrol']);
1202 $custom_control = wp_parse_args($custom_control, array(
1203 'panupSwitch' => 'off',
1204 'panDownSwitch' => 'off',
1205 'panLeftSwitch' => 'off',
1206 'panRightSwitch' => 'off',
1207 'panZoomInSwitch' => 'off',
1208 'panZoomOutSwitch' => 'off',
1209 'panFullscreenSwitch' => 'off',
1210 'gyroscopeSwitch' => 'off',
1211 'backToHomeSwitch' => 'off',
1212 'explainerSwitch' => 'off',
1213 ));
1214 $gyro_enabled = isset($postdata['gyro']) && in_array($postdata['gyro'], array(true, 1, '1', 'on'), true);
1215 $custom_control['gyroSwitch'] = $gyro_enabled ? 'on' : 'off';
1216 $gyro_button_enabled = wpvr_isMobileDevice() && $custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on";
1217 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") {
1218 $control = false;
1219 }
1220 }
1221 }
1222
1223 $floor_plan_enable = 'off';
1224 $floor_plan_image = '';
1225 if (isset($postdata['floor_plan_tour_enabler']) && $postdata['floor_plan_tour_enabler'] == 'on') {
1226 $floor_plan_enable = $postdata['floor_plan_tour_enabler'];
1227 if (isset($postdata['floor_plan_attachment_url']) && !empty($postdata['floor_plan_attachment_url'])) {
1228 $floor_plan_image = $postdata['floor_plan_attachment_url'];
1229 }
1230 }
1231
1232 $vrgallery = false;
1233 if (isset($postdata['vrgallery'])) {
1234 $vrgallery = $postdata['vrgallery'];
1235 }
1236
1237 $vrgallery_title = false;
1238 if (isset($postdata['vrgallery_title'])) {
1239 $vrgallery_title = $postdata['vrgallery_title'];
1240 }
1241
1242 $vrgallery_display = false;
1243 if (isset($postdata['vrgallery_display'])) {
1244 $vrgallery_display = $postdata['vrgallery_display'];
1245 }
1246 $vrgallery_icon_size = false;
1247 if (isset($postdata['vrgallery_icon_size'])) {
1248 $vrgallery_icon_size = $postdata['vrgallery_icon_size'];
1249 }
1250
1251 $gyro = false;
1252 $gyro_orientation = false;
1253 if (isset($postdata['gyro'])) {
1254 $gyro = in_array($postdata['gyro'], array(true, 1, '1', 'on'), true);
1255 if ($gyro && isset($postdata['deviceorientationcontrol'])) {
1256 $gyro_orientation = in_array($postdata['deviceorientationcontrol'], array(true, 1, '1', 'on'), true);
1257 }
1258 }
1259
1260 $compass = false;
1261 $audio_right = "5px";
1262 if (isset($postdata['compass'])) {
1263 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
1264 if ($compass) {
1265 $audio_right = "60px";
1266 }
1267 }
1268 $floor_map_right = "25px";
1269 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
1270 $floor_map_right = "85px";
1271 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
1272 $floor_map_right = "55px";
1273 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
1274 $floor_map_right = "25px";
1275 }
1276
1277 //===explainer handle===//
1278
1279 //===explainer handle===//
1280 $explainer_right = "10px";
1281 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1282 $explainer_right = "130px";
1283 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on' && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1284 $explainer_right = "100px";
1285 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1286 $explainer_right = "55px";
1287 } elseif ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
1288 $explainer_right = "80px";
1289 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
1290 $explainer_right = "55px";
1291 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
1292 $explainer_right = "30px";
1293 } elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image)) {
1294 $explainer_right = "70px";
1295 }
1296 $enable_cardboard = '';
1297 $is_cardboard = get_option('wpvr_cardboard_disable');
1298 if (wpvr_isMobileDevice() && $is_cardboard == 'true') {
1299 $enable_cardboard = 'enable-cardboard';
1300 $audio_right = "73px";
1301 if (isset($postdata['compass'])) {
1302 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
1303 if ($compass) {
1304 $audio_right = "130px";
1305 }
1306 }
1307
1308 $floor_map_right = "60px";
1309 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
1310 $floor_map_right = "150px";
1311 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
1312 $floor_map_right = "120px";
1313 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
1314 $floor_map_right = "90px";
1315 }
1316
1317 //===explainer handle===//
1318
1319 $explainer_right = "65px";
1320
1321 if ((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
1322 $explainer_right = "150px";
1323 } elseif ((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1324 $explainer_right = "180px";
1325 } elseif (isset($postdata['compass']) && $postdata['compass'] == true && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1326 $explainer_right = "150px";
1327 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
1328 $explainer_right = "120px";
1329 } elseif (isset($postdata['compass']) && $postdata['compass'] == true) {
1330 $explainer_right = "130px";
1331 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
1332 $explainer_right = "90px";
1333 } elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image)) {
1334 $explainer_right = "90px";
1335 }
1336 }
1337
1338 //===explainer handle===//
1339
1340 $mouseZoom = true;
1341 if (isset($postdata['mouseZoom'])) {
1342 if ($postdata['mouseZoom'] == "off") {
1343 $mouseZoom = false;
1344 } else {
1345 $mouseZoom = true;
1346 }
1347 }
1348
1349 $draggable = true;
1350 if (isset($postdata['draggable'])) {
1351 $draggable = ! in_array( $postdata['draggable'], array( 'off', 'false', false ), true );
1352 }
1353 $diskeyboard = false;
1354 if (isset($postdata['diskeyboard'])) {
1355 $diskeyboard = ! in_array( $postdata['diskeyboard'], array( 'off', 'false', false ), true );
1356 }
1357
1358 $keyboardzoom = true;
1359 if (isset($postdata['keyboardzoom'])) {
1360 $keyboardzoom = ! in_array( $postdata['keyboardzoom'], array( 'off', 'false', false ), true );
1361 }
1362
1363 $autoload = false;
1364
1365 if (isset($postdata['autoLoad'])) {
1366 $autoload = in_array( $postdata['autoLoad'], array( true, 1, '1', 'on', 'true' ), true );
1367 }
1368
1369 $default_scene = '';
1370 if (isset($postdata['defaultscene'])) {
1371 $default_scene = $postdata['defaultscene'];
1372 }
1373
1374 $preview = '';
1375 if (isset($postdata['preview'])) {
1376 $preview = $postdata['preview'];
1377 }
1378
1379 $autorotation = '';
1380 if (isset($postdata["autoRotate"])) {
1381 $autorotation = $postdata["autoRotate"];
1382 }
1383 $autorotationinactivedelay = '';
1384 if (isset($postdata["autoRotateInactivityDelay"])) {
1385 $autorotationinactivedelay = $postdata["autoRotateInactivityDelay"];
1386 }
1387 $autorotationstopdelay = '';
1388 if (isset($postdata["autoRotateStopDelay"])) {
1389 $autorotationstopdelay = $postdata["autoRotateStopDelay"];
1390 }
1391
1392 $scene_fade_duration = '';
1393 if (isset($postdata['scenefadeduration'])) {
1394 $scene_fade_duration = $postdata['scenefadeduration'];
1395 }
1396
1397 $panodata = array();
1398 if (isset($postdata['panodata'])) {
1399 $panodata = $postdata['panodata'];
1400 }
1401
1402 $show_scene_info = ( $postdata['scene-info-enabled'] ?? 'on' ) !== 'off';
1403 $tour_layout = is_array( $postdata['tourLayout'] ?? null )
1404 ? ( $postdata['tourLayout']['layout'] ?? 'default' )
1405 : ( $postdata['tourLayout'] ?? 'default' );
1406 $is_classic_layout = 'layout1' !== $tour_layout;
1407
1408 $default_zoom_global = 100;
1409 if (isset($postdata['hfov']) && $postdata['hfov'] != '') {
1410 $default_zoom_global = $postdata['hfov'];
1411 }
1412
1413 $min_zoom_global = 50;
1414 if (isset($postdata['minHfov']) && $postdata['minHfov'] != '') {
1415 $min_zoom_global = $postdata['minHfov'];
1416 }
1417
1418 $max_zoom_global = 120;
1419 if (isset($postdata['maxHfov']) && $postdata['maxHfov'] != '') {
1420 $max_zoom_global = $postdata['maxHfov'];
1421 }
1422
1423 $hotspoticoncolor = '#00b4ff';
1424 $hotspotblink = 'on';
1425 $default_data = array();
1426 $default_data = array('firstScene' => $default_scene, 'sceneFadeDuration' => $scene_fade_duration, 'hfov' => $default_zoom_global, 'maxHfov' => $max_zoom_global, 'minHfov' => $min_zoom_global);
1427 $scene_data = array();
1428 if (is_array($panodata) && isset($panodata['scene-list'])) {
1429 if (!empty($panodata['scene-list'])) {
1430 foreach ($panodata['scene-list'] as $panoscenes) {
1431 $scene_ititle = '';
1432 if (isset($panoscenes["scene-ititle"])) {
1433 $scene_ititle = esc_html($panoscenes["scene-ititle"]);
1434 }
1435
1436 $scene_author = '';
1437 if (isset($panoscenes["scene-author"])) {
1438 $scene_author = esc_html($panoscenes["scene-author"]);
1439 }
1440
1441 $scene_author_url = '';
1442 if (isset($panoscenes["scene-author-url"])) {
1443 $scene_author_url = sanitize_text_field($panoscenes["scene-author-url"]);
1444 }
1445
1446 $scene_vaov = 180;
1447 if (isset($panoscenes["scene-vaov"])) {
1448 $scene_vaov = (float)$panoscenes["scene-vaov"];
1449 }
1450
1451 $scene_haov = 360;
1452 if (isset($panoscenes["scene-haov"])) {
1453 $scene_haov = (float)$panoscenes["scene-haov"];
1454 }
1455
1456 $scene_vertical_offset = 0;
1457 if (isset($panoscenes["scene-vertical-offset"])) {
1458 $scene_vertical_offset = (float)$panoscenes["scene-vertical-offset"];
1459 }
1460
1461 $default_scene_pitch = null;
1462 if (isset($panoscenes["scene-pitch"])) {
1463 $default_scene_pitch = (float)$panoscenes["scene-pitch"];
1464 }
1465
1466 $default_scene_yaw = null;
1467 if (isset($panoscenes["scene-yaw"])) {
1468 $default_scene_yaw = (float)$panoscenes["scene-yaw"];
1469 }
1470
1471 $scene_max_pitch = '';
1472 if (isset($panoscenes["scene-maxpitch"])) {
1473 $scene_max_pitch = (float)$panoscenes["scene-maxpitch"];
1474 }
1475
1476
1477 $scene_min_pitch = '';
1478 if (isset($panoscenes["scene-minpitch"])) {
1479 $scene_min_pitch = (float)$panoscenes["scene-minpitch"];
1480 }
1481
1482
1483 $scene_max_yaw = '';
1484 if (isset($panoscenes["scene-maxyaw"])) {
1485 $scene_max_yaw = (float)$panoscenes["scene-maxyaw"];
1486 }
1487
1488
1489 $scene_min_yaw = '';
1490 if (isset($panoscenes["scene-minyaw"])) {
1491 $scene_min_yaw = (float)$panoscenes["scene-minyaw"];
1492 }
1493
1494 $default_zoom = 100;
1495 if (isset($panoscenes["scene-zoom"]) && $panoscenes["scene-zoom"] != '') {
1496 $default_zoom = (int)$panoscenes["scene-zoom"];
1497 } else {
1498 if ($default_zoom_global != '') {
1499 $default_zoom = (int)$default_zoom_global;
1500 }
1501 }
1502
1503
1504 $max_zoom = 120;
1505 if (isset($panoscenes["scene-maxzoom"]) && $panoscenes["scene-maxzoom"] != '') {
1506 $max_zoom = (int)$panoscenes["scene-maxzoom"];
1507 } else {
1508 if ($max_zoom_global != '') {
1509 $max_zoom = (int)$max_zoom_global;
1510 }
1511 }
1512
1513 $min_zoom = 120;
1514 if (isset($panoscenes["scene-minzoom"]) && $panoscenes["scene-minzoom"] != '') {
1515 $min_zoom = (int)$panoscenes["scene-minzoom"];
1516 } else {
1517 if ($min_zoom_global != '') {
1518 $min_zoom = (int)$min_zoom_global;
1519 }
1520 }
1521
1522 $hotspot_datas = array();
1523 if (isset($panoscenes['hotspot-list'])) {
1524 $hotspot_datas = $panoscenes['hotspot-list'];
1525 }
1526
1527 $hotspots = array();
1528
1529 foreach ($hotspot_datas as $hotspot_data) {
1530 $status = get_option('wpvr_edd_license_status');
1531 if ($status !== false && $status == 'valid') {
1532
1533 if (isset($hotspot_data["hotspot-customclass-pro"]) && $hotspot_data["hotspot-customclass-pro"] != 'none') {
1534 $hotspot_data['hotspot-customclass'] = $hotspot_data["hotspot-customclass-pro"] . ' custom-' . $id . '-' . $panoscenes['scene-id'] . '-' . $hotspot_data['hotspot-title'];
1535 }
1536 if (isset($hotspot_data['hotspot-blink'])) {
1537 $hotspotblink = $hotspot_data['hotspot-blink'];
1538 }
1539 }
1540 $hotspot_scene_pitch = '';
1541 if (isset($hotspot_data["hotspot-scene-pitch"])) {
1542 $hotspot_scene_pitch = $hotspot_data["hotspot-scene-pitch"];
1543 }
1544 $hotspot_scene_yaw = '';
1545 if (isset($hotspot_data["hotspot-scene-yaw"])) {
1546 $hotspot_scene_yaw = $hotspot_data["hotspot-scene-yaw"];
1547 }
1548
1549 $hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
1550 $hotspot_content = '';
1551
1552 ob_start();
1553 do_action('wpvr_hotspot_content', $hotspot_data);
1554 $hotspot_content = ob_get_clean();
1555
1556 if (!$hotspot_content) {
1557 $hotspot_content = $hotspot_data["hotspot-content"];
1558 }
1559
1560 if (isset($hotspot_data["wpvr_url_open"][0])) {
1561 $wpvr_url_open = $hotspot_data["wpvr_url_open"][0];
1562 } else {
1563 $wpvr_url_open = "off";
1564 }
1565 $on_hover_content = preg_replace_callback(
1566 '/<p>\s*(<img[^>]*>)\s*<br>\s*<\/p>/i',
1567 function ($matches) {
1568 return $matches[1];
1569 },
1570 $hotspot_data['hotspot-hover'] ?? ''
1571 );
1572
1573 $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1574 $on_hover_content = sanitize_content_preserve_styles($on_hover_content ?? '', false);
1575 $on_click_content = preg_replace_callback('/<img[^>]*>/', "replace_callback", $hotspot_content ?? '');
1576 $on_click_content = sanitize_content_preserve_styles($on_click_content ?? '', $is_fluent_form);
1577
1578
1579 // Shape is independent of the optional custom icon in the
1580 // new editor, so it must always be included in the public
1581 // hotspot configuration.
1582 $hotspot_shape = isset( $hotspot_data['hotspot-shape'] )
1583 && in_array( $hotspot_data['hotspot-shape'], [ 'round', 'square', 'hexagon' ], true )
1584 ? $hotspot_data['hotspot-shape']
1585 : 'round';
1586
1587 $hotspot_data_for_on_click=[];
1588 if( ('info' === $hotspot_type || 'fluent_form' === $hotspot_data["hotspot-type"] ) && !empty($on_click_content)){
1589 $hotspot_data_for_on_click = [
1590 'on_click_content' => $on_click_content,
1591 'tour_id' => $id,
1592 'scene_id' => $panoscenes['scene-id'],
1593 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1594 ];
1595 } elseif('info' === $hotspot_type && !empty($hotspot_data["hotspot-url"])){
1596 $hotspot_data_for_on_click = [
1597 'on_click_content' => '',
1598 'tour_id' => $id,
1599 'scene_id' => $panoscenes['scene-id'],
1600 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1601 ];
1602 }
1603
1604 $hotspot_info = array(
1605 'text' => esc_html(sanitize_text_field($hotspot_data['hotspot-title'])),
1606 'pitch' => $hotspot_data['hotspot-pitch'],
1607 'yaw' => $hotspot_data['hotspot-yaw'],
1608 'type' => $hotspot_type,
1609 'cssClass' => $hotspot_data['hotspot-customclass'],
1610 'URL' => $hotspot_data['hotspot-url'],
1611 "wpvr_url_open" => $wpvr_url_open,
1612 "clickHandlerArgs" => $hotspot_data_for_on_click,
1613 'createTooltipArgs' => !empty(trim($on_hover_content)) ? trim($on_hover_content) : '',
1614 "sceneId" => $hotspot_data["hotspot-scene"],
1615 "targetPitch" => (float)$hotspot_scene_pitch,
1616 "targetYaw" => (float)$hotspot_scene_yaw,
1617 'hotspot_type' => $hotspot_data['hotspot-type'],
1618 'hotspot_shape' => $hotspot_shape,
1619 );
1620
1621 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1622
1623 if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1624 unset($hotspot_info["cssClass"]);
1625 }
1626 if (empty($hotspot_data["hotspot-scene"])) {
1627 unset($hotspot_info['targetPitch']);
1628 unset($hotspot_info['targetYaw']);
1629 }
1630 array_push($hotspots, $hotspot_info);
1631 }
1632
1633 $device_scene = $panoscenes['scene-attachment-url'];
1634 $mobile_media_resize = get_option('mobile_media_resize');
1635 $file_accessible = ini_get('allow_url_fopen');
1636 if ($mobile_media_resize == "true" && $device_scene) {
1637 if ($file_accessible == "1") {
1638 $image_info = getimagesize($device_scene);
1639 if ($image_info && $image_info[0] > 4096) {
1640 $src_to_id_for_mobile = '';
1641 $src_to_id_for_desktop = '';
1642 if (wpvr_isMobileDevice()) {
1643 $src_to_id_for_mobile = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1644 if ($src_to_id_for_mobile) {
1645 $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1646 if ($mobile_scene[3]) {
1647 $device_scene = $mobile_scene[0];
1648 }
1649 }
1650 } else {
1651 $src_to_id_for_desktop = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1652 if ($src_to_id_for_desktop) {
1653 $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1654 if ($desktop_scene && $desktop_scene[0]) {
1655 $device_scene = $desktop_scene[0];
1656 }
1657 }
1658 }
1659 }
1660 }
1661 }
1662
1663 $scene_info = array();
1664
1665 if ($panoscenes["scene-type"] == 'cubemap') {
1666 $pano_type = 'cubemap';
1667 $pano_attachment = array(
1668 $panoscenes["scene-attachment-url-face0"],
1669 $panoscenes["scene-attachment-url-face1"],
1670 $panoscenes["scene-attachment-url-face2"],
1671 $panoscenes["scene-attachment-url-face3"],
1672 $panoscenes["scene-attachment-url-face4"],
1673 $panoscenes["scene-attachment-url-face5"]
1674 );
1675
1676 $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);
1677 } else {
1678 $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);
1679 }
1680
1681
1682
1683 if (isset($panoscenes["ptyscene"])) {
1684 if ($panoscenes["ptyscene"] == "off") {
1685 unset($scene_info['pitch']);
1686 unset($scene_info['yaw']);
1687 }
1688 }
1689
1690 if (!$show_scene_info || empty($panoscenes["scene-ititle"])) {
1691 unset($scene_info['title']);
1692 }
1693 if (!$show_scene_info || empty($panoscenes["scene-author"])) {
1694 unset($scene_info['author']);
1695 }
1696 if (!$show_scene_info || empty($panoscenes["scene-author-url"])) {
1697 unset($scene_info['authorURL']);
1698 }
1699
1700 if (empty($scene_vaov)) {
1701 unset($scene_info['vaov']);
1702 }
1703
1704 if (empty($scene_haov)) {
1705 unset($scene_info['haov']);
1706 }
1707
1708 if (empty($scene_vertical_offset)) {
1709 unset($scene_info['vOffset']);
1710 }
1711
1712 if (isset($panoscenes["cvgscene"])) {
1713 if ($panoscenes["cvgscene"] == "off") {
1714 unset($scene_info['maxPitch']);
1715 unset($scene_info['minPitch']);
1716 }
1717 }
1718 if (empty($panoscenes["scene-maxpitch"])) {
1719 unset($scene_info['maxPitch']);
1720 }
1721
1722 if (empty($panoscenes["scene-minpitch"])) {
1723 unset($scene_info['minPitch']);
1724 }
1725
1726 if (isset($panoscenes["chgscene"])) {
1727 if ($panoscenes["chgscene"] == "off") {
1728 unset($scene_info['maxYaw']);
1729 unset($scene_info['minYaw']);
1730 }
1731 }
1732 if (empty($panoscenes["scene-maxyaw"])) {
1733 unset($scene_info['maxYaw']);
1734 }
1735
1736 if (empty($panoscenes["scene-minyaw"])) {
1737 unset($scene_info['minYaw']);
1738 }
1739
1740 // if (isset($panoscenes["czscene"])) {
1741 // if ($panoscenes["czscene"] == "off") {
1742 // unset($scene_info['hfov']);
1743 // unset($scene_info['maxHfov']);
1744 // unset($scene_info['minHfov']);
1745 // }
1746 // }
1747
1748 $scene_array = array();
1749 $scene_array = array(
1750 $panoscenes['scene-id'] => $scene_info
1751 );
1752
1753 $scene_data[$panoscenes['scene-id']] = $scene_info;
1754 }
1755 }
1756 }
1757 $pano_id_array = array();
1758 $pano_id_array = array('panoid' => $panoid);
1759 $pano_response = array();
1760 $pano_response = array('autoLoad' => $autoload, 'showControls' => $control, '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);
1761 if (empty($autorotation)) {
1762 unset($pano_response['autoRotate']);
1763 unset($pano_response['autoRotateInactivityDelay']);
1764 unset($pano_response['autoRotateStopDelay']);
1765 }
1766 if (empty($autorotationinactivedelay)) {
1767 unset($pano_response['autoRotateInactivityDelay']);
1768 }
1769 if (empty($autorotationstopdelay)) {
1770 unset($pano_response['autoRotateStopDelay']);
1771 }
1772
1773 $response = array();
1774 $response = array($pano_id_array, $pano_response);
1775 if (!empty($response)) {
1776 $response = json_encode($response);
1777 }
1778 if (empty($width)) {
1779 $width = '600';
1780 }
1781 if (empty($height)) {
1782 $height = '400';
1783 }
1784 if ('fullwidth' == $width) {
1785 $width = "100%";
1786 }
1787
1788 $foreground_color = '#fff';
1789 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1790 $rgb = wpvr_HTMLToRGB($hotspoticoncolor);
1791 $hsl = wpvr_RGBToHSL($rgb);
1792 if ($hsl->lightness > 200) {
1793 $foreground_color = '#000000';
1794 } else {
1795 $foreground_color = '#fff';
1796 }
1797
1798 $class = 'myclass';
1799 $html = 'test';
1800 $html = '';
1801 $html .= '<style>';
1802 if ($width == 'embed') {
1803 $html .= 'body{
1804 overflow: hidden;
1805 }';
1806 }
1807 $status = get_option('wpvr_edd_license_status');
1808 if ($status !== false && $status == 'valid') {
1809 if (isset($postdata['customcss_enable']) && $postdata['customcss_enable'] == 'on') {
1810 $html .= isset($postdata['customcss']) ? $postdata['customcss'] : '';
1811 }
1812 }
1813 if ($status !== false && $status == 'valid') {
1814 if (is_array($panodata) && isset($panodata['scene-list'])) {
1815 foreach ($panodata['scene-list'] as $panoscenes) {
1816
1817 foreach ($panoscenes['hotspot-list'] as $hotspot) {
1818 if (isset($hotspot['hotspot-customclass-color-icon-value']) && !empty($hotspot['hotspot-customclass-color-icon-value'])) {
1819 $hotspoticoncolor = $hotspot['hotspot-customclass-color-icon-value'];
1820 } else {
1821 $hotspoticoncolor = "#00b4ff";
1822 }
1823 $hotspot_border = '';
1824 if(isset($hotspot['hotspot-border']) && $hotspot['hotspot-border'] == 'on'){
1825 $border_width = $hotspot['hotspot-border-width'];
1826 $border_color = $hotspot['hotspot-border-color'];
1827 $border_style = $hotspot['hotspot-border-style'];
1828
1829 $hotspot_border = 'border: '.$border_width.'px '.$border_style.' '.$border_color.';';
1830 }
1831 $hotspot_background_color = 'background-color: ' . $hotspoticoncolor . ';';
1832 $hotspot_animation = ' animation: icon-pulse' . $panoid . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1833 '. $hotspot_border.'';
1834
1835
1836 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1837 if (isset($hotspot["hotspot-customclass-pro"]) && $hotspot["hotspot-customclass-pro"] != 'none') {
1838 $border_radius = ' border-radius: 100%;';
1839 $hotspot_shape = isset($hotspot["hotspot-shape"]) ? $hotspot["hotspot-shape"] : 'round';
1840 if($hotspot_shape === 'square'){
1841 $border_radius = '';
1842 }
1843 if ($hotspot_shape === 'hexagon') {
1844 $border_radius = '';
1845 $hotspot_background_color = 'background-color: transparent;';
1846 $hotspot_animation = '';
1847 }
1848
1849 if(isset($hotspot['hotspot-custom-icon-color-value']) && !empty($hotspot['hotspot-custom-icon-color-value'])){
1850 $foreground_color = $hotspot['hotspot-custom-icon-color-value'];
1851 }
1852 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fas.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1853 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fab.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1854 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fa.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1855 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fa-solid.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1856 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.far.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1857 display: block !important;
1858 '.$hotspot_background_color.'
1859 color: ' . $foreground_color . ';
1860 '.$border_radius.'
1861 width: 30px;
1862 height: 30px;
1863 font-size: 16px;
1864 line-height: 30px;
1865 '.$hotspot_animation.'
1866 }';
1867 if($hotspot_shape === 'hexagon'){
1868
1869 $html .= '#' . esc_attr( $panoid ) . ' .custom-' . esc_attr( $id ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' .hexagon-wrapper svg path {
1870 fill: ' . $hotspoticoncolor . ';
1871 }';
1872
1873 $html .= '#' . esc_attr( $panoid ) . ' .custom-' . esc_attr( $id ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . '.pnlm-tooltip:after{
1874 content: "";
1875 position: absolute;
1876 left: 50%;
1877 top: 50%;
1878 transform: translate(-50%, -50%);
1879 width: 85%;
1880 height: 85%;
1881 animation: icon-pulse' . esc_attr( $panoid ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1882 border-radius: 100%;
1883 z-index: -2;
1884 }';
1885
1886 }
1887 $html .= '#' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fas.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1888 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fab.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1889 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fa-solid.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1890 #' . esc_attr( $panoid2) . ' div.pnlm-hotspot-base.fa.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1891 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.far.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1892 display: block !important;
1893 '.esc_attr( $hotspot_background_color).'
1894 color: ' . esc_attr( $foreground_color) . ';
1895 '.esc_attr( $border_radius).'
1896 width: 30px;
1897 height: 30px;
1898 font-size: 16px;
1899 line-height: 30px;
1900 '.esc_attr( $hotspot_animation).'
1901 }';
1902 }
1903 if (isset($hotspot['hotspot-blink'])) {
1904 $hotspotblink = $hotspot['hotspot-blink'];
1905 if ($hotspotblink == 'on') {
1906 $html .= '@-webkit-keyframes icon-pulse' . esc_attr( $panoid) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1907 0% {
1908 box-shadow: 0 0 0 0px rgba(' . esc_attr( $pulse_color[0]) . ', 1);
1909 }
1910 100% {
1911 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pulse_color[0]) . ', 0);
1912 }
1913 }
1914 @keyframes icon-pulse' . esc_attr( $panoid) . ' {
1915 0% {
1916 box-shadow: 0 0 0 0px rgba(' . esc_attr( $pulse_color[0]) . ', 1);)
1917 }
1918 100% {
1919 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pulse_color[0] ). ', 0);
1920 }
1921 }';
1922 }
1923 }
1924 }
1925 }
1926 }
1927 }
1928
1929 $status = get_option('wpvr_edd_license_status');
1930 if ($status !== false && $status == 'valid') {
1931 if (!$gyro) {
1932 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-orientation-button {
1933 display: none;
1934 }';
1935 }
1936 } else {
1937 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-orientation-button {
1938 display: none;
1939 }';
1940 }
1941 $floor_plan_custom_color = isset($postdata['floor_plan_custom_color']) ? $postdata['floor_plan_custom_color'] : '#cca92c';
1942 $foreground_color_pointer = '#fff';
1943 if ($floor_plan_custom_color != '') {
1944 $pointer_pulse = wpvr_hex2rgb($floor_plan_custom_color);
1945 $floor_rgb = wpvr_HTMLToRGB($floor_plan_custom_color);
1946 $floor_hsl = wpvr_RGBToHSL($floor_rgb);
1947 if ($floor_hsl->lightness > 200) {
1948 $foreground_color_pointer = '#000000';
1949 }
1950 $html .= '
1951 .wpvr-floor-map .floor-plan-pointer.add-pulse:before {
1952 border: 17px solid ' . esc_attr( $floor_plan_custom_color ) . ';
1953 }
1954 @-webkit-keyframes pulse {
1955 0% {
1956 -webkit-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1957 }
1958 70% {
1959 -webkit-box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1960 }
1961 100% {
1962 -webkit-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1963 }
1964 }
1965 @keyframes pulse {
1966 0% {
1967 -moz-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1968 box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1969 }
1970 70% {
1971 -moz-box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1972 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1973 }
1974 100% {
1975 -moz-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1976 box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1977 }
1978 }';
1979 }
1980 $html .= '</style>';
1981
1982 $scene_animation = isset($postdata['sceneAnimation']) ? $postdata['sceneAnimation'] : 'off';
1983 $scene_animation_enabled = in_array( $scene_animation, array( 'on', '1', 1, true ), true );
1984
1985 if( $scene_animation_enabled && is_plugin_active( 'wpvr-pro/wpvr-pro.php' ) ) {
1986 $animation_type = isset($postdata['sceneAnimationName']) ? $postdata['sceneAnimationName'] : 'none';
1987 $animation_type = $animation_type === 'fade' ? 'fade_in' : $animation_type;
1988 $animationDuration = isset($postdata['sceneAnimationTransitionDuration']) ? $postdata['sceneAnimationTransitionDuration'] : '500ms';
1989 $animationDelay = isset($postdata['sceneAnimationTransitionDelay']) ? $postdata['sceneAnimationTransitionDelay'] : '0ms';
1990 $animation_css = apply_filters('wpvr_tour_scene_animation',$animation_type,$animationDuration, $animationDelay, $postdata,$id);
1991 $html .= $animation_css;
1992 }
1993
1994 if (wpvr_isMobileDevice()) {
1995 $html .= '<div id="master-container" class="wpvr-cardboard ' . esc_attr( $className ) . ' ' . esc_attr( $enable_cardboard ) . ' " style="max-width:' . esc_attr( $width ) . esc_attr( $width_unit ) . '; width: 100%; height: ' . esc_attr( $mobile_height ) . esc_attr( $mobile_height_unit ) . '; border-radius:' . esc_attr( $radius ) . '; direction:ltr; border : ' . esc_attr( $border_style ) . ' ">';
1996 } else {
1997 $html .= '<div id="master-container" class="wpvr-cardboard ' . esc_attr( $className ) . ' ' . esc_attr( $enable_cardboard ) . '" style="max-width:' . esc_attr( $width ) . esc_attr( $width_unit ) . '; width: 100%; height: ' . esc_attr( $height ) . esc_attr( $height_unit ) . '; border-radius:' . esc_attr( $radius ) . '; direction:ltr; border : ' . esc_attr( $border_style ) . '">';
1998 }
1999 $status = get_option('wpvr_edd_license_status');
2000 $is_cardboard = get_option('wpvr_cardboard_disable');
2001 if ($status !== false && 'valid' == $status && $is_pro && wpvr_isMobileDevice() && $is_cardboard == 'true') {
2002 $html .= '<button class="fullscreen-button">';
2003 $html .= '<span class="expand">';
2004 $html .= '<i class="fas fa-expand" aria-hidden="true"></i>';
2005 $html .= '</span>';
2006
2007 $html .= '<span class="compress">';
2008 $html .= '<i class="fas fa-minimize" aria-hidden="true"></i>';
2009 $html .= '</span>';
2010 $html .= '</button>';
2011 $html .= '<label class="wpvr-cardboard-switcher">
2012 <input type="checkbox" class="vr_mode_change' . $id . '" name="vr_mode_change" value="off">
2013 <span class="switcher-box">
2014 <span class="normal-mode-tooltip">Normal VR Mode</span>
2015 <svg width="78" height="60" viewBox="0 0 78 60" fill="none" xmlns="http://www.w3.org/2000/svg">
2016 <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"/>
2017 </svg>
2018 </span>
2019 </label>';
2020 }
2021
2022 if ($width == 'fullwidth') {
2023 if (wpvr_isMobileDevice()) {
2024 $html .= '<div class="cardboard-vrfullwidth vrfullwidth">';
2025 $html .= '<div id="pano2' . esc_attr( $id ) . '" class="pano-wrap pano-left cardboard-half" style="width: 49%!important; border-radius:' . esc_attr( $radius ). ' ;text-align:center; direction:ltr;" ><div id="center-pointer2' . esc_attr( $id ). '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
2026 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap pano-right" style="width: 100%; text-align:center; direction:ltr; border-radius:' . esc_attr( $radius ) . '" >';
2027 } else {
2028 $html .= '<div id="pano2' . esc_attr( $id ) . '" class="pano-wrap pano-left" style="width: 49%; border-radius:' . esc_attr( $radius ) . ';"><div id="center-pointer2' . esc_attr( $id ). '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
2029 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap vrfullwidth" style=" text-align:center; height: ' . esc_attr( $height ) . esc_attr( $height_unit ) . '; border-radius:' . esc_attr( $radius ) . '; direction:ltr;" >';
2030 }
2031 } else {
2032 if (wpvr_isMobileDevice()) {
2033 $html .= '<div id="pano2' . esc_attr( $id ) . '" class="pano-wrap pano-left cardboard-half" style="width: 49%; border-radius:' . esc_attr( $radius ) . ';">
2034 <div id="center-pointer2' . esc_attr( $id ) . '" class="vr-pointer-container">
2035 <span class="center-pointer"></span>
2036 </div>
2037 </div>';
2038 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap pano-right" style=" width: 100%; border-radius:' . esc_attr( $radius ) . ';">';
2039 } else {
2040
2041 $html .= '<div id="pano2' . esc_attr( $id ) . '" class="pano-wrap pano-left" style="width: 49%; border-radius:' . esc_attr( $radius ) . ';"><div id="center-pointer2' . esc_attr( $id ) . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
2042
2043 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap pano-right" style="width: 100%; border-radius:' . esc_attr( $radius ) . ';">';
2044 }
2045 }
2046 // Vr mode transction scene to scene
2047 if ($status !== false && 'valid' == $status && $is_pro && wpvr_isMobileDevice() && $is_cardboard == 'true') {
2048 $html .= '<div id="center-pointer' . esc_attr( $id ) . '" class="vr-pointer-container" style="display:none"><span class="center-pointer"></span></div>';
2049 }
2050
2051
2052 //===company logo===//
2053 if (isset($postdata['cpLogoSwitch'])) {
2054 $cpLogoImg = $postdata['cpLogoImg'] ?? '';
2055 $cpLogoContent = $postdata['cpLogoContent'] ?? '';
2056 if ($postdata['cpLogoSwitch'] == 'on' && 'valid' == $status && $is_pro) {
2057 $html .= '<div id="cp-logo-controls">';
2058 $html .= '<div class="cp-logo-ctrl" id="cp-logo">';
2059 if ($cpLogoImg) {
2060 $html .= '<img loading="lazy" src="' . esc_attr( $cpLogoImg ) . '" alt="Company Logo">';
2061 }
2062
2063 if ($cpLogoContent) {
2064 $html .= '<div class="cp-info">' . esc_html( $cpLogoContent ) . '</div>';
2065 }
2066 $html .= '</div>';
2067 $html .= '</div>';
2068 }
2069 }
2070 //===company logo ends===//
2071
2072 //===Background Tour===//
2073 if (isset($postdata['bg_tour_enabler'])) {
2074
2075 $bg_tour_enabler = $postdata['bg_tour_enabler'];
2076 if ($bg_tour_enabler == 'on') {
2077 $bg_tour_navmenu = $postdata['bg_tour_navmenu'] ?? 'off';
2078 $bg_tour_title = $postdata['bg_tour_title'] ?? '';
2079 $bg_tour_subtitle = $postdata['bg_tour_subtitle'] ?? '';
2080
2081 if ($bg_tour_navmenu == 'on') {
2082 $menuLocations = get_nav_menu_locations();
2083 $menuID = $menuLocations['primary'];
2084 $primaryNav = wp_get_nav_menu_items($menuID);
2085
2086 if ($primaryNav) {
2087 $html .= '<div class="wpvr-navbar-container">';
2088 foreach ($primaryNav as $primaryNav_key => $primaryNav_value) {
2089 if ($primaryNav_value->menu_item_parent == "0") {
2090 $html .= '<li>';
2091 $html .= '<a href="' . esc_url( $primaryNav_value->url ) . '">' . esc_attr( $primaryNav_value->title ) . '</a>';
2092 $html .= '<ul class="wpvr-navbar-dropdown">';
2093 foreach ($primaryNav as $pm_key => $pm_value) {
2094 if ($pm_value->menu_item_parent == $primaryNav_value->ID) {
2095 $html .= '<li>';
2096 $html .= '<a href="' . esc_url( $pm_value->url ) . '">' . esc_attr( $pm_value->title ) . '</a>';
2097 $html .= '</li>';
2098 }
2099 }
2100 $html .= '</ul>';
2101 $html .= '</li>';
2102 }
2103 }
2104 $html .= '</div>';
2105 }
2106 }
2107
2108 if($is_pro && 'valid' == $status ){
2109 $html .= '<div class="wpvr-home-content">';
2110 $html .= '<div class="wpvr-home-title">' . $bg_tour_title . '</div>';
2111 $html .= '<div class="wpvr-home-subtitle">' . $bg_tour_subtitle . '</div>';
2112 $html .= '</div>';
2113 }
2114 }
2115 }
2116 //===Background Tour End===//
2117
2118 //===Custom Control===//
2119 if (isset($custom_control)) {
2120 $gyro_button_enabled = wpvr_isMobileDevice() && $custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on";
2121 if ($custom_control['panZoomInSwitch'] == "on" || $custom_control['panZoomOutSwitch'] == "on" || $gyro_button_enabled || $custom_control['backToHomeSwitch'] == "on") {
2122 $html .= '<div id="zoom-in-out-controls' . esc_attr( $id ) . '" class="zoom-in-out-controls">';
2123
2124 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
2125 $html .= '<div class="ctrl" id="backToHome' . esc_attr( $id ) . '"><i class="' . $custom_control['backToHomeIcon'] . '" style="color:' . esc_attr( $custom_control['backToHomeColor'] ) . ';"></i></div>';
2126 }
2127
2128 if ($custom_control['panZoomInSwitch'] == "on" && 'valid' == $status && $is_pro) {
2129 $html .= '<div class="ctrl" id="zoom-in' . esc_attr( $id ) . '"><i class="' . $custom_control['panZoomInIcon'] . '" style="color:' . esc_attr( $custom_control['panZoomInColor'] ) . ';"></i></div>';
2130 }
2131
2132 if ($custom_control['panZoomOutSwitch'] == "on" && 'valid' == $status && $is_pro) {
2133 $html .= '<div class="ctrl" id="zoom-out' . esc_attr( $id ) . '"><i class="' . $custom_control['panZoomOutIcon'] . '" style="color:' . esc_attr( $custom_control['panZoomOutColor'] ) . ';"></i></div>';
2134 }
2135
2136 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
2137 $html .= '<div class="ctrl" id="gyroscope' . esc_attr( $id ) . '"><i class="' . $custom_control['gyroscopeIcon'] . '" style="color:' . esc_attr( $custom_control['gyroscopeColor'] ) . ';"></i></div>';
2138 }
2139
2140 $html .= '</div>';
2141 }
2142 //===zoom in out Control===//
2143
2144 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) {
2145
2146 //===Custom Control===//
2147 $html .= '<div class="controls" id="controls' . esc_attr( $id ) . '">';
2148
2149 if ($custom_control['panupSwitch'] == "on") {
2150 $html .= '<div class="ctrl pan-up" id="pan-up' . esc_attr( $id ) . '"><i class="' . $custom_control['panupIcon'] . '" style="color:' . esc_attr( $custom_control['panupColor'] ) . ';"></i></div>';
2151 }
2152
2153 if ($custom_control['panDownSwitch'] == "on") {
2154 $html .= '<div class="ctrl pan-down" id="pan-down' . esc_attr( $id ) . '"><i class="' . $custom_control['panDownIcon'] . '" style="color:' . esc_attr( $custom_control['panDownColor'] ) . ';"></i></div>';
2155 }
2156
2157 if ($custom_control['panLeftSwitch'] == "on") {
2158 $html .= '<div class="ctrl pan-left" id="pan-left' . esc_attr( $id ) . '"><i class="' . $custom_control['panLeftIcon'] . '" style="color:' . esc_attr( $custom_control['panLeftColor'] ) . ';"></i></div>';
2159 }
2160
2161 if ($custom_control['panRightSwitch'] == "on") {
2162 $html .= '<div class="ctrl pan-right" id="pan-right' . esc_attr( $id ) . '"><i class="' . $custom_control['panRightIcon'] . '" style="color:' . esc_attr( $custom_control['panRightColor'] ) . ';"></i></div>';
2163 }
2164
2165 if ($custom_control['panFullscreenSwitch'] == "on") {
2166 $html .= '<div class="ctrl fullscreen" id="fullscreen' . esc_attr( $id ) . '"><i class="' . $custom_control['panFullscreenIcon'] . '" style="color:' . esc_attr( $custom_control['panFullscreenColor'] ) . ';"></i></div>';
2167 }
2168 $html .= '</div>';
2169 }
2170 }
2171
2172 //===explainer button===//
2173 $html .= wpvr_render_explainer_button(
2174 isset( $custom_control ) ? $custom_control : null,
2175 $postdata,
2176 $is_pro,
2177 $autoload,
2178 $explainer_right,
2179 $id
2180 );
2181 //===explainer button end===//
2182
2183 //===Scene navigation Control===//
2184 if (isset($postdata['scene_navigation']) && $postdata['scene_navigation'] === 'on' && 'valid' == $status && $is_pro) {
2185 $scene_navigation_nav_class = 'custom-scene-navigation-nav' . ( $is_classic_layout ? ' wpvr-scene-navigation-nav--classic' : '' );
2186 $html .= '<style>
2187 #et-boc .et-l .pnlm-controls-container,
2188 .pnlm-controls-container{
2189 top: 33px;
2190 }
2191
2192 #et-boc .et-l .zoom-in-out-controls,
2193 .zoom-in-out-controls {
2194 top: 37px;
2195 }
2196 </style>';
2197 $html .= '<div id="custom-scene-navigation' . esc_attr( $id ) . '" class="custom-scene-navigation">
2198 <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>
2199 </div>
2200
2201 <div id="custom-scene-navigation-nav' . esc_attr( $id ) . '" class="' . esc_attr( $scene_navigation_nav_class ) . '">
2202 <ul></ul>
2203 </div>
2204 ';
2205 }
2206
2207 //===Scene navigation Control===//
2208
2209 /**
2210 * Generic Form Handler
2211 * Renders a generic form with modal functionality if enabled in post data
2212 *
2213 * @param array $postdata Array containing form configuration data
2214 * @param string $id Unique identifier for the form instance
2215 * @return string $html Generated HTML content
2216 */
2217
2218 // Check if generic form is enabled and validate the setting
2219 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on' && 'valid' == $status && $is_pro) {
2220
2221 // Process shortcode with fallback handling
2222 $shortcode_content = '';
2223 if (isset($postdata["genericformshortcode"]) && !empty(trim($postdata["genericformshortcode"]))) {
2224 $shortcode_content = do_shortcode( $postdata["genericformshortcode"] );
2225 } else {
2226 $shortcode_content = '<p class="error-message">No shortcode found.</p>';
2227 }
2228
2229 // Generate the form trigger button
2230 $generic_form_icon = isset($postdata['genericformicon']) ? (string) $postdata['genericformicon'] : 'fab fa-wpforms';
2231 $generic_form_icon = implode(' ', array_filter(array_map('sanitize_html_class', preg_split('/\s+/', $generic_form_icon))));
2232 $generic_form_icon = $generic_form_icon ?: 'fab fa-wpforms';
2233 $generic_form_icon_color = sanitize_hex_color($postdata['genericformiconcolor'] ?? '') ?: '#f7fffb';
2234 $html .= '<div class="generic_form_button" id="generic_form_button_' . esc_attr( $id ) . '">';
2235 $html .= '<div class="generic-form-icon" title ="Generic Form" id="generic_form_target_' . esc_attr( $id ) . '"><i class="' . esc_attr( $generic_form_icon ) . '" style="color:' . esc_attr( $generic_form_icon_color ) . ';"></i></div>';
2236 $html .= '</div>';
2237
2238 // Generate the modal form container
2239 $html .= '<div class="wpvr-generic-form" id="wpvr-generic-form' . esc_attr( $id ) . '" style="display: none">';
2240 $html .= '<span class="close-generic-form"><i class="fa fa-times"></i></span>';
2241 $html .= '<div class="generic-form-container">' . $shortcode_content . '</div>';
2242 $html .= '</div>';
2243 }
2244 //=====custom generic form=====//
2245
2246 //===Floor map button===//
2247 $status = get_option('wpvr_edd_license_status');
2248 if ($status !== false && 'valid' == $status && $is_pro) {
2249 if ($floor_plan_enable == "on" && !empty($floor_plan_image)) {
2250 $html .= '<div class="floor_map_button" id="floor_map_button_' . esc_attr( $id ) . '" style="right:' . esc_attr( $floor_map_right ) . '">';
2251 $html .= '<div class="ctrl" id="floor_map_target_' . esc_attr( $id ) . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
2252 $html .= '</div>';
2253 }
2254 }
2255
2256 //===floor map button===//
2257 if ($vrgallery && 'valid' == $status && $is_pro ) {
2258 //===Carousal setup===//
2259 $size = '';
2260 if ($vrgallery_icon_size) {
2261 $size = 'vrg-icon-size-large';
2262 }
2263 $html .= '<div id="vrgcontrols' . esc_attr( $id ) . '" class="vrgcontrols">';
2264
2265 $html .= '<div class="vrgctrl' . esc_attr( $id ) . ' vrbounce ' . esc_attr( $size ) . '">';
2266 $html .= '</div>';
2267 $html .= '</div>';
2268
2269 $tour_layout = is_array( $postdata['tourLayout'] ?? null )
2270 ? ( $postdata['tourLayout']['layout'] ?? 'default' )
2271 : ( $postdata['tourLayout'] ?? 'default' );
2272 $gallery_layout_class = 'layout1' === $tour_layout
2273 ? 'wpvr-gallery--modern'
2274 : 'wpvr-gallery--classic';
2275
2276 $html .= '<div id="sccontrols' . esc_attr( $id ) . '" class="scene-gallery vrowl-carousel owl-theme ' . esc_attr( $gallery_layout_class ) . '">';
2277 if (isset($panodata["scene-list"])) {
2278 foreach ($panodata["scene-list"] as $panoscenes) {
2279 $scene_key = $panoscenes['scene-id'];
2280 if ($vrgallery_title == 'on') {
2281 $scene_key_title = isset($panoscenes['scene-ititle']) ? esc_html($panoscenes['scene-ititle']) : '';
2282 } else {
2283 $scene_key_title = "";
2284 }
2285
2286 if ($panoscenes['scene-type'] == 'cubemap') {
2287 $img_src_url = $panoscenes['scene-attachment-url-face0'];
2288 } else {
2289 $img_src_url = $panoscenes['scene-attachment-url'];
2290 }
2291
2292
2293 $src_to_id = attachment_url_to_postid($img_src_url);
2294 $thumbnail_array = wp_get_attachment_image_src($src_to_id, 'thumbnail');
2295 if ($thumbnail_array) {
2296 $thumbnail = $thumbnail_array[0];
2297 } else {
2298 $thumbnail = $img_src_url;
2299 }
2300 if ( 'layout1' !== $tour_layout ) {
2301 $html .= '<ul><li title="Double click to view scene"><span class="scene-title" title="' . esc_attr($scene_key_title) . '"> ' . $scene_key_title . '</span><img loading="lazy" class="scctrl" id="' . $scene_key . '_gallery_' . $id . '" src="' . $thumbnail . '"></li></ul>';
2302 }else {
2303 $html .= '<ul><li title="Double click to view scene"><img loading="lazy" class="scctrl" id="' . $scene_key . '_gallery_' . $id . '" src="' . $thumbnail . '"><span class="scene-title" title="' . esc_attr($scene_key_title) . '">' . $scene_key_title . '</span></li></ul>';
2304 }
2305 }
2306 }
2307 $html .= '</div>';
2308 $html .= '
2309 <div class="owl-nav wpvr_slider_nav">
2310 <button type="button" role="presentation" class="owl-prev wpvr_owl_prev">
2311 <div class="nav-btn prev-slide"><i class="fa fa-angle-left"></i></div>
2312 </button>
2313 <button type="button" role="presentation" class="owl-next wpvr_owl_next">
2314 <div class="nav-btn next-slide"><i class="fa fa-angle-right"></i></div>
2315 </button>
2316 </div>
2317 ';
2318 //===Carousal setup end===//
2319 }
2320
2321 $bg_music = isset($postdata['bg_music']) ? $postdata['bg_music'] : 'off';
2322 $bg_music_url = isset($postdata['bg_music_url']) ? $postdata['bg_music_url'] : '';
2323 $autoplay_bg_music = isset($postdata['autoplay_bg_music']) ? $postdata['autoplay_bg_music'] : 'off';
2324 $loop_bg_music = isset($postdata['loop_bg_music']) ? $postdata['loop_bg_music'] : 'off';
2325
2326 $bg_loop = ($loop_bg_music === 'on') ? 'loop' : '';
2327 $autoplay_attr = ($autoplay_bg_music === 'on') ? 'autoplay' : '';
2328 $audio_muted_attr = ($autoplay_bg_music === 'on') ? 'muted' : '';
2329 $audio_icon_class = 'fa-volume-mute'; // Always start with mute icon
2330
2331 if ($bg_music === 'on' && 'valid' == $status && $is_pro) {
2332 $html .= '<div id="adcontrol' . esc_attr( $id ) . '" class="adcontrol" style="right:' . esc_attr( $audio_right ) . '">';
2333 $html .= '<audio id="vrAudio' . esc_attr($id) . '" class="vrAudioDefault" data-autoplay="' . esc_attr($autoplay_bg_music) . '" onended="audionEnd' . esc_attr($id) . '()" ' . $autoplay_attr . ' ' . $audio_muted_attr . ' ' . $bg_loop . '>
2334 <source src="' . esc_url($bg_music_url) . '" type="audio/mpeg">
2335 Your browser does not support the audio element.
2336 </audio>';
2337 $html .= '<button onclick="playPause' . esc_attr($id) . '()" class="ctrl audio_control" id="audio_control' . esc_attr($id) . '">
2338 <i id="vr-volume' . esc_attr($id) . '" class="wpvrvolumeicon' . esc_attr($id) . ' fas ' . esc_attr($audio_icon_class) . '" style="color:#fff;"></i>
2339 </button>';
2340 $html .= '</div>';
2341 }
2342
2343 //===Explainer video section===//
2344 $explainerContent = "";
2345 if (isset($postdata['explainerContent'])) {
2346 $explainerContent = wpvr_sanitize_iframe_only($postdata['explainerContent']);
2347 }
2348 $html .= '<div class="explainer" id="explainer' . esc_attr( $id ) . '" style="display: none">';
2349 $html .= '<span class="close-explainer-video"><i class="fa fa-times"></i></span>';
2350 $html .= '' . $explainerContent . '';
2351 $html .= '</div>';
2352 //===Explainer video section End===//
2353
2354 //===Floor plan section===//
2355 $floor_map_image = "";
2356 $floor_map_pointer = array();
2357 $floor_map_scene_id = '';
2358 $floor_plan_custom_color = '#cca92c';
2359 $floor_plan_direction_indicator = isset($postdata['floor_plan_direction_indicator']) ? $postdata['floor_plan_direction_indicator'] : 'on';
2360
2361 if (isset($postdata['floor_plan_attachment_url'])) {
2362 $floor_map_image = $postdata['floor_plan_attachment_url'];
2363 $floor_map_pointer = $postdata['floor_plan_pointer_position'];
2364 $floor_map_scene_id = $postdata['floor_plan_data_list'];
2365 $floor_plan_custom_color = $postdata['floor_plan_custom_color'];
2366 }
2367 $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $id . '" style="display: none">';
2368 $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
2369 $html .= '<img loading="lazy" src="' . $floor_map_image . '">';
2370
2371 foreach ($floor_map_pointer as $key => $pointer_position) {
2372 $html .= '<div class="floor-plan-pointer ui-draggable ui-draggable-handle" scene_id = "' . esc_attr( $floor_map_scene_id[$key]->value ) . '" id="' . esc_attr( $pointer_position->id ) . '" data-top="' . esc_attr( $pointer_position->data_top ) . '" data-left="' . esc_attr( $pointer_position->data_left ) . '" style="' . esc_attr( $pointer_position->style ) . '">
2373
2374 <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2375 <circle cx="12" cy="12" r="11.5" stroke="' . esc_attr( $floor_plan_custom_color ) . '"/>
2376 <circle cx="12" cy="12" r="5" fill="' . esc_attr( $foreground_color_pointer ) . '"/>
2377 </svg>';
2378
2379 // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
2380 if ($floor_plan_direction_indicator === "on") {
2381 $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
2382 <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)"/>
2383 <defs>
2384 <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
2385 <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
2386 <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
2387 </linearGradient>
2388 </defs>
2389 </svg>';
2390 }
2391 $html .= '</div>';
2392 }
2393 $html .= '</div>';
2394 //===Floor plan section===//
2395
2396 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
2397 $html .= '<i class="fa fa-times cross" data-id="' . esc_attr( $id ) . '"></i>';
2398 $html .= '<div class="wpvr-hotspot-tweak-contents-flex">';
2399 $html .= '<div class="wpvr-hotspot-tweak-contents">';
2400 ob_start();
2401 do_action('wpvr_hotspot_tweak_contents', $scene_data);
2402 $hotspot_content = ob_get_clean();
2403 $html .= $hotspot_content;
2404 $html .= '</div>';
2405 $html .= '</div>';
2406 $html .= '</div>';
2407
2408 $html .= '<div class="custom-ifram-wrapper" style="display: none;">';
2409 $html .= '<i class="fa fa-times cross" data-id="' . esc_attr( $id ) . '"></i>';
2410 $html .= '<div class="custom-ifram-flex">';
2411 $html .= '<div class="custom-ifram">';
2412 $html .= '</div>';
2413 $html .= '</div>';
2414 $html .= '</div>';
2415 $html .= '</div>';
2416 $html .= '</div>';
2417
2418
2419 if ("fullwidth" == $width) {
2420 $html .= '</div>';
2421 }
2422 if ($status !== false && 'valid' == $status && $is_pro) {
2423 $call_to_action = isset($postdata['calltoaction']) ? $postdata['calltoaction'] : 'off';
2424 if ('on' == $call_to_action) {
2425 $buttontext = isset($postdata['buttontext']) ? $postdata['buttontext'] : '';
2426 $buttonurl = isset($postdata['buttonurl']) ? $postdata['buttonurl'] : '';
2427 $cta_btn_style = isset($postdata['button_configuration']) ? $postdata['button_configuration'] : array();
2428
2429 $button_open_new_tab = isset($cta_btn_style['button_open_new_tab']) ? $cta_btn_style['button_open_new_tab'] : "off";
2430 $target = '_self';
2431 $button_position = isset($cta_btn_style['button_position']) ? $cta_btn_style['button_position'] : "";
2432 $background_color = isset($cta_btn_style['button_background_color']) ? $cta_btn_style['button_background_color'] : "";
2433 $color = isset($cta_btn_style['button_font_color']) ? $cta_btn_style['button_font_color'] : "";
2434 $font_size = isset($cta_btn_style['button_font_size']) ? $cta_btn_style['button_font_size'] : "";
2435 $font_weight = isset($cta_btn_style['button_font_weight']) ? $cta_btn_style['button_font_weight'] : "";
2436 $text_align = isset($cta_btn_style['button_alignment']) ? $cta_btn_style['button_alignment'] : "";
2437 $text_transform = isset($cta_btn_style['button_transform']) ? $cta_btn_style['button_transform'] : "";
2438 $font_style = isset($cta_btn_style['button_text_style']) ? $cta_btn_style['button_text_style'] : "";
2439 $text_decoration = isset($cta_btn_style['button_text_decoration']) ? $cta_btn_style['button_text_decoration'] : "";
2440 $line_height = isset($cta_btn_style['button_line_height']) ? $cta_btn_style['button_line_height'] : "";
2441 $letter_spacing = isset($cta_btn_style['button_letter_spacing']) ? $cta_btn_style['button_letter_spacing'] : "";
2442 $word_spacing = isset($cta_btn_style['button_word_spacing']) ? $cta_btn_style['button_word_spacing'] : "";
2443
2444 $border_width = isset($cta_btn_style['button_border_width']) ? $cta_btn_style['button_border_width'] : "";
2445 $border_style = isset($cta_btn_style['button_border_style']) ? $cta_btn_style['button_border_style'] : "";
2446 $border_color = isset($cta_btn_style['button_border_color']) ? $cta_btn_style['button_border_color'] : "";
2447 $border_radius = isset($cta_btn_style['button_border_radius']) ? $cta_btn_style['button_border_radius'] : "";
2448
2449 $button_pt = isset($cta_btn_style['button_pt']) ? $cta_btn_style['button_pt'] : "";
2450 $button_pr = isset($cta_btn_style['button_pr']) ? $cta_btn_style['button_pr'] : "";
2451 $button_pb = isset($cta_btn_style['button_pb']) ? $cta_btn_style['button_pb'] : "";
2452 $button_pl = isset($cta_btn_style['button_pl']) ? $cta_btn_style['button_pl'] : "";
2453
2454 if ($button_open_new_tab == 'on') {
2455 $target = '_blank';
2456 }
2457 $style = 'background-color: ' . esc_attr( $background_color ) . ';
2458 color: ' . esc_attr( $color ) . ';
2459 font-size: ' . esc_attr( $font_size ) . 'px;
2460 font-weight: ' . esc_attr( $font_weight ) . ';
2461 text-align: center;
2462 display: inline-block;
2463 text-transform: ' . esc_attr( $text_transform ) . ';
2464 font-style: ' . esc_attr( $font_style ) . ';
2465 text-decoration: ' . esc_attr( $text_decoration ) . ';
2466 line-height: ' . esc_attr( $line_height ) . ';
2467 letter-spacing: ' . esc_attr( $letter_spacing ) . 'px;
2468 word-spacing: ' . esc_attr( $word_spacing ) . 'px;
2469 border: ' . esc_attr( $border_width ) . 'px ' . esc_attr( $border_style ) . ' ' . esc_attr( $border_color ) . ';
2470 border-radius: ' . esc_attr( $border_radius ). 'px;
2471 padding: ' . esc_attr( $button_pt ) . 'px ' . esc_attr( $button_pr ) . 'px ' . esc_attr( $button_pb ) . 'px ' . esc_attr( $button_pl ) . 'px;
2472 ';
2473 $html .= '<div class="wpvr-call-to-action-button position-' . esc_attr( $text_align ) . '" style="max-width:' . esc_attr( $width ) . esc_attr( $width_unit ) . '">
2474 <a href="' . esc_url( $buttonurl ) . '" style="' . esc_attr( $style ) . '" target="' . esc_attr( $target ) . '">' . esc_attr( $buttontext ) . '</a>
2475 </div>';
2476 }
2477 }
2478
2479 //script started
2480
2481 $html .= '<script>';
2482 if (isset($postdata['bg_music']) && $bg_music == 'on' && 'valid' == $status && $is_pro) {
2483 $html .= '
2484 var x' . $id . ' = document.getElementById("vrAudio' . $id . '");
2485
2486 var playing' . $id . ' = false;
2487 var autoplaySupported' . $id . ' = false;
2488 var alertShown' . $id . ' = false;
2489 var autoplayChecked' . $id . ' = false;
2490
2491 function playPause' . $id . '() {
2492 if (playing' . $id . ') {
2493 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2494 x' . $id . '.pause();
2495 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2496 playing' . $id . ' = false;
2497 } else {
2498 x' . $id . '.muted = false;
2499 x' . $id . '.play().then(function() {
2500 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2501 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2502 playing' . $id . ' = true;
2503 }).catch(function(e) {
2504 console.log("Play failed:", e);
2505 });
2506 }
2507 }
2508
2509 function audionEnd' . $id . '() {
2510 playing' . $id . ' = false;
2511 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2512 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2513 }
2514
2515 x' . $id . '.addEventListener("ended", audionEnd' . $id . ');';
2516
2517 if ($autoplay_bg_music == 'on') {
2518 $html .= '
2519
2520 x' . $id . '.addEventListener("loadeddata", function() {
2521 if (!autoplayChecked' . $id . ') {
2522 checkAutoplayStatus' . $id . '();
2523 }
2524 });
2525
2526 x' . $id . '.addEventListener("canplay", function() {
2527 if (!autoplayChecked' . $id . ') {
2528 checkAutoplayStatus' . $id . '();
2529 }
2530 });
2531
2532 x' . $id . '.addEventListener("canplaythrough", function() {
2533 if (!autoplayChecked' . $id . ') {
2534 checkAutoplayStatus' . $id . '();
2535 }
2536 });
2537
2538 setTimeout(function() {
2539 if (!autoplayChecked' . $id . ') {
2540 checkAutoplayStatus' . $id . '();
2541 }
2542 }, 1000);
2543
2544 x' . $id . '.addEventListener("play", function() {
2545 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2546 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2547 playing' . $id . ' = true;
2548 });
2549
2550 x' . $id . '.addEventListener("pause", function() {
2551 if (!playing' . $id . ') {
2552 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2553 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2554 }
2555 });
2556
2557 function checkAutoplayStatus' . $id . '() {
2558 autoplayChecked' . $id . ' = true;
2559
2560 x' . $id . '.muted = true;
2561 var playPromise = x' . $id . '.play();
2562
2563 if (playPromise !== undefined) {
2564 playPromise.then(function () {
2565 if (x' . $id . '.muted || x' . $id . '.volume === 0) {
2566 handleAutoplayBlocked' . $id . '();
2567 } else {
2568 autoplaySupported' . $id . ' = true;
2569 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2570 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2571 playing' . $id . ' = true;
2572 }
2573 }).catch(function () {
2574 handleAutoplayBlocked' . $id . '();
2575 });
2576 } else {
2577 setTimeout(function () {
2578 if (x' . $id . '.paused || x' . $id . '.currentTime === 0) {
2579 handleAutoplayBlocked' . $id . '();
2580 } else {
2581 autoplaySupported' . $id . ' = true;
2582 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2583 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2584 playing' . $id . ' = true;
2585 }
2586 }, 300);
2587 }
2588 }
2589
2590 function handleAutoplayBlocked' . $id . '() {
2591 autoplaySupported' . $id . ' = false;
2592 if (!alertShown' . $id . ') {
2593 alert("Autoplay is not supported in your browser. Please click the audio button to play music.");
2594 alertShown' . $id . ' = true;
2595 }
2596
2597 x' . $id . '.pause();
2598 x' . $id . '.currentTime = 0;
2599 x' . $id . '.muted = true;
2600
2601 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2602 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2603
2604 document.getElementById("pano' . $id . '").addEventListener("click", musicPlay' . $id . ');
2605 document.addEventListener("touchstart", musicPlay' . $id . ', { once: true });
2606 document.addEventListener("click", musicPlay' . $id . ', { once: true });
2607 }
2608
2609 function musicPlay' . $id . '() {
2610 x' . $id . '.muted = false;
2611 var playPromise = x' . $id . '.play();
2612
2613 if (playPromise !== undefined) {
2614 playPromise.then(function () {
2615 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2616 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2617 playing' . $id . ' = true;
2618 }).catch(function(e) {
2619 console.log("Play failed:", e);
2620 });
2621 } else {
2622 setTimeout(function () {
2623 if (!x' . $id . '.paused) {
2624 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2625 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2626 playing' . $id . ' = true;
2627 }
2628 }, 100);
2629 }
2630
2631 document.getElementById("pano' . $id . '").removeEventListener("click", musicPlay' . $id . ');
2632 document.removeEventListener("touchstart", musicPlay' . $id . ');
2633 document.removeEventListener("click", musicPlay' . $id . ');
2634 }
2635 ';
2636 }
2637 }
2638 $html .= 'jQuery(document).ready(function() {';
2639 $html .= 'var response = ' . $response . ';';
2640 $html .= 'var scenes = response[1];';
2641 $html .= 'if(scenes) {';
2642 $html .= 'var scenedata = scenes.scenes;';
2643 $html .= 'for(var i in scenedata) {';
2644 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2645 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2646 $html .= 'if(scenehotspot[i].type === "info") {';
2647 $html .= ' scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2648 $html .= '} else if(scenehotspot[i].type === "scene") {';
2649 $html .= ' scenehotspot[i]["clickHandlerArgs"] = scenehotspot[i]["text"];';
2650 $status = get_option('wpvr_edd_license_status');
2651 if ($status !== false && $status == 'valid') {
2652 $html .='if(typeof wpvr_public !== "undefined" && wpvr_public.is_pro_active) {';
2653 $html .= ' scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof wpvrhotspotscene === "function") { wpvrhotspotscene(div, args); } else if (typeof window.wpvrhotspotscene === "function") { window.wpvrhotspotscene(div, args); } };';
2654 $html .='}';
2655 }
2656 $html .= '}';
2657 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2658 } else {
2659 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2660 $html .= 'scenehotspot[i]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2661 $html .= '}';
2662 }
2663 $html .= '}';
2664 $html .= '}';
2665 $html .= '}';
2666 $html .= 'var panoshow' . $id . ';';
2667 $html .= 'var panoshow2' . $id . ';';
2668 $html .= 'function initWPVRViewer' . $id . '() {';
2669 $html .= 'if (typeof pannellum === "undefined" || typeof jQuery === "undefined") { setTimeout(initWPVRViewer' . $id . ', 50); return; }';
2670 $html .= 'panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);';
2671 $html .= '
2672 window.wpvrViewers = window.wpvrViewers || {};
2673 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $id . ';
2674 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
2675 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $id . ' }
2676 }));
2677 ';
2678 if ( (float) $scene_fade_duration > 0 ) {
2679 $html .= '
2680 panoshow' . $id . '.on("scenechange", function() {
2681 var fadeImage = document.querySelector("#pano' . $id . ' .pnlm-render-container > .pnlm-fade-img");
2682 if (fadeImage) {
2683 fadeImage.style.opacity = "1";
2684 void fadeImage.offsetWidth;
2685 }
2686 });';
2687 }
2688 $html .= '
2689 if(typeof wpvr_public === "undefined" || !wpvr_public.is_pro_active || !wpvr_public.is_license_active) {
2690 panoshow' . $id . '.on("load", function() {
2691 jQuery(".pnlm-panorama-info").hide();
2692 jQuery(".pnlm-compass").hide();
2693 });
2694
2695 panoshow' . $id . '.on("scenechange", function() {
2696 jQuery(".pnlm-panorama-info").hide();
2697 jQuery(".pnlm-compass").hide();
2698 });
2699 }';
2700 $html .= '}';
2701 $html .= 'initWPVRViewer' . $id . '();';
2702
2703 //===Dplicate mode only for vr mode===//
2704 $response2 = json_decode($response);
2705 $response2[1]->compass = false;
2706 $response2[1]->autoRotate = false;
2707 $response = json_encode($response2);
2708 $html .= 'var response_duplicate = ' . $response . ';';
2709 $html .= 'var scenes_duplicate = response_duplicate[1];';
2710
2711 $html .= 'if(scenes_duplicate) {';
2712 $html .= 'var scenedata = scenes_duplicate.scenes;';
2713 $html .= 'for(var i in scenedata) {';
2714 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2715 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2716 $html .= 'if(scenehotspot[i]["clickHandlerArgs"] != "") {';
2717 $html .= 'scenehotspot[i]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2718 $html .= '}';
2719 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2720 } else {
2721 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2722 $html .= 'scenehotspot[i]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2723 $html .= '}';
2724 }
2725 $html .= '}';
2726 $html .= '}';
2727 $html .= '}';
2728 $html .= 'var vr_mode = "off";';
2729 $status = get_option('wpvr_edd_license_status');
2730 if ($status !== false && 'valid' == $status && $is_pro) {
2731 $html .= 'function initWPVRViewer2' . $id . '() {';
2732 $html .= 'if (typeof pannellum === "undefined" || typeof jQuery === "undefined") { setTimeout(initWPVRViewer2' . $id . ', 50); return; }';
2733 $html .= 'panoshow2' . $id . ' = pannellum.viewer("pano2' . $id . '", scenes_duplicate);';
2734 $html .= '
2735 window.wpvrViewers = window.wpvrViewers || {};
2736 window.wpvrViewers["pano2' . $id . '"] = panoshow2' . $id . ';
2737 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
2738 detail: { containerId: "pano2' . $id . '", viewer: panoshow2' . $id . ' }
2739 }));
2740 ';
2741 $html .= '}';
2742 $html .= 'initWPVRViewer2' . $id . '();';
2743
2744 // Show Cardboard Mode in Tour
2745 $html .= '
2746 var tim;
2747 var im = 0;
2748 var active_scene = "' . $default_scene . '";
2749 var c_time;
2750 c_time = new Date();
2751 var timer = c_time.getTime() + 2000;
2752 function panoShowCardBoardOnTrigger(data){
2753 if(scenes_duplicate) {
2754 var scenedata = scenes_duplicate.scenes;
2755 for(var i in scenedata) {
2756 if(active_scene === i) {
2757 var scenehotspot = scenedata[i].hotSpots;
2758 for(var j in scenehotspot) {
2759 var plusFiveYaw = Math.round(scenehotspot[j].yaw) + 5;
2760 var minusFiveYaw = Math.round(scenehotspot[j].yaw) - 5;
2761 var plusFivePitch = Math.round(scenehotspot[j].pitch) + 5;
2762 var minusFivePitch = Math.round(scenehotspot[j].pitch) - 5;
2763 var firstCondition = ( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ;
2764 var secCondition = (Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw);
2765 if(( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ){
2766 if((Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw)){
2767 jQuery(".center-pointer").addClass("wpvr-pluse-effect")
2768 var getScene = scenehotspot[j].sceneId;
2769 if(scenehotspot[j].type == "scene"){
2770 panoshow' . $id . '.loadScene(getScene);
2771 panoshow2' . $id . '.loadScene(getScene);
2772 // var inside_current_time_object = new Date();
2773 // var inside_timer = inside_current_time_object.getTime();
2774 // if(inside_timer > timer) {
2775 // panoshow' . $id . '.loadScene(getScene);
2776 // panoshow2' . $id . '.loadScene(getScene);
2777 // jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2778 // }
2779 }else{
2780 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2781 }
2782 }
2783 else {
2784 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2785 c_time = new Date();
2786 timer = c_time.getTime() + 2000;
2787 }
2788 }
2789 else {
2790 c_time = new Date();
2791 timer = c_time.getTime() + 2000;
2792 }
2793 }
2794 }
2795 }
2796 }
2797 };
2798
2799 function vrDeviseOrientation(){
2800 var data = {
2801 pitch: panoshow' . $id . '.getPitch(),
2802 yaw: panoshow' . $id . '.getYaw(),
2803 };
2804 panoShowCardBoardOnTrigger(data);
2805 }
2806 ';
2807 $html .= '
2808
2809 function requestFullScreen(){
2810 var elem = document.getElementById("master-container");
2811 if (elem.requestFullscreen) {
2812 elem.requestFullscreen();
2813 } else if (elem.webkitRequestFullscreen) { /* Safari */
2814 elem.webkitRequestFullscreen();
2815 } else if (elem.msRequestFullscreen) { /* IE11 */
2816 elem.msRequestFullscreen();
2817 }
2818 }
2819 function requestExitFullscreen(){
2820 var elem = document.getElementById("master-container");
2821 if (document.exitFullscreen) {
2822 document.exitFullscreen();
2823 } else if (document.webkitExitFullscreen) { /* Safari */
2824 document.webkitExitFullscreen();
2825 } else if (document.msExitFullscreen) { /* IE11 */
2826 document.msExitFullscreen();
2827 }
2828 }
2829 jQuery(document).on("click",".fullscreen-button .expand",function() {
2830 jQuery(this).hide()
2831 jQuery(this).parent().find(".compress").show()
2832 requestFullScreen()
2833 screen.orientation.lock("landscape-primary")
2834 .then(function() {
2835 })
2836 .catch(function(error) {
2837 alert("Not Supported for this devise");
2838 });
2839
2840 });
2841 jQuery(document).on("click",".fullscreen-button .compress",function() {
2842 jQuery(this).hide()
2843 jQuery(this).parent().find(".expand").show()
2844 requestExitFullscreen()
2845 screen.orientation.unlock();
2846
2847 });
2848
2849 let onLoadAnalytics = false;
2850 let sceneLoadAnalytics = false;
2851 function storeAnalyticsData(data) {
2852 if(typeof wpvr_public !== "undefined" && wpvr_public.is_pro_active) {
2853 jQuery.ajax({
2854 url: wpvrAnalyticsObj.ajaxUrl,
2855 type: "POST",
2856 data: {
2857 action: "store_scene_hotspot_data",
2858 scene_id: data.scene_id,
2859 tour_id: data.tour_id,
2860 type: data.type,
2861 hotspot_id: data.hotspot_id || "",
2862 user_agent: navigator.userAgent,
2863 device_type: getDeviceType() || "desktop",
2864 nonce: wpvrAnalyticsObj.nonce,
2865 },
2866 success: function (response) {
2867 console.log("Data stored successfully");
2868 },
2869 error: function (error) {
2870 console.log("Error in storing data");
2871 }
2872 });
2873 }
2874 }
2875
2876 function getDeviceType() {
2877 const userAgent = navigator.userAgent.toLowerCase();
2878
2879 if (/mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent)) {
2880 return "mobile";
2881 } else if (/tablet|ipad/i.test(userAgent)) {
2882 return "tablet";
2883 } else {
2884 return "desktop";
2885 }
2886 }
2887
2888 panoshow' . $id . '.on("scenechange", function(scene) {
2889 onLoadAnalytics = true;
2890 sceneLoadAnalytics = true;
2891 let scene_id = scene;
2892 let tour_id = ' . $id . ';
2893 let type = "scene";
2894 let hotspot_id = "";
2895 let user_agent = navigator.userAgent;
2896 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2897 storeAnalyticsData({
2898 scene_id: scene_id,
2899 tour_id: tour_id,
2900 type: type,
2901 hotspot_id: hotspot_id,
2902 user_agent: user_agent,
2903 device_type: device_type,
2904 });
2905 if(typeof wpvr_public === "undefined" || !wpvr_public.is_pro_active) {
2906 jQuery(".pnlm-panorama-info").hide();
2907 setTimeout(function() {
2908 jQuery(".pnlm-panorama-info").each(function() {
2909 jQuery(this).hide();
2910 });
2911 }, 500);
2912 }
2913 });
2914
2915 panoshow' . $id . '.on("load", function() {
2916 let scene_id = panoshow' . $id . '.getScene();
2917 let tour_id = ' . $id . ';
2918 let type = "scene";
2919 let hotspot_id = "";
2920 let user_agent = navigator.userAgent;
2921 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2922 if(!onLoadAnalytics && !sceneLoadAnalytics){
2923 storeAnalyticsData({
2924 scene_id: scene_id,
2925 tour_id: tour_id,
2926 type: type,
2927 hotspot_id: hotspot_id,
2928 user_agent: user_agent,
2929 device_type: device_type,
2930 });
2931 }
2932 if(typeof wpvr_public === "undefined" || !wpvr_public.is_pro_active) {
2933 jQuery(".pnlm-panorama-info").hide();
2934 setTimeout(function() {
2935 jQuery(".pnlm-panorama-info").each(function() {
2936 jQuery(this).hide();
2937 });
2938 }, 500);
2939 }
2940 })
2941
2942 function wpvrhotspotscene(hotSpotDiv, args) {
2943 onLoadAnalytics = true;
2944 let scene_id = panoshow' . $id . '.getScene();
2945 let tour_id = ' . $id . ';
2946 let type = "hotspot";
2947 let hotspot_id = args;
2948 let user_agent = navigator.userAgent;
2949 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2950 storeAnalyticsData({
2951 scene_id: scene_id,
2952 tour_id: tour_id,
2953 type: type,
2954 hotspot_id: hotspot_id,
2955 user_agent: user_agent,
2956 device_type: device_type
2957 });
2958 }';
2959
2960 $html .= '
2961 panoshow' . $id . '.on("scenechange", function (scene){
2962 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2963 active_scene = scene;
2964 });
2965 var compassBlock = "";
2966 var infoBlock = "";
2967 var getValue = "";
2968 jQuery(document).on("click",".vr_mode_change' . $id . '",function (){
2969
2970 jQuery("#pano2' . $id . ' .pnlm-load-button").trigger("click");
2971 jQuery("#pano' . $id . ' .pnlm-load-button").trigger("click");
2972
2973 getValue = jQuery(this).val();
2974 var getParent = jQuery(this).parent().parent();
2975 var fullWidthParent = getParent.parent();
2976 var compass = getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display");
2977 var panoInfo = getParent.find("#pano' . $id . ' .pnlm-panorama-info").css("display");
2978 if(compass == "block"){
2979 compassBlock = "block";
2980 }
2981 if(panoInfo == "block"){
2982 infoBlock = "block";
2983 }
2984 if (getValue == "off") {
2985 requestFullScreen()
2986 screen.orientation.lock("landscape-primary")
2987 .then(function() {
2988 })
2989 .catch(function(error) {
2990 alert("VR Glass Mode not supported in this device");
2991 });
2992 getParent.find(".pano-wrap").addClass("wpvr-cardboard-disable-event");
2993 // localStorage.setItem("vr_mode", "on");
2994 vr_mode = "on";
2995 jQuery(".vr-mode-title").show();
2996 jQuery(this).val("on");
2997 getParent.find("#pano2' . $id . '").css({
2998 "opacity": "1",
2999 "visibility": "visible",
3000 "position": "relative",
3001 });
3002 gyroSwitch = true;
3003 panoshow' . $id . '.startOrientation();
3004 panoshow2' . $id . '.startOrientation();
3005 panoshow2' . $id . '.setPitch(panoshow' . $id . '.getPitch(), 0);
3006 panoshow2' . $id . '.setYaw(panoshow' . $id . '.getYaw(), 0);
3007 getParent.find("#pano' . $id . ' #zoom-in-out-controls' . $id . '").hide();
3008 getParent.find("#pano' . $id . ' #controls' . $id . '").hide();
3009 getParent.find("#pano' . $id . ' #explainer_button_' . $id . '").hide();
3010 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").hide();
3011 getParent.find("#pano' . $id . ' #floor_map_button_' . $id . '").hide();
3012 getParent.find("#pano' . $id . ' #vrgcontrols' . $id . '").hide();
3013 getParent.find("#pano' . $id . ' #sccontrols' . $id . '").hide();
3014 getParent.find("#pano' . $id . ' #adcontrol' . $id . '").hide();
3015 getParent.find("#pano' . $id . ' .owl-nav.wpvr_slider_nav").hide();
3016 getParent.find("#pano' . $id . ' #cp-logo-controls").hide();
3017
3018 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").hide();
3019
3020 getParent.find("#pano2' . $id . ' .pnlm-controls-container").hide();
3021 getParent.find("#pano' . $id . ' .pnlm-controls-container").hide();
3022
3023 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
3024 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
3025
3026 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").hide();
3027 getParent.find("#pano' . $id . ' .pnlm-panorama-info").hide();
3028 getParent.find("#pano' . $id . '").addClass("cardboard-half");
3029
3030 getParent.find("#center-pointer' . $id . '").show();
3031 getParent.find(".fullscreen-button").hide();
3032
3033
3034 if (window.DeviceOrientationEvent) {
3035 window.addEventListener("deviceorientation", vrDeviseOrientation);
3036 }
3037
3038 panoshow' . $id . '.on("mousemove", function (data){
3039 panoshow2' . $id . '.setPitch(data.pitch, 0);
3040 panoshow2' . $id . '.setYaw(data.yaw, 0);
3041 panoShowCardBoardOnTrigger(data);
3042
3043 });
3044 panoshow2' . $id . '.on("mousemove", function (data){
3045 panoshow2' . $id . '.setPitch(data.pitch, 0);
3046 panoshow' . $id . '.setYaw(data.yaw, 0);
3047 panoShowCardBoardOnTrigger(data);
3048
3049 });
3050
3051 panoshow' . $id . '.on("zoomchange", function (data){
3052 panoshow2' . $id . '.setHfov(data, 0);
3053 });
3054
3055 panoshow2' . $id . '.on("zoomchange", function (data){
3056 panoshow' . $id . '.setHfov(data, 0);
3057 });
3058
3059 panoshow' . $id . '.on("touchmove", function (data){
3060 panoshow' . $id . '.stopOrientation();
3061 panoshow2' . $id . '.stopOrientation();
3062 panoshow2' . $id . '.setPitch(data.pitch, 0);
3063 panoshow2' . $id . '.setYaw(data.yaw, 0);
3064 panoShowCardBoardOnTrigger(data);
3065
3066 });
3067
3068 panoshow2' . $id . '.on("touchmove", function (data){
3069 panoshow' . $id . '.stopOrientation();
3070 panoshow2' . $id . '.stopOrientation();
3071 panoshow' . $id . '.setPitch(data.pitch, 0);
3072 panoshow' . $id . '.setYaw(data.yaw, 0);
3073 panoShowCardBoardOnTrigger(data);
3074
3075 });
3076
3077 }
3078 else if(getValue == "on") {
3079 screen.orientation.unlock();
3080 requestExitFullscreen();
3081 // localStorage.setItem("vr_mode", "off");
3082 vr_mode = "off";
3083 jQuery(".vr-mode-title").hide();
3084 jQuery(this).val("off");
3085 getParent.find("#pano2' . $id . '").css({
3086 "opacity": "0",
3087 "visibility": "hidden",
3088 "position": "absolute",
3089 });
3090 panoshow' . $id . '.stopOrientation();
3091 panoshow2' . $id . '.stopOrientation();
3092 getParent.find(".pano-wrap").removeClass("wpvr-cardboard-disable-event");
3093 getParent.find("#pano' . $id . ' #zoom-in-out-controls' . $id . '").show();
3094 getParent.find("#pano' . $id . ' #controls' . $id . '").show();
3095 getParent.find("#pano' . $id . ' #explainer_button_' . $id . '").show();
3096 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").show();
3097 getParent.find("#pano' . $id . ' #floor_map_button_' . $id . '").show();
3098
3099 getParent.find("#pano2' . $id . ' .pnlm-controls-container").show();
3100 getParent.find("#pano' . $id . ' .pnlm-controls-container").show();
3101 getParent.find("#pano' . $id . ' #vrgcontrols' . $id . '").show();
3102 getParent.find("#pano' . $id . ' #sccontrols' . $id . '").hide();
3103 getParent.find("#pano' . $id . ' #adcontrol' . $id . '").show();
3104 getParent.find("#pano' . $id . ' .owl-nav.wpvr_slider_nav").hide();
3105 getParent.find("#pano' . $id . ' #cp-logo-controls").show();
3106 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").show();
3107
3108 if(compassBlock == "block"){
3109 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
3110 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
3111 }
3112 if(infoBlock == "block"){
3113 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").show();
3114 getParent.find("#pano' . $id . ' .pnlm-panorama-info").show();
3115 }
3116
3117 getParent.find("#pano' . $id . '").removeClass("cardboard-half");
3118 getParent.find("#center-pointer' . $id . '").hide();
3119 getParent.find(".fullscreen-button").hide();
3120 panoshow' . $id . '.off("mousemove");
3121 panoshow' . $id . '.off("touchmove");
3122 panoshow2' . $id . '.off("mousemove");
3123 panoshow2' . $id . '.off("touchmove");
3124 if (window.DeviceOrientationEvent) {
3125 window.removeEventListener("deviceorientation", vrDeviseOrientation);
3126 }
3127 }
3128 });';
3129
3130 $html .= 'panoshow2' . $id . '.on("load", function (){
3131 // if(localStorage.getItem("vr_mode") == "off") {
3132 if( vr_mode == "off") {
3133 jQuery(".vr-mode-title").hide();
3134 }
3135 else {
3136 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
3137 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
3138 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
3139 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
3140 jQuery(".vr-mode-title").show();
3141 }
3142 });';
3143 }
3144
3145 $html .= 'jQuery("#pano' . $id . ' .wpvr-floor-map .floor-plan-pointer").on("click",function(){
3146 var scene_id = jQuery(this).attr("scene_id");
3147 panoshow' . $id . '.loadScene(scene_id)
3148 jQuery(".floor-plan-pointer").removeClass("add-pulse")
3149 jQuery(this).addClass("add-pulse")
3150 });';
3151
3152 if ($scene_animation_enabled && is_plugin_active('wpvr-pro/wpvr-pro.php') ) {
3153 $animation_js = apply_filters('wpvr_scene_animation_js', $id, $animation_type, $animationDuration, $animationDelay);
3154 if (!empty($animation_js)) {
3155 $html .= $animation_js;
3156 $html .= 'panoshow' . $id . '.on("load", function (scene){
3157 if (typeof changeScene === "function") {
3158 changeScene();
3159 } else {
3160 console.warn("changeScene function is not defined.");
3161 }
3162 });';
3163 }
3164 }
3165
3166
3167 $html .= '
3168 panoshow' . $id . '.on("mousemove", function (data){
3169 jQuery(".add-pulse").css({"transform":"rotate("+data.yaw+"deg)"});
3170 });
3171 ';
3172
3173
3174
3175 $status = get_option('wpvr_edd_license_status');
3176 if ($status !== false && 'valid' == $status && $is_pro) {
3177 $html .= 'panoshow' . $id . '.on("scenechange", function (scene){
3178 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
3179 jQuery(".floor-plan-pointer").each(function(index ,element){
3180 var scene_id = jQuery(this).attr("scene_id");
3181 if( active_scene == scene_id ){
3182 jQuery(".floor-plan-pointer").removeClass("add-pulse")
3183 jQuery(this).addClass("add-pulse")
3184 }
3185 });
3186
3187 });';
3188 $html .= 'panoshow' . $id . '.on("load", function (){
3189 if(jQuery(".floor-plan-pointer").length > 0){
3190 jQuery(".floor-plan-pointer").each(function(index ,element){
3191 var scene_id = jQuery(this).attr("scene_id");
3192 if( active_scene == scene_id ){
3193 jQuery(".floor-plan-pointer").removeClass("add-pulse")
3194 jQuery(this).addClass("add-pulse")
3195 }
3196 });
3197 }
3198 });';
3199 }
3200
3201 if ($status !== false && 'valid' == $status && $is_pro) {
3202 $scene_navigation_content_type = isset($postdata['scene_navigation_content_type']) ? $postdata['scene_navigation_content_type'] : 'scene_id';
3203 $html .= '
3204 jQuery("#pano' . $id . ' .custom-scene-navigation").on("click",function(){
3205 jQuery("#custom-scene-navigation-nav' . $id . ' ul").empty()
3206 if(scenes){
3207 var scene_navigation_content_type = ' . "'" . $scene_navigation_content_type . "'" . ';
3208 var sceneList = scenes.scenes;
3209 var getScene = panoshow' . $id . '.getScene();
3210 for (const key in sceneList) {
3211 let title;
3212 if (scene_navigation_content_type === "scene_title") {
3213 if (sceneList[key].title) {
3214 title = sceneList[key].title;
3215
3216 }else{
3217 if(title == "" || title == undefined){
3218 if (sceneList[key].panorama) {
3219 title = getImageNameWithoutExtension(sceneList[key].panorama);
3220 }
3221 }
3222 }
3223 } else if (scene_navigation_content_type === "scene_image_name") {
3224 if (sceneList[key].panorama) {
3225 title = getImageNameWithoutExtension(sceneList[key].panorama);
3226 }
3227 } else {
3228 title = key;
3229 }
3230 if (sceneList.hasOwnProperty(key)) {
3231 if( key === getScene){
3232 jQuery("#custom-scene-navigation-nav' . $id . ' ul").append("<li class=\"scene-navigation-list active\" scene_id= " + key + " >" + title + "</li>");
3233 }else{
3234 jQuery("#custom-scene-navigation-nav' . $id . ' ul").append("<li class=\"scene-navigation-list\" scene_id= " + key + " >" + title + "</li>");
3235 }
3236 }
3237 }
3238 }
3239 jQuery("#custom-scene-navigation-nav' . $id . '").toggleClass("visible");
3240 });
3241 ';
3242
3243 $html .= 'function getImageNameWithoutExtension(imageUrl) {
3244 // Split the URL by "/"
3245 var parts = imageUrl.split("/");
3246
3247 // Get the last part which contains the image name
3248 var imageNameWithExtension = parts[parts.length - 1];
3249
3250 // Split the image name by period (.)
3251 var imageNameParts = imageNameWithExtension.split(".");
3252
3253 // Remove the last part (which is the extension) and join the remaining parts
3254 var imageNameWithoutExtension = imageNameParts.slice(0, -1).join(".");
3255
3256 // Return the image name without extension
3257 return imageNameWithoutExtension;
3258 }';
3259
3260
3261 $html .= '
3262 jQuery("#pano' . $id . ' #custom-scene-navigation-nav' . $id . ' ul").on("click", "li.scene-navigation-list", function() {
3263 if (scenes) {
3264 jQuery(this).siblings("li").removeClass("active");
3265 jQuery(this).addClass("active");
3266
3267 var scene_key = jQuery(this).attr("scene_id");
3268 panoshow' . $id . '.loadScene(scene_key);
3269 }
3270 });
3271 ';
3272 }
3273
3274 //Duplicate mode only for vr mode end===//
3275 $html .= 'panoshow' . $id . '.on("load", function (){
3276
3277 // if(localStorage.getItem("vr_mode") == "off") {
3278 if( vr_mode == "off") {
3279 jQuery(".vr-mode-title").hide();
3280 }
3281 else {
3282 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
3283 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
3284 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
3285 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
3286 jQuery(".vr-mode-title").show();
3287 }
3288
3289
3290 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3291 jQuery("#controls' . $id . '").css("bottom", "80px");
3292 }
3293 else {
3294 jQuery("#controls' . $id . '").css("bottom", "5px");
3295 }
3296 });';
3297
3298
3299 $html .= '
3300 if (scenes.autoRotate) {
3301 var wpvrAutoRotateTimer' . $id . ' = null;
3302 var wpvrAutoRotateStopDelay' . $id . ' = parseInt(scenes.autoRotateStopDelay, 10) || 0;
3303 var wpvrScheduleAutoRotate' . $id . ' = function () {
3304 clearTimeout(wpvrAutoRotateTimer' . $id . ');
3305 if (wpvrAutoRotateStopDelay' . $id . ' > 0) {
3306 wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
3307 panoshow' . $id . '.stopAutoRotate();
3308 }, wpvrAutoRotateStopDelay' . $id . ');
3309 } else {
3310 wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
3311 panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0);
3312 }, 3000);
3313 }
3314 };
3315 panoshow' . $id . '.on("load", wpvrScheduleAutoRotate' . $id . ');
3316 panoshow' . $id . '.on("scenechange", wpvrScheduleAutoRotate' . $id . ');
3317 }
3318 ';
3319 $html .= 'var touchtime = 0;';
3320 if ($vrgallery) {
3321 if (isset($panodata["scene-list"])) {
3322 foreach ($panodata["scene-list"] as $panoscenes) {
3323 $scene_key = $panoscenes['scene-id'];
3324 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $id;
3325 $img_src_url = $panoscenes['scene-attachment-url'];
3326 // $html .= 'document.getElementById("' . $scene_key_gallery . '").addEventListener("click", function(e) { ';
3327 // $html .= 'if (touchtime == 0) {';
3328 // $html .= 'touchtime = new Date().getTime();';
3329 // $html .= '} else {';
3330 // $html .= 'if (((new Date().getTime()) - touchtime) < 800) {';
3331 // $html .= 'panoshow' . $id . '.loadScene("' . $scene_key . '");';
3332 // $html .= 'touchtime = 0;';
3333 // $html .= '} else {';
3334 // $html .= 'touchtime = new Date().getTime();';
3335 // $html .= '}';
3336 // $html .= '}';
3337 // $html .= '});';
3338 $html .= '
3339 jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
3340 panoshow' . $id . '.loadScene("' . $scene_key . '");
3341 });
3342 ';
3343 }
3344 }
3345
3346 $html .= '
3347 var owlGallery' . $id . ' = jQuery("#sccontrols' . $id . '").owlCarousel({
3348 items: 1,
3349 loop: true,
3350 nav: false,
3351 dots: false,
3352 margin: 5,
3353 stagePadding: 30
3354 });
3355 jQuery("#pano' . $id . '").on("click", ".wpvr_owl_prev", function() {
3356 owlGallery' . $id . '.trigger("prev.owl.carousel");
3357 });
3358 jQuery("#pano' . $id . '").on("click", ".wpvr_owl_next", function() {
3359 owlGallery' . $id . '.trigger("next.owl.carousel");
3360 });
3361 ';
3362 }
3363
3364
3365
3366 //===Custom Control===//
3367 if (isset($custom_control)) {
3368 if ($custom_control['panupSwitch'] == "on" && $status == 'valid' && $is_pro) {
3369 $html .= 'document.getElementById("pan-up' . $id . '").addEventListener("click", function(e) {';
3370 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() + 10);';
3371 $html .= '});';
3372 }
3373
3374 if ($custom_control['panDownSwitch'] == "on" && $status == 'valid' && $is_pro) {
3375 $html .= 'document.getElementById("pan-down' . $id . '").addEventListener("click", function(e) {';
3376 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() - 10);';
3377 $html .= '});';
3378 }
3379
3380 if ($custom_control['panLeftSwitch'] == "on" && $status == 'valid' && $is_pro) {
3381 $html .= 'document.getElementById("pan-left' . $id . '").addEventListener("click", function(e) {';
3382 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() - 10);';
3383 $html .= '});';
3384 }
3385
3386 if ($custom_control['panRightSwitch'] == "on" && $status == 'valid' && $is_pro) {
3387 $html .= 'document.getElementById("pan-right' . $id . '").addEventListener("click", function(e) {';
3388 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() + 10);';
3389 $html .= '});';
3390 }
3391
3392 if ($custom_control['panZoomInSwitch'] == "on") {
3393 $html .= 'document.getElementById("zoom-in' . $id . '").addEventListener("click", function(e) {';
3394 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() - 10);';
3395 $html .= '});';
3396 }
3397
3398 if ($custom_control['panZoomOutSwitch'] == "on") {
3399 $html .= 'document.getElementById("zoom-out' . $id . '").addEventListener("click", function(e) {';
3400 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() + 10);';
3401 $html .= '});';
3402 }
3403
3404 if ($custom_control['panFullscreenSwitch'] == "on" && $status == 'valid' && $is_pro) {
3405 $html .= 'document.getElementById("fullscreen' . $id . '").addEventListener("click", function(e) {';
3406 $html .= 'panoshow' . $id . '.toggleFullscreen();';
3407 $html .= '});';
3408 $html .= '(function() {';
3409 $html .= 'function wpvrFsChange' . $id . '() {';
3410 $html .= 'var fsIcon = document.querySelector("#fullscreen' . $id . ' i");';
3411 $html .= 'if (!fsIcon) return;';
3412 $html .= 'if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {';
3413 $html .= 'fsIcon.classList.remove("fa-expand"); fsIcon.classList.add("fa-minimize");';
3414 $html .= '} else {';
3415 $html .= 'fsIcon.classList.remove("fa-minimize"); fsIcon.classList.add("fa-expand");';
3416 $html .= '}';
3417 $html .= '}';
3418 $html .= 'document.addEventListener("fullscreenchange", wpvrFsChange' . $id . ');';
3419 $html .= 'document.addEventListener("webkitfullscreenchange", wpvrFsChange' . $id . ');';
3420 $html .= 'document.addEventListener("mozfullscreenchange", wpvrFsChange' . $id . ');';
3421 $html .= 'document.addEventListener("MSFullscreenChange", wpvrFsChange' . $id . ');';
3422 $html .= '})();';
3423 }
3424
3425 if ($custom_control['backToHomeSwitch'] == "on" && $status == 'valid' && $is_pro) {
3426 $html .= 'document.getElementById("backToHome' . $id . '").addEventListener("click", function(e) {';
3427 $html .= 'panoshow' . $id . '.loadScene("' . $default_scene . '");';
3428 $html .= '});';
3429 }
3430
3431 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
3432 $html .= '
3433 (function() {
3434 var gyroButton = document.getElementById("gyroscope' . $id . '");
3435 var gyroIcon = gyroButton ? gyroButton.querySelector("i") : null;
3436 var activeColor = ' . wp_json_encode($custom_control['gyroscopeColor']) . ';
3437 var permissionGranted = false;
3438
3439 if (!gyroButton || !gyroIcon) {
3440 return;
3441 }
3442
3443 function updateGyroscopeState() {
3444 gyroIcon.style.color = panoshow' . $id . '.isOrientationActive()
3445 ? activeColor
3446 : "red";
3447 }
3448
3449 function startGyroscope() {
3450 if (!panoshow' . $id . '.isOrientationSupported()) {
3451 updateGyroscopeState();
3452 return;
3453 }
3454
3455 panoshow' . $id . '.startOrientation();
3456 window.setTimeout(updateGyroscopeState, 0);
3457 }
3458
3459 function requestGyroscopePermission() {
3460 var orientationEvent = window.DeviceOrientationEvent;
3461 if (orientationEvent) {
3462 if (typeof orientationEvent.requestPermission === "function") {
3463 if (!permissionGranted) {
3464 orientationEvent.requestPermission()
3465 .then(function(state) {
3466 permissionGranted = state === "granted";
3467 if (permissionGranted) {
3468 startGyroscope();
3469 } else {
3470 updateGyroscopeState();
3471 }
3472 })
3473 .catch(updateGyroscopeState);
3474 return;
3475 }
3476 }
3477 }
3478
3479 startGyroscope();
3480 }
3481
3482 panoshow' . $id . '.on("load", updateGyroscopeState);
3483 panoshow' . $id . '.on("scenechange", updateGyroscopeState);
3484
3485 gyroButton.addEventListener("click", function() {
3486 if (panoshow' . $id . '.isOrientationActive()) {
3487 panoshow' . $id . '.stopOrientation();
3488 updateGyroscopeState();
3489 return;
3490 }
3491
3492 requestGyroscopePermission();
3493 });
3494 })();';
3495 }
3496 }
3497
3498 $angle_up = '<i class="fa fa-angle-up"></i>';
3499 $angle_down = '<i class="fa fa-angle-down"></i>';
3500 $sin_qout = "'";
3501
3502 //===Explainer Script===//
3503 $html .= '
3504 jQuery(document).on("click","#explainer_button_' . $id . '",function() {
3505 jQuery("#explainer' . $id . '").slideToggle(function(){
3506 var $explainerVideoId = jQuery("#explainer' . $id . '");
3507 var $explainerVideoIframe = $explainerVideoId.find("iframe");
3508 var explainerVideoIframSrc = $explainerVideoIframe.attr("src");
3509 $explainerVideoIframe.attr("src", "");
3510 $explainerVideoIframe.attr("src", explainerVideoIframSrc);
3511 });
3512 });
3513
3514 jQuery(document).on("click", ".close-explainer-video", function() {
3515 var $explainer = jQuery(this).parent(".explainer");
3516 var $iframe = $explainer.find("iframe");
3517 var src = $iframe.attr("src");
3518 $iframe.attr("src", "");
3519 $explainer.hide();
3520 $iframe.attr("src", src);
3521 });
3522
3523 jQuery(document).on("click","#pano' . $id . '",function(event) {
3524 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3525 var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3526 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3527 if( isActiveModal == null && isForm == null && isHotspot == null){
3528 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3529 jQuery(".custom-ifram-wrapper").hide();
3530 jQuery(this).removeClass("show-modal");
3531 jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3532 }else if(isForm != null){
3533 jQuery(this).addClass("show-modal");
3534 }
3535 });
3536
3537 ';
3538 //===Explainer Script End===//
3539
3540 //===generic form script===//
3541 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on') {
3542 $html .= '
3543 jQuery(document).on("click","#generic_form_button_' . $id . '",function() {
3544 jQuery("#wpvr-generic-form' . $id . '").fadeToggle();
3545 });
3546
3547 jQuery(document).on("click",".close-generic-form",function() {
3548 jQuery(this).parent(".wpvr-generic-form").fadeOut()
3549 });
3550 ';
3551 }
3552
3553 //===generic from script===//
3554
3555 //===Floor map Script===//
3556 $html .= '
3557 jQuery(document).on("click","#floor_map_button_' . $id . '",function() {
3558 jQuery("#wpvr-floor-map' . $id . '").toggle().removeClass("fullwindow");
3559 });
3560
3561 jQuery(document).on("dblclick","#wpvr-floor-map' . $id . '",function(){
3562 jQuery(this).addClass("fullwindow");
3563 jQuery(this).parents(".pano-wrap").addClass("show-modal");
3564 });
3565
3566 jQuery(document).on("click",".close-floor-map-plan",function() {
3567 jQuery(this).parent(".wpvr-floor-map").hide();
3568 jQuery(this).parent(".wpvr-floor-map").removeClass("fullwindow");
3569 jQuery(this).parents(".pano-wrap").removeClass("show-modal");
3570 });
3571
3572 ';
3573 //===Floor map Script End===//
3574
3575 if ($vrgallery_display) {
3576 if (!$autoload) {
3577 $html .= '
3578 jQuery(document).ready(function($){
3579 jQuery("#sccontrols' . $id . '").hide();
3580 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3581 jQuery("#sccontrols' . $id . '").hide();
3582 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3583 });
3584 ';
3585
3586 $html .= '
3587 var slide' . $id . ' = "down";
3588 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3589
3590 if (slide' . $id . ' == "up") {
3591 jQuery(".vrgctrl' . $id . '").empty();
3592 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3593 slide' . $id . ' = "down";
3594 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3595 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3596 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3597 if (jQuery(this).is(":visible")) {
3598 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3599 "display": "flex",
3600 "justify-content": "center",
3601 "align-items": "center",
3602 "gap": "15px"
3603 });
3604 }
3605 }
3606 if (jQuery(".bricks-is-frontend").length) {
3607 if (jQuery(this).is(":visible")) {
3608 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3609 "display": "flex",
3610 "justify-content": "center",
3611 "align-items": "center"
3612 });
3613 }
3614 }
3615 });
3616 }
3617 else {
3618 jQuery(".vrgctrl' . $id . '").empty();
3619 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3620 slide' . $id . ' = "up";
3621 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3622 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3623 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3624 if (jQuery(this).is(":visible")) {
3625 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3626 "display": "flex",
3627 "justify-content": "center",
3628 "align-items": "center",
3629 "gap": "15px"
3630 });
3631 }
3632 }
3633 if (jQuery(".bricks-is-frontend").length) {
3634 if (jQuery(this).is(":visible")) {
3635 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3636 "display": "flex",
3637 "justify-content": "center",
3638 "align-items": "center"
3639 });
3640 }
3641 }
3642 });
3643 }
3644 });
3645 ';
3646 } else {
3647 $html .= '
3648 jQuery(document).ready(function($){
3649 jQuery("#sccontrols' . $id . '").show();
3650 jQuery("#pano' . $id . ' .wpvr_slider_nav").show();
3651 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3652 });
3653 ';
3654
3655 $html .= '
3656 var slide' . $id . ' = "down";
3657 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3658
3659 if (slide' . $id . ' == "up") {
3660 jQuery(".vrgctrl' . $id . '").empty();
3661 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3662 slide' . $id . ' = "down";
3663 }
3664 else {
3665 jQuery(".vrgctrl' . $id . '").empty();
3666 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3667 slide' . $id . ' = "up";
3668 }
3669 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3670 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3671 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3672 if (jQuery(this).is(":visible")) {
3673 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3674 "display": "flex",
3675 "justify-content": "center",
3676 "align-items": "center",
3677 "gap": "15px"
3678 });
3679 }
3680 }
3681 if (jQuery(".bricks-is-frontend").length) {
3682 if (jQuery(this).is(":visible")) {
3683 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3684 "display": "flex",
3685 "justify-content": "center",
3686 "align-items": "center"
3687 });
3688 }
3689 }
3690 });
3691 });
3692 ';
3693 }
3694 } else {
3695 $html .= '
3696 jQuery(document).ready(function($){
3697 jQuery("#sccontrols' . $id . '").hide();
3698 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3699 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3700 });
3701 ';
3702
3703 $html .= '
3704 var slide' . $id . ' = "down";
3705 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3706
3707 if (slide' . $id . ' == "up") {
3708 jQuery(".vrgctrl' . $id . '").empty();
3709 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3710 slide' . $id . ' = "down";
3711 }
3712 else {
3713 jQuery(".vrgctrl' . $id . '").empty();
3714 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3715 slide' . $id . ' = "up";
3716 }
3717 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3718 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3719 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3720 if (jQuery(this).is(":visible")) {
3721 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3722 "display": "flex",
3723 "justify-content": "center",
3724 "align-items": "center",
3725 "gap": "15px"
3726 });
3727 }
3728 }
3729 if (jQuery(".bricks-is-frontend").length) {
3730 if (jQuery(this).is(":visible")) {
3731 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3732 "display": "flex",
3733 "justify-content": "center",
3734 "align-items": "center"
3735 });
3736 }
3737 }
3738 });
3739 });
3740 ';
3741 }
3742
3743 if (!$autoload) {
3744 $html .= '
3745
3746 jQuery(document).ready(function(){
3747 jQuery("#controls' . $id . '").hide();
3748 jQuery("#zoom-in-out-controls' . $id . '").hide();
3749 jQuery("#adcontrol' . $id . '").hide();
3750 jQuery("#explainer_button_' . $id . '").hide();
3751 jQuery("#generic_form_button_' . $id . '").hide();
3752 jQuery("#floor_map_button_' . $id . '").hide();
3753 jQuery("#vrgcontrols' . $id . '").hide();
3754 jQuery("#cp-logo-controls").hide();
3755 jQuery(".custom-scene-navigation").hide();
3756 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").hide();
3757 });
3758
3759 ';
3760
3761 if ($vrgallery_display) {
3762 $html .= 'var load_once = "true";';
3763 $html .= 'panoshow' . $id . '.on("load", function (){
3764 if (load_once == "true") {
3765 load_once = "false";
3766 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3767 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3768 if (jQuery(this).is(":visible")) {
3769 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css("display", "flex");
3770 }
3771 }
3772 if (jQuery(".bricks-is-frontend").length) {
3773 if (jQuery(this).is(":visible")) {
3774 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3775 "display": "flex",
3776 "justify-content": "center",
3777 "align-items": "center"
3778 });
3779 }
3780 }
3781 });
3782 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3783 }
3784 });';
3785 }
3786
3787 $html .= 'panoshow' . $id . '.on("load", function (){
3788 jQuery("#controls' . $id . '").show();
3789 jQuery("#zoom-in-out-controls' . $id . '").show();
3790 jQuery("#adcontrol' . $id . '").show();
3791 jQuery("#explainer_button_' . $id . '").show();
3792 jQuery("#generic_form_button_' . $id . '").show();
3793 jQuery("#floor_map_button_' . $id . '").show();
3794 jQuery("#vrgcontrols' . $id . '").show();
3795 jQuery("#cp-logo-controls").show();
3796 jQuery(".custom-scene-navigation").show();
3797 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").show();
3798 });';
3799 }
3800
3801 $previewText = $postdata['previewtext'] ?? 'Click To Load Panorama';
3802 if ($previewText) {
3803 $html .= '
3804 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previewText. '")
3805 ';
3806 } else {
3807 $html .= '
3808 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("Click To Load Panorama")
3809 ';
3810 }
3811
3812 $html .= 'jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseenter", function(){
3813 jQuery(this).attr("title", jQuery(this).text());
3814 });
3815 jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseleave", function(){
3816 jQuery(this).removeAttr("title");
3817 });';
3818 $html .= '});';
3819 $html .= '</script>';
3820
3821 $tour_data = [];
3822 if(defined("WPVR_PRO_VERSION")){
3823 $tour_data = array(
3824 'explainerControlSwitch' => (
3825 isset( $postdata['explainerSwitch'] )
3826 && in_array( $postdata['explainerSwitch'], array( true, 1, '1', 'on' ), true )
3827 ) ? 'on' : 'off',
3828 'floor_plan_enable' => $floor_plan_enable ?? false,
3829 'floor_plan_image' => $floor_plan_image ?? '',
3830 'custom_control' => $custom_control ?? [],
3831 );
3832 }
3833 return apply_filters('wpvr_generate_tour_layout_html', $html ,$postdata ,$id, $tour_data);
3834 }
3835
3836 function sanitize_content_preserve_styles($content, $allow_forms = false) {
3837 // Decode HTML entities first (in case content was encoded in database)
3838 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3839
3840 // Escape <script> blocks to display as text instead of removing them
3841 $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3842 return esc_html($matches[0]); // Convert to plain text
3843 }, $content);
3844
3845 // Strip dangerous URL-based attributes
3846 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3847
3848 // Escape inline event handlers (onclick, onhover, etc.) to display as text
3849 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*(["\'])([^"\']*)\2/i', function($matches) {
3850 // Escape the attribute value but keep the attribute name visible as text
3851 return ' ' . esc_html($matches[1]) . '=' . $matches[2] . esc_html($matches[3]) . $matches[2];
3852 }, $content);
3853 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*([^>\s]+)/i', function($matches) {
3854 // Handle unquoted event handlers
3855 return ' ' . esc_html($matches[1]) . '=' . esc_html($matches[2]);
3856 }, $content);
3857
3858 // Remove unsafe embedded/interactive elements
3859 if ($allow_forms) {
3860 $content = preg_replace('/<(object|embed|applet|frame|frameset|meta|link|base)\b[^>]*>/i', '', $content);
3861 $content = preg_replace('/<\/(object|embed|applet|frame|frameset|meta|link|base)>/i', '', $content);
3862 } else {
3863 $content = preg_replace('/<(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)\b[^>]*>/i', '', $content);
3864 $content = preg_replace('/<\/(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)>/i', '', $content);
3865 }
3866
3867 // Clean style attributes safely
3868 $content = preg_replace_callback('/style\s*=\s*["\']([^"\']*)["\']/', function($matches) {
3869 $style = $matches[1];
3870 $style = preg_replace('/expression\s*\(/i', '', $style);
3871 $style = preg_replace('/(javascript|vbscript|data|about)\s*:/i', '', $style);
3872 $style = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $style);
3873 $style = preg_replace('/behavior\s*:/i', '', $style);
3874 $style = preg_replace('/-moz-binding\s*:/i', '', $style);
3875 return 'style="' . esc_attr($style) . '"';
3876 }, $content);
3877
3878 // Sanitize <style> blocks
3879 $content = preg_replace_callback('/<style\b[^>]*>(.*?)<\/style>/si', function($matches) {
3880 $css = $matches[1];
3881 $css = preg_replace('/(expression|javascript|vbscript|data|about)\s*:/i', '', $css);
3882 $css = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $css);
3883 $css = preg_replace('/behavior\s*:/i', '', $css);
3884 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3885 return '<style>' . esc_html($css) . '</style>';
3886 }, $content);
3887
3888 // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3889 $allowed_tags = wp_kses_allowed_html('post');
3890 $allowed_tags['iframe'] = [
3891 'src' => true,
3892 'width' => true,
3893 'height' => true,
3894 'frameborder' => true,
3895 'allowfullscreen' => true,
3896 'class' => true,
3897 'style' => true,
3898 'title' => true,
3899 'allow' => true,
3900 'name' => true,
3901 'referrerpolicy' => true,
3902 'loading' => true,
3903 'sandbox' => true,
3904 ];
3905 $allowed_tags['img'] = [
3906 'src' => true,
3907 'alt' => true,
3908 'title' => true,
3909 'width' => true,
3910 'height' => true,
3911 'class' => true,
3912 'id' => true,
3913 'style' => true,
3914 'loading' => true,
3915 'srcset' => true,
3916 'sizes' => true,
3917 ];
3918
3919 if ($allow_forms) {
3920 $form_attributes = [
3921 'id' => true,
3922 'class' => true,
3923 'style' => true,
3924 'name' => true,
3925 'value' => true,
3926 'type' => true,
3927 'placeholder' => true,
3928 'action' => true,
3929 'method' => true,
3930 'target' => true,
3931 'enctype' => true,
3932 'disabled' => true,
3933 'readonly' => true,
3934 'required' => true,
3935 'checked' => true,
3936 'selected' => true,
3937 'multiple' => true,
3938 'size' => true,
3939 'rows' => true,
3940 'cols' => true,
3941 'maxlength' => true,
3942 'minlength' => true,
3943 'min' => true,
3944 'max' => true,
3945 'step' => true,
3946 'pattern' => true,
3947 'autocomplete'=> true,
3948 'autofocus' => true,
3949 'for' => true,
3950 ];
3951 $allowed_tags['form'] = $form_attributes;
3952 $allowed_tags['input'] = $form_attributes;
3953 $allowed_tags['button'] = $form_attributes;
3954 $allowed_tags['textarea'] = $form_attributes;
3955 $allowed_tags['select'] = $form_attributes;
3956 $allowed_tags['option'] = $form_attributes;
3957 $allowed_tags['optgroup'] = $form_attributes;
3958 $allowed_tags['label'] = $form_attributes;
3959 $allowed_tags['fieldset'] = $form_attributes;
3960 $allowed_tags['legend'] = $form_attributes;
3961 }
3962
3963 // Apply wp_kses() to keep only allowed tags/attributes
3964 $content = wp_kses($content, $allowed_tags);
3965
3966 // Finally, validate iframe src for security (allow https only, block javascript: etc.)
3967 $content = preg_replace_callback('/<iframe[^>]+src=["\']([^"\']+)["\'][^>]*>(?:<\/iframe>)?/i', function($matches) {
3968 $src = $matches[1];
3969 // Allow any https:// or http:// URL, but block javascript:, data:, vbscript:, etc.
3970 if (preg_match('/^(https?:)?\/\//i', $src) && !preg_match('/^(javascript|data|vbscript|about):/i', $src)) {
3971 return $matches[0]; // keep safe iframe
3972 }
3973 // Strip unsafe iframe
3974 return '';
3975 }, $content);
3976
3977 return $content;
3978 }
3979 function wpvr_hex2rgb($colour)
3980 {
3981 if (isset($colour[0]) && $colour[0] == '#') {
3982 $colour = substr($colour, 1);
3983 }
3984 if (strlen($colour) == 6) {
3985 list($r, $g, $b) = array($colour[0] . $colour[1], $colour[2] . $colour[3], $colour[4] . $colour[5]);
3986 } elseif (strlen($colour) == 3) {
3987 list($r, $g, $b) = array($colour[0] . $colour[0], $colour[1] . $colour[1], $colour[2] . $colour[2]);
3988 } else {
3989 return false;
3990 }
3991 $r = hexdec($r);
3992 $g = hexdec($g);
3993 $b = hexdec($b);
3994 return array($r . ', ' . $g . ', ' . $b);
3995 }
3996
3997 function wpvr_HTMLToRGB($htmlCode)
3998 {
3999 $r = 0;
4000 $g = 0;
4001 $b = 0;
4002 if (isset($htmlCode[0]) && $htmlCode[0] == '#') {
4003 $htmlCode = substr($htmlCode, 1);
4004 }
4005
4006 if (strlen($htmlCode) == 3) {
4007 $htmlCode = $htmlCode[0] . $htmlCode[0] . $htmlCode[1] . $htmlCode[1] . $htmlCode[2] . $htmlCode[2];
4008 }
4009
4010 if (isset($htmlCode[0]) && isset($htmlCode[1])) {
4011 $r = hexdec($htmlCode[0] . $htmlCode[1]);
4012 }
4013 if (isset($htmlCode[2]) && isset($htmlCode[3])) {
4014 $g = hexdec($htmlCode[2] . $htmlCode[3]);
4015 }
4016 if (isset($htmlCode[4]) && isset($htmlCode[5])) {
4017 $b = hexdec($htmlCode[4] . $htmlCode[5]);
4018 }
4019
4020 return $b + ($g << 0x8) + ($r << 0x10);
4021 }
4022
4023 function wpvr_RGBToHSL($RGB)
4024 {
4025 $r = 0xFF & ($RGB >> 0x10);
4026 $g = 0xFF & ($RGB >> 0x8);
4027 $b = 0xFF & $RGB;
4028
4029 $r = ((float)$r) / 255.0;
4030 $g = ((float)$g) / 255.0;
4031 $b = ((float)$b) / 255.0;
4032
4033 $maxC = max($r, $g, $b);
4034 $minC = min($r, $g, $b);
4035
4036 $l = ($maxC + $minC) / 2.0;
4037
4038 if ($maxC == $minC) {
4039 $s = 0;
4040 $h = 0;
4041 } else {
4042 if ($l < .5) {
4043 $s = ($maxC - $minC) / ($maxC + $minC);
4044 } else {
4045 $s = ($maxC - $minC) / (2.0 - $maxC - $minC);
4046 }
4047 if ($r == $maxC) {
4048 $h = ($g - $b) / ($maxC - $minC);
4049 }
4050 if ($g == $maxC) {
4051 $h = 2.0 + ($b - $r) / ($maxC - $minC);
4052 }
4053 if ($b == $maxC) {
4054 $h = 4.0 + ($r - $g) / ($maxC - $minC);
4055 }
4056
4057 $h = $h / 6.0;
4058 }
4059
4060 $h = (int)round(255.0 * $h);
4061 $s = (int)round(255.0 * $s);
4062 $l = (int)round(255.0 * $l);
4063
4064 return (object) array('hue' => $h, 'saturation' => $s, 'lightness' => $l);
4065 }
4066
4067 add_action('rest_api_init', 'wpvr_rest_data_route');
4068 function wpvr_rest_data_route()
4069 {
4070 register_rest_route('wpvr/v1', '/panodata/', array(
4071 'methods' => 'GET',
4072 'callback' => 'wpvr_rest_data_set',
4073 'permission_callback' => 'wpvr_rest_route_permission'
4074 ));
4075 }
4076
4077 function wpvr_rest_route_permission()
4078 {
4079 return true;
4080 }
4081
4082 function wpvr_rest_data_set()
4083 {
4084 $query = new WP_Query(array(
4085 'post_type' => 'wpvr_item',
4086 'posts_per_page' => -1,
4087 ));
4088
4089 $wpvr_list = array();
4090 $list_none = array('value' => 0, 'label' => 'None');
4091 array_push($wpvr_list, $list_none);
4092 while ($query->have_posts()) {
4093 $query->the_post();
4094 $title = mb_convert_encoding(get_the_title(), 'UTF-8', 'HTML-ENTITIES');
4095 $post_id = get_the_ID();
4096 $title = $post_id . ' : ' . $title;
4097 $list_ob = array('value' => $post_id, 'label' => $title);
4098 array_push($wpvr_list, $list_ob);
4099 }
4100
4101 return $wpvr_list;
4102 }
4103
4104 function wpvr_isMobileDevice()
4105 {
4106 return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $_SERVER["HTTP_USER_AGENT"]);
4107 }
4108
4109 function wpvr_directory()
4110 {
4111 $upload = wp_upload_dir();
4112 $upload_dir = $upload['basedir'];
4113 $upload_dir_temp = $upload_dir . '/wpvr/temp/';
4114 if (!is_dir($upload_dir_temp)) {
4115 wp_mkdir_p($upload_dir_temp, 0700);
4116 }
4117 }
4118
4119 add_action('admin_init', 'wpvr_directory');
4120
4121
4122 function wpvr_add_role_cap()
4123 {
4124 $editor_active = get_option('wpvr_editor_active');
4125
4126 $author_active = get_option('wpvr_author_active');
4127
4128 $admin = get_role('administrator');
4129 $admin->add_cap('publish_wpvr_tour');
4130 $admin->add_cap('edit_wpvr_tours');
4131 $admin->add_cap('read_wpvr_tour');
4132 $admin->add_cap('edit_wpvr_tour');
4133 $admin->add_cap('edit_wpvr_tours');
4134 $admin->add_cap('publish_wpvr_tours');
4135 $admin->add_cap('publish_wpvr_tour');
4136 $admin->add_cap('delete_wpvr_tour');
4137 $admin->add_cap('edit_other_wpvr_tours');
4138 $admin->add_cap('delete_other_wpvr_tours');
4139
4140 if ($editor_active == "true") {
4141 $editor = get_role('editor');
4142 if ($editor) {
4143 $editor->add_cap('publish_wpvr_tour');
4144 $editor->add_cap('edit_wpvr_tours');
4145 $editor->add_cap('read_wpvr_tour');
4146 $editor->add_cap('edit_wpvr_tour');
4147 $editor->add_cap('edit_wpvr_tours');
4148 $editor->add_cap('publish_wpvr_tours');
4149 $editor->add_cap('publish_wpvr_tour');
4150 $editor->add_cap('delete_wpvr_tour');
4151 $editor->add_cap('edit_other_wpvr_tours');
4152 $editor->add_cap('delete_other_wpvr_tours');
4153 }
4154 } else {
4155 $editor = get_role('editor');
4156 if ($editor) {
4157 $editor->remove_cap('publish_wpvr_tour');
4158 $editor->remove_cap('edit_wpvr_tours');
4159 $editor->remove_cap('read_wpvr_tour');
4160 $editor->remove_cap('edit_wpvr_tour');
4161 $editor->remove_cap('edit_wpvr_tours');
4162 $editor->remove_cap('publish_wpvr_tours');
4163 $editor->remove_cap('publish_wpvr_tour');
4164 $editor->remove_cap('delete_wpvr_tour');
4165 $editor->remove_cap('edit_other_wpvr_tours');
4166 $editor->remove_cap('delete_other_wpvr_tours');
4167 }
4168 }
4169
4170 if ($author_active == "true") {
4171 $author = get_role('author');
4172 if ($author) {
4173 $author->add_cap('read_wpvr_tour');
4174 $author->add_cap('edit_wpvr_tour');
4175 $author->add_cap('edit_wpvr_tours');
4176 $author->add_cap('publish_wpvr_tours');
4177 $author->add_cap('publish_wpvr_tour');
4178 $author->add_cap('delete_wpvr_tour');
4179 }
4180 } else {
4181 $author = get_role('author');
4182 if ($author) {
4183 $author->remove_cap('read_wpvr_tour');
4184 $author->remove_cap('edit_wpvr_tour');
4185 $author->remove_cap('edit_wpvr_tours');
4186 $author->remove_cap('publish_wpvr_tours');
4187 $author->remove_cap('publish_wpvr_tour');
4188 $author->remove_cap('delete_wpvr_tour');
4189 }
4190 }
4191
4192 if(is_plugin_active( 'dokan-lite/dokan.php' ) || is_plugin_active( 'dokan-pro/dokan.php' )){
4193 $dokan_vendor_active = get_option('dokan_vendor_active');
4194
4195 if( 'true' === $dokan_vendor_active){
4196 $seller = get_role('seller');
4197 if ($seller) {
4198 $seller->add_cap('read_wpvr_tour');
4199 $seller->add_cap('edit_wpvr_tour');
4200 $seller->add_cap('edit_wpvr_tours');
4201 $seller->add_cap('publish_wpvr_tours');
4202 $seller->add_cap('publish_wpvr_tour');
4203 $seller->add_cap('delete_wpvr_tour');
4204 }
4205 } else{
4206 $seller = get_role('seller');
4207 if ($seller) {
4208 $seller->remove_cap('read_wpvr_tour');
4209 $seller->remove_cap('edit_wpvr_tour');
4210 $seller->remove_cap('edit_wpvr_tours');
4211 $seller->remove_cap('publish_wpvr_tours');
4212 $seller->remove_cap('publish_wpvr_tour');
4213 $seller->remove_cap('delete_wpvr_tour');
4214 }
4215 }
4216 }
4217
4218
4219 }
4220
4221 add_action('admin_init', 'wpvr_add_role_cap', 999);
4222
4223 function wpvr_role_management_from_post_type($args, $post_type)
4224 {
4225 if ('wpvr_item' !== $post_type) {
4226 return $args;
4227 }
4228
4229 $editor_active = get_option('wpvr_editor_active');
4230 $author_active = get_option('wpvr_author_active');
4231 $user = wp_get_current_user();
4232
4233 if ($editor_active == "true") {
4234 if (in_array('editor', (array) $user->roles)) {
4235 $args['show_in_menu'] = true;
4236 }
4237 }
4238
4239 if ($author_active == "true") {
4240 if (in_array('author', (array) $user->roles)) {
4241 $args['show_in_menu'] = true;
4242 }
4243 }
4244
4245 if(is_plugin_active( 'dokan-lite/dokan.php' ) || is_plugin_active( 'dokan-pro/dokan.php' )){
4246 $dokan_vendor_active = get_option('dokan_vendor_active');
4247 if( 'true' === $dokan_vendor_active){
4248 if (in_array('seller', (array) $user->roles)) {
4249 $args['show_in_menu'] = true;
4250 }
4251 }
4252
4253 }
4254
4255 return $args;
4256 }
4257 add_filter('register_post_type_args', 'wpvr_role_management_from_post_type', 10, 2);
4258
4259 function wpvr_cache_admin_notice()
4260 {
4261 $option = get_option('wpvr_warning');
4262 if (!$option) {
4263 ?>
4264 <div class="notice notice-warning" id="wpvr-warning" style="position: relative;">
4265 <p><?php _e('Since you have updated the plugin, please clear the browser cache for smooth functioning. Follow these steps if you are using <a href="https://support.google.com/accounts/answer/32050?co=GENIE.Platform%3DDesktop&hl=en" target="_blank">Google Chrome</a>, <a href="https://support.mozilla.org/en-US/kb/how-clear-firefox-cache" target="_blank">Mozilla Firefox</a>, <a href="https://clear-my-cache.com/en/apple-mac-os/safari.html" target="_blank">Safai</a> or <a href="https://support.microsoft.com/en-us/help/10607/microsoft-edge-view-delete-browser-history" target="_blank">Microsoft Edge</a>', 'wpvr'); ?></p>
4266 <button type="button" id="wpvr-dismissible" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
4267 </div>
4268 <?php
4269 }
4270 }
4271 // add_action('admin_notices', 'wpvr_cache_admin_notice');
4272
4273 //===Oxygen widget===//
4274 add_action('plugins_loaded', function () {
4275 if (!class_exists('OxyEl')) {
4276 return;
4277 }
4278 require_once __DIR__ . '/oxygen/oxy-manager.php';
4279 });
4280
4281 add_action('init', 'wpvr_mobile_media_handle');
4282 function wpvr_mobile_media_handle()
4283 {
4284 add_image_size('wpvr_mobile', 4096, 2048); //mobile
4285 }
4286
4287
4288 add_action(
4289 /**
4290 * @param $api \VisualComposer\Modules\Api\Factory
4291 */
4292 'vcv:api',
4293 function ($api) {
4294 $elementsToRegister = [
4295 'wpvrelement',
4296 ];
4297 $pluginBaseUrl = rtrim(plugins_url(basename(__DIR__)), '\\/');
4298 /** @var \VisualComposer\Modules\Elements\ApiController $elementsApi */
4299 $elementsApi = $api->elements;
4300 foreach ($elementsToRegister as $tag) {
4301 $manifestPath = __DIR__ . '/vc/' . $tag . '/manifest.json';
4302 $elementBaseUrl = $pluginBaseUrl . '/vc/' . $tag;
4303 $elementsApi->add($manifestPath, $elementBaseUrl);
4304 }
4305 }
4306 );
4307
4308 function wpvr_redirect_after_activation($plugin)
4309 {
4310 if ($plugin == plugin_basename(__FILE__)) {
4311 $url = admin_url('admin.php?page=rex-wpvr-setup-wizard');
4312 $url = esc_url($url, FILTER_SANITIZE_URL);
4313 exit(wp_safe_redirect($url));
4314 }
4315 }
4316 //add_action('activated_plugin', 'wpvr_redirect_after_activation');
4317
4318 function replace_callback($matches)
4319 {
4320 foreach ($matches as $match) {
4321 return str_replace('<img', '<img decoding="async" ', $match);
4322 }
4323 }
4324
4325
4326 function wpvr_get_explainer_embed_url( $input ) {
4327 $url = esc_url_raw( trim( (string) $input ), array( 'http', 'https' ) );
4328
4329 if ( empty( $url ) || ! preg_match( '#^https?://#i', $url ) ) {
4330 return '';
4331 }
4332
4333 $host = strtolower( (string) wp_parse_url( $url, PHP_URL_HOST ) );
4334 $host = preg_replace( '/^www\./', '', $host );
4335 $path = trim( (string) wp_parse_url( $url, PHP_URL_PATH ), '/' );
4336
4337 if ( 'youtu.be' === $host ) {
4338 $segments = explode( '/', $path );
4339 $video_id = isset( $segments[0] ) ? preg_replace( '/[^A-Za-z0-9_-]/', '', $segments[0] ) : '';
4340
4341 return $video_id ? 'https://www.youtube.com/embed/' . $video_id : '';
4342 }
4343
4344 if ( in_array( $host, array( 'youtube.com', 'm.youtube.com', 'music.youtube.com', 'youtube-nocookie.com' ), true ) ) {
4345 $video_id = '';
4346 $segments = explode( '/', $path );
4347
4348 if ( 'watch' === $path ) {
4349 $query = array();
4350 wp_parse_str( (string) wp_parse_url( $url, PHP_URL_QUERY ), $query );
4351 $video_id = isset( $query['v'] ) ? $query['v'] : '';
4352 } elseif ( isset( $segments[0], $segments[1] ) && in_array( $segments[0], array( 'embed', 'shorts', 'live' ), true ) ) {
4353 $video_id = $segments[1];
4354 }
4355
4356 $video_id = preg_replace( '/[^A-Za-z0-9_-]/', '', (string) $video_id );
4357
4358 return $video_id ? 'https://www.youtube.com/embed/' . $video_id : '';
4359 }
4360
4361 if ( 'vimeo.com' === $host || 'player.vimeo.com' === $host ) {
4362 $segments = array_reverse( array_filter( explode( '/', $path ) ) );
4363
4364 foreach ( $segments as $segment ) {
4365 if ( ctype_digit( $segment ) ) {
4366 return 'https://player.vimeo.com/video/' . $segment;
4367 }
4368 }
4369
4370 return '';
4371 }
4372
4373 return $url;
4374 }
4375
4376 function wpvr_sanitize_iframe_only( $input ) {
4377 // Start with standard allowed post HTML (p, a, strong, etc.)
4378 $allowed_tags = wp_kses_allowed_html( 'post' );
4379
4380 // Explicitly allow <iframe> with specific safe attributes
4381 $allowed_tags['iframe'] = array(
4382 'src' => true,
4383 'width' => true,
4384 'height' => true,
4385 'title' => true,
4386 'frameborder' => true,
4387 'allow' => true,
4388 'allowfullscreen' => true,
4389 'referrerpolicy' => true,
4390 );
4391
4392 $content = trim( (string) $input );
4393
4394 if ( '' === $content ) {
4395 return '';
4396 }
4397
4398 if ( false === stripos( $content, '<iframe' ) ) {
4399 $embed_url = wpvr_get_explainer_embed_url( $content );
4400
4401 if ( $embed_url ) {
4402 $content = sprintf(
4403 '<iframe src="%s" width="100%%" height="100%%" title="Explainer video" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe>',
4404 esc_url( $embed_url )
4405 );
4406 }
4407 }
4408
4409 return wp_kses( $content, $allowed_tags );
4410 }
4411