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

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

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