PluginProbe
WP VR – 360 Panorama and Virtual Tour Builder / 8.5.68
WP VR – 360 Panorama and Virtual Tour Builder v8.5.68
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 8.5.40 All 220 releases
wpvr / wpvr.php

wpvr.php in WP VR – 360 Panorama and Virtual Tour Builder 8.5.68, at wpvr.php

3,863 lines 179.5 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.68
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.68');
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
526
527 $html = '';
528 $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;">';
529
530 // Compatibility check script
531 $html .= '<script>
532 function wpvr_check_360_support() {
533 var support = {
534 supported: false,
535 fullySupported: false,
536 webgl: false,
537 orientation: false,
538 gyroscope: false,
539 touch: false,
540 browser: "unknown",
541 isMobile: false,
542 isIPhone: false,
543 details: []
544 };
545
546 support.isMobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
547 support.isIPhone = /iPhone/i.test(navigator.userAgent);
548 if (support.isMobile) support.details.push("Mobile device detected");
549 if (support.isIPhone) support.details.push("iPhone detected");
550
551 var ua = navigator.userAgent;
552 if (/^((?!chrome|android).)*safari/i.test(ua)) {
553 support.browser = "safari";
554 support.details.push("Safari browser detected");
555 } else if (ua.indexOf("Chrome") > -1) {
556 support.browser = "chrome";
557 support.details.push("Chrome browser detected");
558 } else if (ua.indexOf("Firefox") > -1) {
559 support.browser = "firefox";
560 support.details.push("Firefox browser detected");
561 } else if (ua.indexOf("MSIE") > -1 || ua.indexOf("Trident") > -1) {
562 support.browser = "ie";
563 support.details.push("Internet Explorer detected");
564 } else if (ua.indexOf("Edge") > -1 || ua.indexOf("Edg") > -1) {
565 support.browser = "edge";
566 support.details.push("Edge browser detected");
567 } else if (ua.indexOf("Opera") > -1 || ua.indexOf("OPR") > -1) {
568 support.browser = "opera";
569 support.details.push("Opera browser detected");
570 }
571
572 try {
573 var canvas = document.createElement("canvas");
574 support.webgl = !!(window.WebGLRenderingContext &&
575 (canvas.getContext("webgl") || canvas.getContext("experimental-webgl")));
576 support.details.push(support.webgl ? "WebGL supported" : "WebGL not supported");
577 } catch (e) {
578 support.webgl = false;
579 support.details.push("WebGL detection error: " + e.message);
580 }
581
582 support.orientation = !!(window.DeviceOrientationEvent);
583 support.details.push(support.orientation ? "Device Orientation API supported" : "Device Orientation API not supported");
584
585 support.gyroscope = !!window.Gyroscope;
586 support.details.push(support.gyroscope ? "Gyroscope supported" : "Gyroscope not supported");
587
588 support.touch = "ontouchstart" in window || navigator.maxTouchPoints > 0;
589 support.details.push(support.touch ? "Touch supported" : "Touch not supported");
590
591 support.supported = support.webgl;
592 support.fullySupported = support.webgl && ((support.isMobile && support.orientation) || !support.isMobile);
593
594 if (support.browser === "safari" && support.isIPhone) {
595 support.browserWarning = "iPhone has limited support for 360 videos in browser. The experience may not be optimal.";
596 support.fullySupported = false;
597 } else if (support.browser === "ie") {
598 support.browserWarning = "Internet Explorer has limited support for 360 videos.";
599 support.fullySupported = false;
600 } else if (!support.supported) {
601 support.browserWarning = "Your browser does not support 360° videos. Use Chrome or Firefox with WebGL.";
602 }
603
604 return support;
605 }
606 </script>';
607
608 $random_id = 'video-container-' . rand(10000, 99999);
609 $html .= '<div id="' . $random_id . '-container" style="position:relative; width:100%; height:100%;">';
610
611 // Compatibility check screen (initially hidden for all, will show only for iPhone)
612 $html .= '<div id="' . $random_id . '-compatibility-check" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:#f9f9f9; border-radius:' . esc_attr( $radius ) . ';">
613 <div style="margin-bottom:20px; text-align:center;">
614 <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>
615 <p style="margin:0;">Checking browser compatibility...</p>
616 </div>
617 </div>';
618
619 // Spinner animation
620 $html .= '<style>@keyframes wpvr-spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>';
621
622 // Iframe (initial display set to block)
623 $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;">';
624 $html .= '<iframe id="' . $random_id . '-iframe" src="https://www.youtube.com/embed/' . rawurlencode(sanitize_text_field($expdata)) . '?rel=0&modestbranding=1' . esc_attr($loop) . '&autohide=1' . esc_attr($muted) . '&showinfo=0&controls=1' . esc_attr($autoplay) . esc_attr($playlist) . '&enablejsapi=1" width="100%" height="100%" style="border-radius: ' . esc_attr($radius) . ';" frameborder="0" allowfullscreen allow="accelerometer; gyroscope; picture-in-picture"></iframe>';
625 $html .= '</div>';
626
627 // Permission request (mobile only)
628 $html .= '<div id="' . $random_id . '-permission-request" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.7); color:white; text-align:center; border-radius:' . esc_attr( $radius ) . ';">';
629 $html .= '<p style="font-size:16px; margin:0 20px 15px;">For the best 360° video experience on mobile</p>';
630 $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>';
631 $html .= '</div>';
632
633 // Browser warning
634 $html .= '<div id="' . $random_id . '-browser-warning" style="position:absolute; top:0; left:0; width:100%; height:100%; display:none; flex-direction:column; justify-content:center; align-items:center; background-color:rgba(0,0,0,0.7); color:white; text-align:center; border-radius:' . esc_attr( $radius ) . ';">';
635 $html .= '<p id="' . $random_id . '-warning-text" style="font-size:16px; margin:0 20px 5px;"></p>';
636 $html .= '<p style="font-size:14px; margin:5px 20px 15px;">For the best experience, use Chrome or Firefox.</p>';
637 $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>';
638 $html .= '</div>';
639
640 // Main script
641 $html .= '<script>
642 document.addEventListener("DOMContentLoaded", function() {
643 var supportInfo = wpvr_check_360_support();
644 var compatibilityCheck = document.getElementById("' . $random_id . '-compatibility-check");
645 var frameContainer = document.getElementById("' . $random_id . '-frame");
646 var warning = document.getElementById("' . $random_id . '-browser-warning");
647 var warningText = document.getElementById("' . $random_id . '-warning-text");
648 var continueBtn = document.getElementById("' . $random_id . '-browser-continue");
649
650 // Only show compatibility check and warning for iPhone
651 if (supportInfo.isIPhone) {
652 // Hide the iframe initially for iPhone
653 frameContainer.style.display = "none";
654
655 // Show compatibility check for iPhone
656 compatibilityCheck.style.display = "flex";
657
658 // After delay, hide compatibility check and show warning
659 setTimeout(function() {
660 compatibilityCheck.style.display = "none";
661 warningText.textContent = supportInfo.browserWarning || "Your browser may not fully support 360° videos.";
662 warning.style.display = "flex";
663
664 continueBtn.addEventListener("click", function() {
665 warning.style.display = "none";
666
667 if (supportInfo.fullySupported && supportInfo.isMobile) {
668 document.getElementById("' . $random_id . '-permission-request").style.display = "flex";
669 document.getElementById("' . $random_id . '-permission-button").addEventListener("click", function() {
670 requestDevicePermissions();
671 });
672 } else {
673 showVideo();
674 }
675 });
676 }, 1000);
677 } else {
678 // For non-iPhone devices, directly initialize the player
679 initializeYouTubePlayer();
680 }
681
682 function requestDevicePermissions() {
683 try {
684 if (typeof DeviceOrientationEvent !== "undefined" &&
685 typeof DeviceOrientationEvent.requestPermission === "function") {
686 DeviceOrientationEvent.requestPermission().then(function(response) {
687 if (response === "granted") {
688 if (typeof DeviceMotionEvent !== "undefined" &&
689 typeof DeviceMotionEvent.requestPermission === "function") {
690 DeviceMotionEvent.requestPermission().then(showVideo).catch(showVideo);
691 } else {
692 showVideo();
693 }
694 } else {
695 showVideo();
696 }
697 }).catch(showVideo);
698 } else {
699 showVideo();
700 }
701 } catch (e) {
702 showVideo();
703 }
704 }
705
706 function showVideo() {
707 document.getElementById("' . $random_id . '-permission-request").style.display = "none";
708 frameContainer.style.display = "block";
709 initializeYouTubePlayer();
710 }
711
712 function initializeYouTubePlayer() {
713 if (window.YT) {
714 initPlayer();
715 } else {
716 var tag = document.createElement("script");
717 tag.src = "https://www.youtube.com/iframe_api";
718 var firstScriptTag = document.getElementsByTagName("script")[0];
719 firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
720 window.onYouTubeIframeAPIReady = initPlayer;
721 }
722
723 function initPlayer() {
724 new YT.Player("' . $random_id . '-iframe", {
725 events: {
726 "onReady": function(event) {}
727 }
728 });
729 }
730 }
731 });
732 </script>';
733
734 $html .= '</div>'; // Close container
735 $html .= '</div>'; // Close outer wrapper
736 } else {
737 $html = '';
738 $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;">';
739 $html .= '<div style="width:100%; height:100%; border-radius: ' . esc_attr($radius) . ';">' . wp_kses(
740 $postdata['panoviddata'],
741 array(
742 'video' => array(
743 'id' => array(),
744 'class' => array(),
745 'src' => array(),
746 'controls' => array(),
747 'autoplay' => array(),
748 'loop' => array(),
749 'muted' => array(),
750 'poster' => array(),
751 'preload' => array(),
752 'width' => array(),
753 'height' => array(),
754 'style' => array(),
755 'playsinline' => array(),
756 'crossorigin' => array(),
757 'data-*' => true,
758 ),
759 'source' => array(
760 'src' => array(),
761 'type' => array(),
762 ),
763 'track' => array(
764 'kind' => array(),
765 'src' => array(),
766 'srclang' => array(),
767 'label' => array(),
768 'default' => array(),
769 ),
770 'div' => array(
771 'id' => array(),
772 'class' => array(),
773 'style' => array(),
774 'data-*' => true,
775 ),
776 'span' => array(
777 'id' => array(),
778 'class' => array(),
779 'style' => array(),
780 ),
781 'button' => array(
782 'id' => array(),
783 'class' => array(),
784 'style' => array(),
785 'type' => array(),
786 'title' => array(),
787 ),
788 )
789 ) . '</div>';
790
791 $html .= '
792 <style>
793 .video-js {
794 border-radius:' . esc_attr($radius) . ';
795 }
796 .video-js canvas{
797 border-radius:' . esc_attr($radius) . ';
798 }
799 #pano' . esc_attr($id) . ' .vjs-poster {
800 border-radius: ' . esc_attr($radius) . ';
801 }
802 </style>
803
804 ';
805
806 // $html .= '<script>';
807 // $html .= 'videojs(' . $postdata['vidid'] . ', {';
808 // $html .= 'plugins: {';
809 // $html .= 'pannellum: {}';
810 // $html .= '}';
811 // $html .= '});';
812 // $html .= '</script>';
813 $html .= '</div>';
814
815 //video js vr setup //
816 $html .= '<script>';
817 $html .= '
818 (function (window, videojs) {
819 var player = window.player = videojs("' . $postdata['vidid'] . '");
820 player.mediainfo = player.mediainfo || {};
821 player.mediainfo.projection = "equirectangular";
822
823 // AUTO is the default and looks at mediainfo
824 var vr = window.vr = player.vr({ projection: "AUTO", debug: true, forceCardboard: false, antialias: false });
825 }(window, window.videojs));
826
827 ';
828 $html .= '</script>';
829 //video js vr end //
830 }
831 return $html;
832 }
833
834 $control = false;
835 if (isset($postdata['showControls'])) {
836 $control = $postdata['showControls'];
837 }
838
839 if ($control) {
840 if (isset($postdata['customcontrol'])) {
841 $custom_control = $postdata['customcontrol'];
842 $custom_control['gyroSwitch'] = isset($postdata['gyro']) && $postdata['gyro'] ? 'on' : 'off';
843 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") {
844 $control = false;
845 }
846 }
847 }
848
849 $floor_plan_enable = 'off';
850 $floor_plan_image = '';
851 if (isset($postdata['floor_plan_tour_enabler']) && $postdata['floor_plan_tour_enabler'] == 'on') {
852 $floor_plan_enable = $postdata['floor_plan_tour_enabler'];
853 if (isset($postdata['floor_plan_attachment_url']) && !empty($postdata['floor_plan_attachment_url'])) {
854 $floor_plan_image = $postdata['floor_plan_attachment_url'];
855 }
856 }
857
858 $vrgallery = false;
859 if (isset($postdata['vrgallery'])) {
860 $vrgallery = $postdata['vrgallery'];
861 }
862
863 $vrgallery_title = false;
864 if (isset($postdata['vrgallery_title'])) {
865 $vrgallery_title = $postdata['vrgallery_title'];
866 }
867
868 $vrgallery_display = false;
869 if (isset($postdata['vrgallery_display'])) {
870 $vrgallery_display = $postdata['vrgallery_display'];
871 }
872 $vrgallery_icon_size = false;
873 if (isset($postdata['vrgallery_icon_size'])) {
874 $vrgallery_icon_size = $postdata['vrgallery_icon_size'];
875 }
876
877 $gyro = false;
878 $gyro_orientation = false;
879 if (isset($postdata['gyro'])) {
880 $gyro = $postdata['gyro'];
881 if (isset($postdata['deviceorientationcontrol'])) {
882 $gyro_orientation = $postdata['deviceorientationcontrol'];
883 }
884 }
885
886 $compass = false;
887 $audio_right = "5px";
888 if (isset($postdata['compass'])) {
889 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
890 if ($compass) {
891 $audio_right = "60px";
892 }
893 }
894 $floor_map_right = "25px";
895 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
896 $floor_map_right = "85px";
897 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
898 $floor_map_right = "55px";
899 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
900 $floor_map_right = "25px";
901 }
902
903 //===explainer handle===//
904
905 //===explainer handle===//
906 $explainer_right = "10px";
907 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
908 $explainer_right = "130px";
909 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on' && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
910 $explainer_right = "100px";
911 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
912 $explainer_right = "55px";
913 } elseif ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
914 $explainer_right = "80px";
915 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
916 $explainer_right = "55px";
917 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
918 $explainer_right = "30px";
919 } elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image)) {
920 $explainer_right = "70px";
921 }
922 $enable_cardboard = '';
923 $is_cardboard = get_option('wpvr_cardboard_disable');
924 if (wpvr_isMobileDevice() && $is_cardboard == 'true') {
925 $enable_cardboard = 'enable-cardboard';
926 $audio_right = "73px";
927 if (isset($postdata['compass'])) {
928 $compass = $postdata['compass'] == 'on' || $postdata['compass'] != null ? true : false;
929 if ($compass) {
930 $audio_right = "130px";
931 }
932 }
933
934 $floor_map_right = "60px";
935 if ((isset($postdata['compass']) && $postdata['compass'] == 'on') && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
936 $floor_map_right = "150px";
937 } elseif (isset($postdata['compass']) && $postdata['compass'] == 'on') {
938 $floor_map_right = "120px";
939 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
940 $floor_map_right = "90px";
941 }
942
943 //===explainer handle===//
944
945 $explainer_right = "65px";
946
947 if ((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on')) {
948 $explainer_right = "150px";
949 } elseif ((isset($postdata['compass']) && $postdata['compass'] == true) && (isset($postdata['bg_music']) && $postdata['bg_music'] == 'on') && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
950 $explainer_right = "180px";
951 } elseif (isset($postdata['compass']) && $postdata['compass'] == true && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
952 $explainer_right = "150px";
953 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on" && ($floor_plan_enable == 'on' && !empty($floor_plan_image))) {
954 $explainer_right = "120px";
955 } elseif (isset($postdata['compass']) && $postdata['compass'] == true) {
956 $explainer_right = "130px";
957 } elseif (isset($postdata['bg_music']) && $postdata['bg_music'] == "on") {
958 $explainer_right = "90px";
959 } elseif ($floor_plan_enable == 'on' && !empty($floor_plan_image)) {
960 $explainer_right = "90px";
961 }
962 }
963
964 //===explainer handle===//
965
966 $mouseZoom = true;
967 if (isset($postdata['mouseZoom'])) {
968 if ($postdata['mouseZoom'] == "off") {
969 $mouseZoom = false;
970 } else {
971 $mouseZoom = true;
972 }
973 }
974
975 $draggable = true;
976 if (isset($postdata['draggable'])) {
977 $draggable = $postdata['draggable'] == 'on' || $postdata['draggable'] != null ? true : false;
978 if ($postdata['draggable'] === 'off') {
979 $draggable = false;
980 }
981 }
982 $diskeyboard = false;
983 if (isset($postdata['diskeyboard'])) {
984 $diskeyboard = $postdata['diskeyboard'] == 'off' || $postdata['diskeyboard'] == null ? false : true;
985 }
986
987 $keyboardzoom = true;
988 if (isset($postdata['keyboardzoom'])) {
989 $keyboardzoom = $postdata['keyboardzoom'];
990 }
991
992 $autoload = false;
993
994 if (isset($postdata['autoLoad'])) {
995 $autoload = $postdata['autoLoad'];
996 }
997
998 $default_scene = '';
999 if (isset($postdata['defaultscene'])) {
1000 $default_scene = $postdata['defaultscene'];
1001 }
1002
1003 $preview = '';
1004 if (isset($postdata['preview'])) {
1005 $preview = $postdata['preview'];
1006 }
1007
1008 $autorotation = '';
1009 if (isset($postdata["autoRotate"])) {
1010 $autorotation = $postdata["autoRotate"];
1011 }
1012 $autorotationinactivedelay = '';
1013 if (isset($postdata["autoRotateInactivityDelay"])) {
1014 $autorotationinactivedelay = $postdata["autoRotateInactivityDelay"];
1015 }
1016 $autorotationstopdelay = '';
1017 if (isset($postdata["autoRotateStopDelay"])) {
1018 $autorotationstopdelay = $postdata["autoRotateStopDelay"];
1019 }
1020
1021 $scene_fade_duration = '';
1022 if (isset($postdata['scenefadeduration'])) {
1023 $scene_fade_duration = $postdata['scenefadeduration'];
1024 }
1025
1026 $panodata = array();
1027 if (isset($postdata['panodata'])) {
1028 $panodata = $postdata['panodata'];
1029 }
1030
1031 $default_zoom_global = 100;
1032 if (isset($postdata['hfov']) && $postdata['hfov'] != '') {
1033 $default_zoom_global = $postdata['hfov'];
1034 }
1035
1036 $min_zoom_global = 50;
1037 if (isset($postdata['minHfov']) && $postdata['minHfov'] != '') {
1038 $min_zoom_global = $postdata['minHfov'];
1039 }
1040
1041 $max_zoom_global = 120;
1042 if (isset($postdata['maxHfov']) && $postdata['maxHfov'] != '') {
1043 $max_zoom_global = $postdata['maxHfov'];
1044 }
1045
1046 $hotspoticoncolor = '#00b4ff';
1047 $hotspotblink = 'on';
1048 $default_data = array();
1049 $default_data = array('firstScene' => $default_scene, 'sceneFadeDuration' => $scene_fade_duration, 'hfov' => $default_zoom_global, 'maxHfov' => $max_zoom_global, 'minHfov' => $min_zoom_global);
1050 $scene_data = array();
1051 if (is_array($panodata) && isset($panodata['scene-list'])) {
1052 if (!empty($panodata['scene-list'])) {
1053 foreach ($panodata['scene-list'] as $panoscenes) {
1054 $scene_ititle = '';
1055 if (isset($panoscenes["scene-ititle"])) {
1056 $scene_ititle = esc_html($panoscenes["scene-ititle"]);
1057 }
1058
1059 $scene_author = '';
1060 if (isset($panoscenes["scene-author"])) {
1061 $scene_author = esc_html($panoscenes["scene-author"]);
1062 }
1063
1064 $scene_author_url = '';
1065 if (isset($panoscenes["scene-author-url"])) {
1066 $scene_author_url = sanitize_text_field($panoscenes["scene-author-url"]);
1067 }
1068
1069 $scene_vaov = 180;
1070 if (isset($panoscenes["scene-vaov"])) {
1071 $scene_vaov = (float)$panoscenes["scene-vaov"];
1072 }
1073
1074 $scene_haov = 360;
1075 if (isset($panoscenes["scene-haov"])) {
1076 $scene_haov = (float)$panoscenes["scene-haov"];
1077 }
1078
1079 $scene_vertical_offset = 0;
1080 if (isset($panoscenes["scene-vertical-offset"])) {
1081 $scene_vertical_offset = (float)$panoscenes["scene-vertical-offset"];
1082 }
1083
1084 $default_scene_pitch = null;
1085 if (isset($panoscenes["scene-pitch"])) {
1086 $default_scene_pitch = (float)$panoscenes["scene-pitch"];
1087 }
1088
1089 $default_scene_yaw = null;
1090 if (isset($panoscenes["scene-yaw"])) {
1091 $default_scene_yaw = (float)$panoscenes["scene-yaw"];
1092 }
1093
1094 $scene_max_pitch = '';
1095 if (isset($panoscenes["scene-maxpitch"])) {
1096 $scene_max_pitch = (float)$panoscenes["scene-maxpitch"];
1097 }
1098
1099
1100 $scene_min_pitch = '';
1101 if (isset($panoscenes["scene-minpitch"])) {
1102 $scene_min_pitch = (float)$panoscenes["scene-minpitch"];
1103 }
1104
1105
1106 $scene_max_yaw = '';
1107 if (isset($panoscenes["scene-maxyaw"])) {
1108 $scene_max_yaw = (float)$panoscenes["scene-maxyaw"];
1109 }
1110
1111
1112 $scene_min_yaw = '';
1113 if (isset($panoscenes["scene-minyaw"])) {
1114 $scene_min_yaw = (float)$panoscenes["scene-minyaw"];
1115 }
1116
1117 $default_zoom = 100;
1118 if (isset($panoscenes["scene-zoom"]) && $panoscenes["scene-zoom"] != '') {
1119 $default_zoom = (int)$panoscenes["scene-zoom"];
1120 } else {
1121 if ($default_zoom_global != '') {
1122 $default_zoom = (int)$default_zoom_global;
1123 }
1124 }
1125
1126
1127 $max_zoom = 120;
1128 if (isset($panoscenes["scene-maxzoom"]) && $panoscenes["scene-maxzoom"] != '') {
1129 $max_zoom = (int)$panoscenes["scene-maxzoom"];
1130 } else {
1131 if ($max_zoom_global != '') {
1132 $max_zoom = (int)$max_zoom_global;
1133 }
1134 }
1135
1136 $min_zoom = 120;
1137 if (isset($panoscenes["scene-minzoom"]) && $panoscenes["scene-minzoom"] != '') {
1138 $min_zoom = (int)$panoscenes["scene-minzoom"];
1139 } else {
1140 if ($min_zoom_global != '') {
1141 $min_zoom = (int)$min_zoom_global;
1142 }
1143 }
1144
1145 $hotspot_datas = array();
1146 if (isset($panoscenes['hotspot-list'])) {
1147 $hotspot_datas = $panoscenes['hotspot-list'];
1148 }
1149
1150 $hotspots = array();
1151
1152 foreach ($hotspot_datas as $hotspot_data) {
1153 $status = get_option('wpvr_edd_license_status');
1154 if ($status !== false && $status == 'valid') {
1155
1156 if (isset($hotspot_data["hotspot-customclass-pro"]) && $hotspot_data["hotspot-customclass-pro"] != 'none') {
1157 $hotspot_data['hotspot-customclass'] = $hotspot_data["hotspot-customclass-pro"] . ' custom-' . $id . '-' . $panoscenes['scene-id'] . '-' . $hotspot_data['hotspot-title'];
1158 }
1159 if (isset($hotspot_data['hotspot-blink'])) {
1160 $hotspotblink = $hotspot_data['hotspot-blink'];
1161 }
1162 }
1163 $hotspot_scene_pitch = '';
1164 if (isset($hotspot_data["hotspot-scene-pitch"])) {
1165 $hotspot_scene_pitch = $hotspot_data["hotspot-scene-pitch"];
1166 }
1167 $hotspot_scene_yaw = '';
1168 if (isset($hotspot_data["hotspot-scene-yaw"])) {
1169 $hotspot_scene_yaw = $hotspot_data["hotspot-scene-yaw"];
1170 }
1171
1172 $hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
1173 $hotspot_content = '';
1174
1175 ob_start();
1176 do_action('wpvr_hotspot_content', $hotspot_data);
1177 $hotspot_content = ob_get_clean();
1178
1179 if (!$hotspot_content) {
1180 $hotspot_content = $hotspot_data["hotspot-content"];
1181 }
1182
1183 if (isset($hotspot_data["wpvr_url_open"][0])) {
1184 $wpvr_url_open = $hotspot_data["wpvr_url_open"][0];
1185 } else {
1186 $wpvr_url_open = "off";
1187 }
1188 $on_hover_content = preg_replace_callback(
1189 '/<p>\s*(<img[^>]*>)\s*<br>\s*<\/p>/i',
1190 function ($matches) {
1191 return $matches[1];
1192 },
1193 $hotspot_data['hotspot-hover'] ?? ''
1194 );
1195
1196 if('fluent_form' !== $hotspot_data["hotspot-type"]){
1197 $on_hover_content = sanitize_content_preserve_styles($on_hover_content ?? '');
1198 $on_click_content = preg_replace_callback('/<img[^>]*>/', "replace_callback", $hotspot_content ?? '');
1199 $on_click_content = sanitize_content_preserve_styles($on_click_content ?? '');
1200 }else{
1201 $on_hover_content = $on_hover_content ?? '';
1202 $on_click_content = $hotspot_content ?? '';
1203 }
1204
1205
1206 $hotspot_shape = 'round';
1207 if (isset($hotspot_data["hotspot-customclass-pro"]) && $hotspot_data["hotspot-customclass-pro"] != 'none') {
1208 $hotspot_shape = isset($hotspot_data["hotspot-shape"]) ? $hotspot_data["hotspot-shape"] : 'round';
1209 }
1210
1211 $hotspot_data_for_on_click=[];
1212 if( ('info' === $hotspot_type || 'fluent_form' === $hotspot_data["hotspot-type"] ) && !empty($on_click_content)){
1213 $hotspot_data_for_on_click = [
1214 'on_click_content' => $on_click_content,
1215 'tour_id' => $id,
1216 'scene_id' => $panoscenes['scene-id'],
1217 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1218 ];
1219 } elseif('info' === $hotspot_type && !empty($hotspot_data["hotspot-url"])){
1220 $hotspot_data_for_on_click = [
1221 'on_click_content' => '',
1222 'tour_id' => $id,
1223 'scene_id' => $panoscenes['scene-id'],
1224 'hotspot_id' => sanitize_html_class($hotspot_data['hotspot-title']),
1225 ];
1226 }
1227
1228 $hotspot_info = array(
1229 'text' => esc_html(sanitize_text_field($hotspot_data['hotspot-title'])),
1230 'pitch' => $hotspot_data['hotspot-pitch'],
1231 'yaw' => $hotspot_data['hotspot-yaw'],
1232 'type' => $hotspot_type,
1233 'cssClass' => $hotspot_data['hotspot-customclass'],
1234 'URL' => $hotspot_data['hotspot-url'],
1235 "wpvr_url_open" => $wpvr_url_open,
1236 "clickHandlerArgs" => $hotspot_data_for_on_click,
1237 'createTooltipArgs' => !empty(trim($on_hover_content)) ? trim($on_hover_content) : '',
1238 "sceneId" => $hotspot_data["hotspot-scene"],
1239 "targetPitch" => (float)$hotspot_scene_pitch,
1240 "targetYaw" => (float)$hotspot_scene_yaw,
1241 'hotspot_type' => $hotspot_data['hotspot-type'],
1242 'hotspot_shape' => $hotspot_shape,
1243 );
1244
1245 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1246
1247 if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1248 unset($hotspot_info["cssClass"]);
1249 }
1250 if (empty($hotspot_data["hotspot-scene"])) {
1251 unset($hotspot_info['targetPitch']);
1252 unset($hotspot_info['targetYaw']);
1253 }
1254 array_push($hotspots, $hotspot_info);
1255 }
1256
1257 $device_scene = $panoscenes['scene-attachment-url'];
1258 $mobile_media_resize = get_option('mobile_media_resize');
1259 $file_accessible = ini_get('allow_url_fopen');
1260 if ($mobile_media_resize == "true" && $device_scene) {
1261 if ($file_accessible == "1") {
1262 $image_info = getimagesize($device_scene);
1263 if ($image_info && $image_info[0] > 4096) {
1264 $src_to_id_for_mobile = '';
1265 $src_to_id_for_desktop = '';
1266 if (wpvr_isMobileDevice()) {
1267 $src_to_id_for_mobile = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1268 if ($src_to_id_for_mobile) {
1269 $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1270 if ($mobile_scene[3]) {
1271 $device_scene = $mobile_scene[0];
1272 }
1273 }
1274 } else {
1275 $src_to_id_for_desktop = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1276 if ($src_to_id_for_desktop) {
1277 $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1278 if ($desktop_scene && $desktop_scene[0]) {
1279 $device_scene = $desktop_scene[0];
1280 }
1281 }
1282 }
1283 }
1284 }
1285 }
1286
1287 $scene_info = array();
1288
1289 if ($panoscenes["scene-type"] == 'cubemap') {
1290 $pano_type = 'cubemap';
1291 $pano_attachment = array(
1292 $panoscenes["scene-attachment-url-face0"],
1293 $panoscenes["scene-attachment-url-face1"],
1294 $panoscenes["scene-attachment-url-face2"],
1295 $panoscenes["scene-attachment-url-face3"],
1296 $panoscenes["scene-attachment-url-face4"],
1297 $panoscenes["scene-attachment-url-face5"]
1298 );
1299
1300 $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);
1301 } else {
1302 $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);
1303 }
1304
1305
1306
1307 if (isset($panoscenes["ptyscene"])) {
1308 if ($panoscenes["ptyscene"] == "off") {
1309 unset($scene_info['pitch']);
1310 unset($scene_info['yaw']);
1311 }
1312 }
1313
1314 if (empty($panoscenes["scene-ititle"])) {
1315 unset($scene_info['title']);
1316 }
1317 if (empty($panoscenes["scene-author"])) {
1318 unset($scene_info['author']);
1319 }
1320 if (empty($panoscenes["scene-author-url"])) {
1321 unset($scene_info['authorURL']);
1322 }
1323
1324 if (empty($scene_vaov)) {
1325 unset($scene_info['vaov']);
1326 }
1327
1328 if (empty($scene_haov)) {
1329 unset($scene_info['haov']);
1330 }
1331
1332 if (empty($scene_vertical_offset)) {
1333 unset($scene_info['vOffset']);
1334 }
1335
1336 if (isset($panoscenes["cvgscene"])) {
1337 if ($panoscenes["cvgscene"] == "off") {
1338 unset($scene_info['maxPitch']);
1339 unset($scene_info['minPitch']);
1340 }
1341 }
1342 if (empty($panoscenes["scene-maxpitch"])) {
1343 unset($scene_info['maxPitch']);
1344 }
1345
1346 if (empty($panoscenes["scene-minpitch"])) {
1347 unset($scene_info['minPitch']);
1348 }
1349
1350 if (isset($panoscenes["chgscene"])) {
1351 if ($panoscenes["chgscene"] == "off") {
1352 unset($scene_info['maxYaw']);
1353 unset($scene_info['minYaw']);
1354 }
1355 }
1356 if (empty($panoscenes["scene-maxyaw"])) {
1357 unset($scene_info['maxYaw']);
1358 }
1359
1360 if (empty($panoscenes["scene-minyaw"])) {
1361 unset($scene_info['minYaw']);
1362 }
1363
1364 // if (isset($panoscenes["czscene"])) {
1365 // if ($panoscenes["czscene"] == "off") {
1366 // unset($scene_info['hfov']);
1367 // unset($scene_info['maxHfov']);
1368 // unset($scene_info['minHfov']);
1369 // }
1370 // }
1371
1372 $scene_array = array();
1373 $scene_array = array(
1374 $panoscenes['scene-id'] => $scene_info
1375 );
1376
1377 $scene_data[$panoscenes['scene-id']] = $scene_info;
1378 }
1379 }
1380 }
1381 $pano_id_array = array();
1382 $pano_id_array = array('panoid' => $panoid);
1383 $pano_response = array();
1384 $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);
1385 if (empty($autorotation)) {
1386 unset($pano_response['autoRotate']);
1387 unset($pano_response['autoRotateInactivityDelay']);
1388 unset($pano_response['autoRotateStopDelay']);
1389 }
1390 if (empty($autorotationinactivedelay)) {
1391 unset($pano_response['autoRotateInactivityDelay']);
1392 }
1393 if (empty($autorotationstopdelay)) {
1394 unset($pano_response['autoRotateStopDelay']);
1395 }
1396
1397 $response = array();
1398 $response = array($pano_id_array, $pano_response);
1399 if (!empty($response)) {
1400 $response = json_encode($response);
1401 }
1402 if (empty($width)) {
1403 $width = '600';
1404 }
1405 if (empty($height)) {
1406 $height = '400';
1407 }
1408 if ('fullwidth' == $width) {
1409 $width = "100%";
1410 }
1411
1412 $foreground_color = '#fff';
1413 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1414 $rgb = wpvr_HTMLToRGB($hotspoticoncolor);
1415 $hsl = wpvr_RGBToHSL($rgb);
1416 if ($hsl->lightness > 200) {
1417 $foreground_color = '#000000';
1418 } else {
1419 $foreground_color = '#fff';
1420 }
1421
1422 $class = 'myclass';
1423 $html = 'test';
1424 $html = '';
1425 $html .= '<style>';
1426 if ($width == 'embed') {
1427 $html .= 'body{
1428 overflow: hidden;
1429 }';
1430 }
1431 $status = get_option('wpvr_edd_license_status');
1432 if ($status !== false && $status == 'valid') {
1433 if (isset($postdata['customcss_enable']) && $postdata['customcss_enable'] == 'on') {
1434 $html .= isset($postdata['customcss']) ? $postdata['customcss'] : '';
1435 }
1436 }
1437 if ($status !== false && $status == 'valid') {
1438 if (is_array($panodata) && isset($panodata['scene-list'])) {
1439 foreach ($panodata['scene-list'] as $panoscenes) {
1440
1441 foreach ($panoscenes['hotspot-list'] as $hotspot) {
1442 if (isset($hotspot['hotspot-customclass-color-icon-value']) && !empty($hotspot['hotspot-customclass-color-icon-value'])) {
1443 $hotspoticoncolor = $hotspot['hotspot-customclass-color-icon-value'];
1444 } else {
1445 $hotspoticoncolor = "#00b4ff";
1446 }
1447 $hotspot_border = '';
1448 if(isset($hotspot['hotspot-border']) && $hotspot['hotspot-border'] == 'on'){
1449 $border_width = $hotspot['hotspot-border-width'];
1450 $border_color = $hotspot['hotspot-border-color'];
1451 $border_style = $hotspot['hotspot-border-style'];
1452
1453 $hotspot_border = 'border: '.$border_width.'px '.$border_style.' '.$border_color.';';
1454 }
1455 $hotspot_background_color = 'background-color: ' . $hotspoticoncolor . ';';
1456 $hotspot_animation = ' animation: icon-pulse' . $panoid . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1457 '. $hotspot_border.'';
1458
1459
1460 $pulse_color = wpvr_hex2rgb($hotspoticoncolor);
1461 if (isset($hotspot["hotspot-customclass-pro"]) && $hotspot["hotspot-customclass-pro"] != 'none') {
1462 $border_radius = ' border-radius: 100%;';
1463 $hotspot_shape = isset($hotspot["hotspot-shape"]) ? $hotspot["hotspot-shape"] : 'round';
1464 if($hotspot_shape === 'square'){
1465 $border_radius = '';
1466 }
1467 if ($hotspot_shape === 'hexagon') {
1468 $border_radius = '';
1469 $hotspot_background_color = 'background-color: transparent;';
1470 $hotspot_animation = '';
1471 }
1472
1473 if(isset($hotspot['hotspot-custom-icon-color-value']) && !empty($hotspot['hotspot-custom-icon-color-value'])){
1474 $foreground_color = $hotspot['hotspot-custom-icon-color-value'];
1475 }
1476 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fas.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1477 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fab.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1478 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fa.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1479 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.fa-solid.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1480 #' . esc_attr( $panoid ). ' div.pnlm-hotspot-base.far.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1481 display: block !important;
1482 '.$hotspot_background_color.'
1483 color: ' . $foreground_color . ';
1484 '.$border_radius.'
1485 width: 30px;
1486 height: 30px;
1487 font-size: 16px;
1488 line-height: 30px;
1489 '.$hotspot_animation.'
1490 }';
1491 if($hotspot_shape === 'hexagon'){
1492
1493 $html .= '#' . esc_attr( $panoid ) . ' .custom-' . esc_attr( $id ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' .hexagon-wrapper svg path {
1494 fill: ' . $hotspoticoncolor . ';
1495 }';
1496
1497 $html .= '#' . esc_attr( $panoid ) . ' .custom-' . esc_attr( $id ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . '.pnlm-tooltip:after{
1498 content: "";
1499 position: absolute;
1500 left: 50%;
1501 top: 50%;
1502 transform: translate(-50%, -50%);
1503 width: 85%;
1504 height: 85%;
1505 animation: icon-pulse' . esc_attr( $panoid ) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
1506 border-radius: 100%;
1507 z-index: -2;
1508 }';
1509
1510 }
1511 $html .= '#' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fas.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1512 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fab.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1513 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.fa-solid.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1514 #' . esc_attr( $panoid2) . ' div.pnlm-hotspot-base.fa.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ',
1515 #' . esc_attr( $panoid2 ). ' div.pnlm-hotspot-base.far.custom-' . esc_attr( $id ). '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1516 display: block !important;
1517 '.esc_attr( $hotspot_background_color).'
1518 color: ' . esc_attr( $foreground_color) . ';
1519 '.esc_attr( $border_radius).'
1520 width: 30px;
1521 height: 30px;
1522 font-size: 16px;
1523 line-height: 30px;
1524 '.esc_attr( $hotspot_animation).'
1525 }';
1526 }
1527 if (isset($hotspot['hotspot-blink'])) {
1528 $hotspotblink = $hotspot['hotspot-blink'];
1529 if ($hotspotblink == 'on') {
1530 $html .= '@-webkit-keyframes icon-pulse' . esc_attr( $panoid) . '-' . $panoscenes['scene-id'] . '-' . sanitize_html_class($hotspot['hotspot-title']) . ' {
1531 0% {
1532 box-shadow: 0 0 0 0px rgba(' . esc_attr( $pulse_color[0]) . ', 1);
1533 }
1534 100% {
1535 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pulse_color[0]) . ', 0);
1536 }
1537 }
1538 @keyframes icon-pulse' . esc_attr( $panoid) . ' {
1539 0% {
1540 box-shadow: 0 0 0 0px rgba(' . esc_attr( $pulse_color[0]) . ', 1);)
1541 }
1542 100% {
1543 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pulse_color[0] ). ', 0);
1544 }
1545 }';
1546 }
1547 }
1548 }
1549 }
1550 }
1551 }
1552
1553 $status = get_option('wpvr_edd_license_status');
1554 if ($status !== false && $status == 'valid') {
1555 if (!$gyro) {
1556 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-orientation-button {
1557 display: none;
1558 }';
1559 }
1560 } else {
1561 $html .= '#' . esc_attr( $panoid ). ' div.pnlm-orientation-button {
1562 display: none;
1563 }';
1564 }
1565 $floor_plan_custom_color = isset($postdata['floor_plan_custom_color']) ? $postdata['floor_plan_custom_color'] : '#cca92c';
1566 $foreground_color_pointer = '#fff';
1567 if ($floor_plan_custom_color != '') {
1568 $pointer_pulse = wpvr_hex2rgb($floor_plan_custom_color);
1569 $floor_rgb = wpvr_HTMLToRGB($floor_plan_custom_color);
1570 $floor_hsl = wpvr_RGBToHSL($floor_rgb);
1571 if ($floor_hsl->lightness > 200) {
1572 $foreground_color_pointer = '#000000';
1573 }
1574 $html .= '
1575 .wpvr-floor-map .floor-plan-pointer.add-pulse:before {
1576 border: 17px solid ' . esc_attr( $floor_plan_custom_color ) . ';
1577 }
1578 @-webkit-keyframes pulse {
1579 0% {
1580 -webkit-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1581 }
1582 70% {
1583 -webkit-box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1584 }
1585 100% {
1586 -webkit-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1587 }
1588 }
1589 @keyframes pulse {
1590 0% {
1591 -moz-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1592 box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0.7);
1593 }
1594 70% {
1595 -moz-box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1596 box-shadow: 0 0 0 10px rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1597 }
1598 100% {
1599 -moz-box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1600 box-shadow: 0 0 0 0 rgba(' . esc_attr( $pointer_pulse[0] ) . ', 0);
1601 }
1602 }';
1603 }
1604 $html .= '</style>';
1605
1606 $scene_animation = isset($postdata['sceneAnimation']) ? $postdata['sceneAnimation'] : 'off';
1607
1608 if( $scene_animation === 'on' && is_plugin_active( 'wpvr-pro/wpvr-pro.php' ) ) {
1609 $animation_type = isset($postdata['sceneAnimationName']) ? $postdata['sceneAnimationName'] : 'none';
1610 $animationDuration = isset($postdata['sceneAnimationTransitionDuration']) ? $postdata['sceneAnimationTransitionDuration'] : '500ms';
1611 $animationDelay = isset($postdata['sceneAnimationTransitionDelay']) ? $postdata['sceneAnimationTransitionDelay'] : '0ms';
1612 $animation_css = apply_filters('wpvr_tour_scene_animation',$animation_type,$animationDuration, $animationDelay, $postdata,$id);
1613 $html .= $animation_css;
1614 }
1615
1616 if (wpvr_isMobileDevice()) {
1617 $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 ) . ' ">';
1618 } else {
1619 $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 ) . '">';
1620 }
1621 $status = get_option('wpvr_edd_license_status');
1622 $is_cardboard = get_option('wpvr_cardboard_disable');
1623 if ($status !== false && 'valid' == $status && $is_pro && wpvr_isMobileDevice() && $is_cardboard == 'true') {
1624 $html .= '<button class="fullscreen-button">';
1625 $html .= '<span class="expand">';
1626 $html .= '<i class="fas fa-expand" aria-hidden="true"></i>';
1627 $html .= '</span>';
1628
1629 $html .= '<span class="compress">';
1630 $html .= '<i class="fas fa-minimize" aria-hidden="true"></i>';
1631 $html .= '</span>';
1632 $html .= '</button>';
1633 $html .= '<label class="wpvr-cardboard-switcher">
1634 <input type="checkbox" class="vr_mode_change' . $id . '" name="vr_mode_change" value="off">
1635 <span class="switcher-box">
1636 <span class="normal-mode-tooltip">Normal VR Mode</span>
1637 <svg width="78" height="60" viewBox="0 0 78 60" fill="none" xmlns="http://www.w3.org/2000/svg">
1638 <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"/>
1639 </svg>
1640 </span>
1641 </label>';
1642 }
1643
1644 if ($width == 'fullwidth') {
1645 if (wpvr_isMobileDevice()) {
1646 $html .= '<div class="cardboard-vrfullwidth vrfullwidth">';
1647 $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>';
1648 $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 ) . '" >';
1649 } else {
1650 $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>';
1651 $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;" >';
1652 }
1653 } else {
1654 if (wpvr_isMobileDevice()) {
1655 $html .= '<div id="pano2' . esc_attr( $id ) . '" class="pano-wrap pano-left cardboard-half" style="width: 49%; border-radius:' . esc_attr( $radius ) . ';">
1656 <div id="center-pointer2' . esc_attr( $id ) . '" class="vr-pointer-container">
1657 <span class="center-pointer"></span>
1658 </div>
1659 </div>';
1660 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap pano-right" style=" width: 100%; border-radius:' . esc_attr( $radius ) . ';">';
1661 } else {
1662
1663 $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>';
1664
1665 $html .= '<div id="pano' . esc_attr( $id ) . '" class="pano-wrap pano-right" style="width: 100%; border-radius:' . esc_attr( $radius ) . ';">';
1666 }
1667 }
1668 // Vr mode transction scene to scene
1669 if ($status !== false && 'valid' == $status && $is_pro && wpvr_isMobileDevice() && $is_cardboard == 'true') {
1670 $html .= '<div id="center-pointer' . esc_attr( $id ) . '" class="vr-pointer-container" style="display:none"><span class="center-pointer"></span></div>';
1671 }
1672
1673
1674 //===company logo===//
1675 if (isset($postdata['cpLogoSwitch'])) {
1676 $cpLogoImg = $postdata['cpLogoImg'];
1677 $cpLogoContent = $postdata['cpLogoContent'];
1678 if ($postdata['cpLogoSwitch'] == 'on' && 'valid' == $status && $is_pro) {
1679 $html .= '<div id="cp-logo-controls">';
1680 $html .= '<div class="cp-logo-ctrl" id="cp-logo">';
1681 if ($cpLogoImg) {
1682 $html .= '<img loading="lazy" src="' . esc_attr( $cpLogoImg ) . '" alt="Company Logo">';
1683 }
1684
1685 if ($cpLogoContent) {
1686 $html .= '<div class="cp-info">' . esc_html( $cpLogoContent ) . '</div>';
1687 }
1688 $html .= '</div>';
1689 $html .= '</div>';
1690 }
1691 }
1692 //===company logo ends===//
1693
1694 //===Background Tour===//
1695 if (isset($postdata['bg_tour_enabler'])) {
1696
1697 $bg_tour_enabler = $postdata['bg_tour_enabler'];
1698 if ($bg_tour_enabler == 'on') {
1699 $bg_tour_navmenu = $postdata['bg_tour_navmenu'] ?? 'off';
1700 $bg_tour_title = $postdata['bg_tour_title'] ?? '';
1701 $bg_tour_subtitle = $postdata['bg_tour_subtitle'] ?? '';
1702
1703 if ($bg_tour_navmenu == 'on') {
1704 $menuLocations = get_nav_menu_locations();
1705 $menuID = $menuLocations['primary'];
1706 $primaryNav = wp_get_nav_menu_items($menuID);
1707
1708 if ($primaryNav) {
1709 $html .= '<div class="wpvr-navbar-container">';
1710 foreach ($primaryNav as $primaryNav_key => $primaryNav_value) {
1711 if ($primaryNav_value->menu_item_parent == "0") {
1712 $html .= '<li>';
1713 $html .= '<a href="' . esc_url( $primaryNav_value->url ) . '">' . esc_attr( $primaryNav_value->title ) . '</a>';
1714 $html .= '<ul class="wpvr-navbar-dropdown">';
1715 foreach ($primaryNav as $pm_key => $pm_value) {
1716 if ($pm_value->menu_item_parent == $primaryNav_value->ID) {
1717 $html .= '<li>';
1718 $html .= '<a href="' . esc_url( $pm_value->url ) . '">' . esc_attr( $pm_value->title ) . '</a>';
1719 $html .= '</li>';
1720 }
1721 }
1722 $html .= '</ul>';
1723 $html .= '</li>';
1724 }
1725 }
1726 $html .= '</div>';
1727 }
1728 }
1729
1730 if($is_pro && 'valid' == $status ){
1731 $html .= '<div class="wpvr-home-content">';
1732 $html .= '<div class="wpvr-home-title">' . $bg_tour_title . '</div>';
1733 $html .= '<div class="wpvr-home-subtitle">' . $bg_tour_subtitle . '</div>';
1734 $html .= '</div>';
1735 }
1736 }
1737 }
1738 //===Background Tour End===//
1739
1740 //===Custom Control===//
1741 if (isset($custom_control)) {
1742 if ($custom_control['panZoomInSwitch'] == "on" || $custom_control['panZoomOutSwitch'] == "on" || ( $custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on") || $custom_control['backToHomeSwitch'] == "on") {
1743 $html .= '<div id="zoom-in-out-controls' . esc_attr( $id ) . '" class="zoom-in-out-controls">';
1744
1745 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
1746 $html .= '<div class="ctrl" id="backToHome' . esc_attr( $id ) . '"><i class="' . $custom_control['backToHomeIcon'] . '" style="color:' . esc_attr( $custom_control['backToHomeColor'] ) . ';"></i></div>';
1747 }
1748
1749 if ($custom_control['panZoomInSwitch'] == "on" && 'valid' == $status && $is_pro) {
1750 $html .= '<div class="ctrl" id="zoom-in' . esc_attr( $id ) . '"><i class="' . $custom_control['panZoomInIcon'] . '" style="color:' . esc_attr( $custom_control['panZoomInColor'] ) . ';"></i></div>';
1751 }
1752
1753 if ($custom_control['panZoomOutSwitch'] == "on" && 'valid' == $status && $is_pro) {
1754 $html .= '<div class="ctrl" id="zoom-out' . esc_attr( $id ) . '"><i class="' . $custom_control['panZoomOutIcon'] . '" style="color:' . esc_attr( $custom_control['panZoomOutColor'] ) . ';"></i></div>';
1755 }
1756
1757 if ($custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on" && 'valid' == $status && $is_pro) {
1758 $html .= '<div class="ctrl" id="gyroscope' . esc_attr( $id ) . '"><i class="' . $custom_control['gyroscopeIcon'] . '" style="color:' . esc_attr( $custom_control['gyroscopeColor'] ) . ';"></i></div>';
1759 }
1760
1761 $html .= '</div>';
1762 }
1763 //===zoom in out Control===//
1764
1765 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) {
1766
1767 //===Custom Control===//
1768 $html .= '<div class="controls" id="controls' . esc_attr( $id ) . '">';
1769
1770 if ($custom_control['panupSwitch'] == "on") {
1771 $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>';
1772 }
1773
1774 if ($custom_control['panDownSwitch'] == "on") {
1775 $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>';
1776 }
1777
1778 if ($custom_control['panLeftSwitch'] == "on") {
1779 $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>';
1780 }
1781
1782 if ($custom_control['panRightSwitch'] == "on") {
1783 $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>';
1784 }
1785
1786 if ($custom_control['panFullscreenSwitch'] == "on") {
1787 $html .= '<div class="ctrl fullscreen" id="fullscreen' . esc_attr( $id ) . '"><i class="' . $custom_control['panFullscreenIcon'] . '" style="color:' . esc_attr( $custom_control['panFullscreenColor'] ) . ';"></i></div>';
1788 }
1789 $html .= '</div>';
1790 }
1791 }
1792
1793 //===explainer button===//
1794 $html .= wpvr_render_explainer_button(
1795 isset( $custom_control ) ? $custom_control : null,
1796 $postdata,
1797 $is_pro,
1798 $autoload,
1799 $explainer_right,
1800 $id
1801 );
1802 //===explainer button end===//
1803
1804 //===Scene navigation Control===//
1805 if (isset($postdata['scene_navigation']) && $postdata['scene_navigation'] === 'on' && 'valid' == $status && $is_pro) {
1806 $html .= '<style>
1807 #et-boc .et-l .pnlm-controls-container,
1808 .pnlm-controls-container{
1809 top: 33px;
1810 }
1811
1812 #et-boc .et-l .zoom-in-out-controls,
1813 .zoom-in-out-controls {
1814 top: 37px;
1815 }
1816 </style>';
1817 $html .= '<div id="custom-scene-navigation' . esc_attr( $id ) . '" class="custom-scene-navigation">
1818 <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>
1819 </div>
1820
1821 <div id="custom-scene-navigation-nav' . esc_attr( $id ) . '" class="custom-scene-navigation-nav">
1822 <ul></ul>
1823 </div>
1824 ';
1825 }
1826
1827 //===Scene navigation Control===//
1828
1829 /**
1830 * Generic Form Handler
1831 * Renders a generic form with modal functionality if enabled in post data
1832 *
1833 * @param array $postdata Array containing form configuration data
1834 * @param string $id Unique identifier for the form instance
1835 * @return string $html Generated HTML content
1836 */
1837
1838 // Check if generic form is enabled and validate the setting
1839 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on' && 'valid' == $status && $is_pro) {
1840
1841 // Process shortcode with fallback handling
1842 $shortcode_content = '';
1843 if (isset($postdata["genericformshortcode"]) && !empty(trim($postdata["genericformshortcode"]))) {
1844 $shortcode_content = do_shortcode( $postdata["genericformshortcode"] );
1845 } else {
1846 $shortcode_content = '<p class="error-message">No shortcode found.</p>';
1847 }
1848
1849 // Generate the form trigger button
1850 $html .= '<div class="generic_form_button" id="generic_form_button_' . esc_attr( $id ) . '">';
1851 $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>';
1852 $html .= '</div>';
1853
1854 // Generate the modal form container
1855 $html .= '<div class="wpvr-generic-form" id="wpvr-generic-form' . esc_attr( $id ) . '" style="display: none">';
1856 $html .= '<span class="close-generic-form"><i class="fa fa-times"></i></span>';
1857 $html .= '<div class="generic-form-container">' . $shortcode_content . '</div>';
1858 $html .= '</div>';
1859 }
1860 //=====custom generic form=====//
1861
1862 //===Floor map button===//
1863 $status = get_option('wpvr_edd_license_status');
1864 if ($status !== false && 'valid' == $status && $is_pro) {
1865 if ($floor_plan_enable == "on" && !empty($floor_plan_image)) {
1866 $html .= '<div class="floor_map_button" id="floor_map_button_' . esc_attr( $id ) . '" style="right:' . esc_attr( $floor_map_right ) . '">';
1867 $html .= '<div class="ctrl" id="floor_map_target_' . esc_attr( $id ) . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
1868 $html .= '</div>';
1869 }
1870 }
1871
1872 //===floor map button===//
1873 if ($vrgallery && 'valid' == $status && $is_pro ) {
1874 //===Carousal setup===//
1875 $size = '';
1876 if ($vrgallery_icon_size) {
1877 $size = 'vrg-icon-size-large';
1878 }
1879 $html .= '<div id="vrgcontrols' . esc_attr( $id ) . '" class="vrgcontrols">';
1880
1881 $html .= '<div class="vrgctrl' . esc_attr( $id ) . ' vrbounce ' . esc_attr( $size ) . '">';
1882 $html .= '</div>';
1883 $html .= '</div>';
1884
1885 $html .= '<div id="sccontrols' . $id . '" class="scene-gallery vrowl-carousel owl-theme ">';
1886 if (isset($panodata["scene-list"])) {
1887 foreach ($panodata["scene-list"] as $panoscenes) {
1888 $scene_key = $panoscenes['scene-id'];
1889 if ($vrgallery_title == 'on') {
1890 $scene_key_title = isset($panoscenes['scene-ititle']) ? esc_html($panoscenes['scene-ititle']) : '';
1891 } else {
1892 $scene_key_title = "";
1893 }
1894
1895 if ($panoscenes['scene-type'] == 'cubemap') {
1896 $img_src_url = $panoscenes['scene-attachment-url-face0'];
1897 } else {
1898 $img_src_url = $panoscenes['scene-attachment-url'];
1899 }
1900
1901
1902 $src_to_id = attachment_url_to_postid($img_src_url);
1903 $thumbnail_array = wp_get_attachment_image_src($src_to_id, 'thumbnail');
1904 if ($thumbnail_array) {
1905 $thumbnail = $thumbnail_array[0];
1906 } else {
1907 $thumbnail = $img_src_url;
1908 }
1909 if( isset($postdata['tourLayout']['layout']) && 'layout1' !== $postdata['tourLayout']['layout']) {
1910 $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>';
1911 }else {
1912 $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>';
1913 }
1914 }
1915 }
1916 $html .= '</div>';
1917 $html .= '
1918 <div class="owl-nav wpvr_slider_nav">
1919 <button type="button" role="presentation" class="owl-prev wpvr_owl_prev">
1920 <div class="nav-btn prev-slide"><i class="fa fa-angle-left"></i></div>
1921 </button>
1922 <button type="button" role="presentation" class="owl-next wpvr_owl_next">
1923 <div class="nav-btn next-slide"><i class="fa fa-angle-right"></i></div>
1924 </button>
1925 </div>
1926 ';
1927 //===Carousal setup end===//
1928 }
1929
1930 $bg_music = isset($postdata['bg_music']) ? $postdata['bg_music'] : 'off';
1931 $bg_music_url = isset($postdata['bg_music_url']) ? $postdata['bg_music_url'] : '';
1932 $autoplay_bg_music = isset($postdata['autoplay_bg_music']) ? $postdata['autoplay_bg_music'] : 'off';
1933 $loop_bg_music = isset($postdata['loop_bg_music']) ? $postdata['loop_bg_music'] : 'off';
1934
1935 $bg_loop = ($loop_bg_music === 'on') ? 'loop' : '';
1936 $autoplay_attr = ($autoplay_bg_music === 'on') ? 'autoplay' : '';
1937 $audio_muted_attr = ($autoplay_bg_music === 'on') ? 'muted' : '';
1938 $audio_icon_class = 'fa-volume-mute'; // Always start with mute icon
1939
1940 if ($bg_music === 'on' && 'valid' == $status && $is_pro) {
1941 $html .= '<div id="adcontrol' . esc_attr( $id ) . '" class="adcontrol" style="right:' . esc_attr( $audio_right ) . '">';
1942 $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 . '>
1943 <source src="' . esc_url($bg_music_url) . '" type="audio/mpeg">
1944 Your browser does not support the audio element.
1945 </audio>';
1946 $html .= '<button onclick="playPause' . esc_attr($id) . '()" class="ctrl audio_control" id="audio_control' . esc_attr($id) . '">
1947 <i id="vr-volume' . esc_attr($id) . '" class="wpvrvolumeicon' . esc_attr($id) . ' fas ' . esc_attr($audio_icon_class) . '" style="color:#fff;"></i>
1948 </button>';
1949 $html .= '</div>';
1950 }
1951
1952 //===Explainer video section===//
1953 $explainerContent = "";
1954 if (isset($postdata['explainerContent'])) {
1955 $explainerContent = wpvr_sanitize_iframe_only($postdata['explainerContent']);
1956 }
1957 $html .= '<div class="explainer" id="explainer' . esc_attr( $id ) . '" style="display: none">';
1958 $html .= '<span class="close-explainer-video"><i class="fa fa-times"></i></span>';
1959 $html .= '' . $explainerContent . '';
1960 $html .= '</div>';
1961 //===Explainer video section End===//
1962
1963 //===Floor plan section===//
1964 $floor_map_image = "";
1965 $floor_map_pointer = array();
1966 $floor_map_scene_id = '';
1967 $floor_plan_custom_color = '#cca92c';
1968 $floor_plan_direction_indicator = isset($postdata['floor_plan_direction_indicator']) ? $postdata['floor_plan_direction_indicator'] : 'on';
1969
1970 if (isset($postdata['floor_plan_attachment_url'])) {
1971 $floor_map_image = $postdata['floor_plan_attachment_url'];
1972 $floor_map_pointer = $postdata['floor_plan_pointer_position'];
1973 $floor_map_scene_id = $postdata['floor_plan_data_list'];
1974 $floor_plan_custom_color = $postdata['floor_plan_custom_color'];
1975 }
1976 $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $id . '" style="display: none">';
1977 $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
1978 $html .= '<img loading="lazy" src="' . $floor_map_image . '">';
1979
1980 foreach ($floor_map_pointer as $key => $pointer_position) {
1981 $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 ) . '">
1982
1983 <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1984 <circle cx="12" cy="12" r="11.5" stroke="' . esc_attr( $floor_plan_custom_color ) . '"/>
1985 <circle cx="12" cy="12" r="5" fill="' . esc_attr( $foreground_color_pointer ) . '"/>
1986 </svg>';
1987
1988 // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
1989 if ($floor_plan_direction_indicator === "on") {
1990 $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
1991 <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)"/>
1992 <defs>
1993 <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
1994 <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
1995 <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
1996 </linearGradient>
1997 </defs>
1998 </svg>';
1999 }
2000 $html .= '</div>';
2001 }
2002 $html .= '</div>';
2003 //===Floor plan section===//
2004
2005 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
2006 $html .= '<i class="fa fa-times cross" data-id="' . esc_attr( $id ) . '"></i>';
2007 $html .= '<div class="wpvr-hotspot-tweak-contents-flex">';
2008 $html .= '<div class="wpvr-hotspot-tweak-contents">';
2009 ob_start();
2010 do_action('wpvr_hotspot_tweak_contents', $scene_data);
2011 $hotspot_content = ob_get_clean();
2012 $html .= $hotspot_content;
2013 $html .= '</div>';
2014 $html .= '</div>';
2015 $html .= '</div>';
2016
2017 $html .= '<div class="custom-ifram-wrapper" style="display: none;">';
2018 $html .= '<i class="fa fa-times cross" data-id="' . esc_attr( $id ) . '"></i>';
2019 $html .= '<div class="custom-ifram-flex">';
2020 $html .= '<div class="custom-ifram">';
2021 $html .= '</div>';
2022 $html .= '</div>';
2023 $html .= '</div>';
2024 $html .= '</div>';
2025 $html .= '</div>';
2026
2027
2028 if ("fullwidth" == $width) {
2029 $html .= '</div>';
2030 }
2031 if ($status !== false && 'valid' == $status && $is_pro) {
2032 $call_to_action = isset($postdata['calltoaction']) ? $postdata['calltoaction'] : 'off';
2033 if ('on' == $call_to_action) {
2034 $buttontext = isset($postdata['buttontext']) ? $postdata['buttontext'] : '';
2035 $buttonurl = isset($postdata['buttonurl']) ? $postdata['buttonurl'] : '';
2036 $cta_btn_style = isset($postdata['button_configuration']) ? $postdata['button_configuration'] : array();
2037
2038 $button_open_new_tab = isset($cta_btn_style['button_open_new_tab']) ? $cta_btn_style['button_open_new_tab'] : "off";
2039 $target = '_self';
2040 $button_position = isset($cta_btn_style['button_position']) ? $cta_btn_style['button_position'] : "";
2041 $background_color = isset($cta_btn_style['button_background_color']) ? $cta_btn_style['button_background_color'] : "";
2042 $color = isset($cta_btn_style['button_font_color']) ? $cta_btn_style['button_font_color'] : "";
2043 $font_size = isset($cta_btn_style['button_font_size']) ? $cta_btn_style['button_font_size'] : "";
2044 $font_weight = isset($cta_btn_style['button_font_weight']) ? $cta_btn_style['button_font_weight'] : "";
2045 $text_align = isset($cta_btn_style['button_alignment']) ? $cta_btn_style['button_alignment'] : "";
2046 $text_transform = isset($cta_btn_style['button_transform']) ? $cta_btn_style['button_transform'] : "";
2047 $font_style = isset($cta_btn_style['button_text_style']) ? $cta_btn_style['button_text_style'] : "";
2048 $text_decoration = isset($cta_btn_style['button_text_decoration']) ? $cta_btn_style['button_text_decoration'] : "";
2049 $line_height = isset($cta_btn_style['button_line_height']) ? $cta_btn_style['button_line_height'] : "";
2050 $letter_spacing = isset($cta_btn_style['button_letter_spacing']) ? $cta_btn_style['button_letter_spacing'] : "";
2051 $word_spacing = isset($cta_btn_style['button_word_spacing']) ? $cta_btn_style['button_word_spacing'] : "";
2052
2053 $border_width = isset($cta_btn_style['button_border_width']) ? $cta_btn_style['button_border_width'] : "";
2054 $border_style = isset($cta_btn_style['button_border_style']) ? $cta_btn_style['button_border_style'] : "";
2055 $border_color = isset($cta_btn_style['button_border_color']) ? $cta_btn_style['button_border_color'] : "";
2056 $border_radius = isset($cta_btn_style['button_border_radius']) ? $cta_btn_style['button_border_radius'] : "";
2057
2058 $button_pt = isset($cta_btn_style['button_pt']) ? $cta_btn_style['button_pt'] : "";
2059 $button_pr = isset($cta_btn_style['button_pr']) ? $cta_btn_style['button_pr'] : "";
2060 $button_pb = isset($cta_btn_style['button_pb']) ? $cta_btn_style['button_pb'] : "";
2061 $button_pl = isset($cta_btn_style['button_pl']) ? $cta_btn_style['button_pl'] : "";
2062
2063 if ($button_open_new_tab == 'on') {
2064 $target = '_blank';
2065 }
2066 $style = 'background-color: ' . esc_attr( $background_color ) . ';
2067 color: ' . esc_attr( $color ) . ';
2068 font-size: ' . esc_attr( $font_size ) . 'px;
2069 font-weight: ' . esc_attr( $font_weight ) . ';
2070 text-align: center;
2071 display: inline-block;
2072 text-transform: ' . esc_attr( $text_transform ) . ';
2073 font-style: ' . esc_attr( $font_style ) . ';
2074 text-decoration: ' . esc_attr( $text_decoration ) . ';
2075 line-height: ' . esc_attr( $line_height ) . ';
2076 letter-spacing: ' . esc_attr( $letter_spacing ) . 'px;
2077 word-spacing: ' . esc_attr( $word_spacing ) . 'px;
2078 border: ' . esc_attr( $border_width ) . 'px ' . esc_attr( $border_style ) . ' ' . esc_attr( $border_color ) . ';
2079 border-radius: ' . esc_attr( $border_radius ). 'px;
2080 padding: ' . esc_attr( $button_pt ) . 'px ' . esc_attr( $button_pr ) . 'px ' . esc_attr( $button_pb ) . 'px ' . esc_attr( $button_pl ) . 'px;
2081 ';
2082 $html .= '<div class="wpvr-call-to-action-button position-' . esc_attr( $text_align ) . '" style="max-width:' . esc_attr( $width ) . esc_attr( $width_unit ) . '">
2083 <a href="' . esc_url( $buttonurl ) . '" style="' . esc_attr( $style ) . '" target="' . esc_attr( $target ) . '">' . esc_attr( $buttontext ) . '</a>
2084 </div>';
2085 }
2086 }
2087
2088 //script started
2089
2090 $html .= '<script>';
2091 if (isset($postdata['bg_music']) && $bg_music == 'on' && 'valid' == $status && $is_pro) {
2092 $html .= '
2093 var x' . $id . ' = document.getElementById("vrAudio' . $id . '");
2094 var playing' . $id . ' = false;
2095 var autoplaySupported' . $id . ' = false;
2096 var alertShown' . $id . ' = false;
2097 var autoplayChecked' . $id . ' = false;
2098
2099 function playPause' . $id . '() {
2100 if (playing' . $id . ') {
2101 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2102 x' . $id . '.pause();
2103 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2104 playing' . $id . ' = false;
2105 } else {
2106 x' . $id . '.muted = false;
2107 x' . $id . '.play().then(function() {
2108 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2109 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2110 playing' . $id . ' = true;
2111 }).catch(function(e) {
2112 console.log("Play failed:", e);
2113 });
2114 }
2115 }
2116
2117 function audionEnd' . $id . '() {
2118 playing' . $id . ' = false;
2119 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2120 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2121 }
2122
2123 x' . $id . '.addEventListener("ended", audionEnd' . $id . ');';
2124
2125 if ($autoplay_bg_music == 'on') {
2126 $html .= '
2127
2128 x' . $id . '.addEventListener("loadeddata", function() {
2129 if (!autoplayChecked' . $id . ') {
2130 checkAutoplayStatus' . $id . '();
2131 }
2132 });
2133
2134 x' . $id . '.addEventListener("canplay", function() {
2135 if (!autoplayChecked' . $id . ') {
2136 checkAutoplayStatus' . $id . '();
2137 }
2138 });
2139
2140 x' . $id . '.addEventListener("canplaythrough", function() {
2141 if (!autoplayChecked' . $id . ') {
2142 checkAutoplayStatus' . $id . '();
2143 }
2144 });
2145
2146 setTimeout(function() {
2147 if (!autoplayChecked' . $id . ') {
2148 checkAutoplayStatus' . $id . '();
2149 }
2150 }, 1000);
2151
2152 x' . $id . '.addEventListener("play", function() {
2153 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2154 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2155 playing' . $id . ' = true;
2156 });
2157
2158 x' . $id . '.addEventListener("pause", function() {
2159 if (!playing' . $id . ') {
2160 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2161 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2162 }
2163 });
2164
2165 function checkAutoplayStatus' . $id . '() {
2166 autoplayChecked' . $id . ' = true;
2167
2168 x' . $id . '.muted = true;
2169 var playPromise = x' . $id . '.play();
2170
2171 if (playPromise !== undefined) {
2172 playPromise.then(function () {
2173 if (x' . $id . '.muted || x' . $id . '.volume === 0) {
2174 handleAutoplayBlocked' . $id . '();
2175 } else {
2176 autoplaySupported' . $id . ' = true;
2177 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2178 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2179 playing' . $id . ' = true;
2180 }
2181 }).catch(function () {
2182 handleAutoplayBlocked' . $id . '();
2183 });
2184 } else {
2185 setTimeout(function () {
2186 if (x' . $id . '.paused || x' . $id . '.currentTime === 0) {
2187 handleAutoplayBlocked' . $id . '();
2188 } else {
2189 autoplaySupported' . $id . ' = true;
2190 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2191 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2192 playing' . $id . ' = true;
2193 }
2194 }, 300);
2195 }
2196 }
2197
2198 function handleAutoplayBlocked' . $id . '() {
2199 autoplaySupported' . $id . ' = false;
2200 if (!alertShown' . $id . ') {
2201 alert("Autoplay is not supported in your browser. Please click the audio button to play music.");
2202 alertShown' . $id . ' = true;
2203 }
2204
2205 x' . $id . '.pause();
2206 x' . $id . '.currentTime = 0;
2207 x' . $id . '.muted = true;
2208
2209 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-up").addClass("fas fa-volume-mute");
2210 jQuery("#audio_control' . $id . '").attr("data-play", "off");
2211
2212 document.getElementById("pano' . $id . '").addEventListener("click", musicPlay' . $id . ');
2213 document.addEventListener("touchstart", musicPlay' . $id . ', { once: true });
2214 document.addEventListener("click", musicPlay' . $id . ', { once: true });
2215 }
2216
2217 function musicPlay' . $id . '() {
2218 x' . $id . '.muted = false;
2219 var playPromise = x' . $id . '.play();
2220
2221 if (playPromise !== undefined) {
2222 playPromise.then(function () {
2223 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2224 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2225 playing' . $id . ' = true;
2226 }).catch(function(e) {
2227 console.log("Play failed:", e);
2228 });
2229 } else {
2230 setTimeout(function () {
2231 if (!x' . $id . '.paused) {
2232 jQuery("#vr-volume' . $id . '").removeClass("fas fa-volume-mute").addClass("fas fa-volume-up");
2233 jQuery("#audio_control' . $id . '").attr("data-play", "on");
2234 playing' . $id . ' = true;
2235 }
2236 }, 100);
2237 }
2238
2239 document.getElementById("pano' . $id . '").removeEventListener("click", musicPlay' . $id . ');
2240 document.removeEventListener("touchstart", musicPlay' . $id . ');
2241 document.removeEventListener("click", musicPlay' . $id . ');
2242 }
2243 ';
2244 }
2245 }
2246 $html .= 'jQuery(document).ready(function() {';
2247 $html .= 'var response = ' . $response . ';';
2248 $html .= 'var scenes = response[1];';
2249 $html .= 'if(scenes) {';
2250 $html .= 'var scenedata = scenes.scenes;';
2251 $html .= 'for(var i in scenedata) {';
2252 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2253 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2254 $html .= 'if(scenehotspot[i].type === "info") {';
2255 $html .= ' scenehotspot[i]["clickHandlerFunc"] = wpvrhotspot;';
2256 $html .= '} else if(scenehotspot[i].type === "scene") {';
2257 $html .= ' scenehotspot[i]["clickHandlerArgs"] = scenehotspot[i]["text"];';
2258 $status = get_option('wpvr_edd_license_status');
2259 if ($status !== false && $status == 'valid') {
2260 $html .='if(wpvr_public.is_pro_active) {';
2261 $html .= ' scenehotspot[i]["clickHandlerFunc"] = wpvrhotspotscene;';
2262 $html .='}';
2263 }
2264 $html .= '}';
2265 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2266 } else {
2267 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2268 $html .= 'scenehotspot[i]["createTooltipFunc"] = wpvrtooltip;';
2269 $html .= '}';
2270 }
2271 $html .= '}';
2272 $html .= '}';
2273 $html .= '}';
2274 $html .= 'var panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);';
2275 $html .= '
2276 if(!wpvr_public.is_pro_active || !wpvr_public.is_license_active) {
2277 panoshow' . $id . '.on("load", function() {
2278 jQuery(".pnlm-panorama-info").hide();
2279 jQuery(".pnlm-compass").hide();
2280 });
2281
2282 panoshow' . $id . '.on("scenechange", function() {
2283 jQuery(".pnlm-panorama-info").hide();
2284 jQuery(".pnlm-compass").hide();
2285 });
2286 }';
2287
2288 //===Dplicate mode only for vr mode===//
2289 $response2 = json_decode($response);
2290 $response2[1]->compass = false;
2291 $response2[1]->autoRotate = false;
2292 $response = json_encode($response2);
2293 $html .= 'var response_duplicate = ' . $response . ';';
2294 $html .= 'var scenes_duplicate = response_duplicate[1];';
2295
2296 $html .= 'if(scenes_duplicate) {';
2297 $html .= 'var scenedata = scenes_duplicate.scenes;';
2298 $html .= 'for(var i in scenedata) {';
2299 $html .= 'var scenehotspot = scenedata[i].hotSpots;';
2300 $html .= 'for(var i = 0; i < scenehotspot.length; i++) {';
2301 $html .= 'if(scenehotspot[i]["clickHandlerArgs"] != "") {';
2302 $html .= 'scenehotspot[i]["clickHandlerFunc"] = wpvrhotspot;';
2303 $html .= '}';
2304 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2305 } else {
2306 $html .= 'if(scenehotspot[i]["createTooltipArgs"] != "") {';
2307 $html .= 'scenehotspot[i]["createTooltipFunc"] = wpvrtooltip;';
2308 $html .= '}';
2309 }
2310 $html .= '}';
2311 $html .= '}';
2312 $html .= '}';
2313 $html .= 'var vr_mode = "off";';
2314 $status = get_option('wpvr_edd_license_status');
2315 if ($status !== false && 'valid' == $status && $is_pro) {
2316 $html .= 'var panoshow2' . $id . ' = pannellum.viewer("pano2' . $id . '", scenes_duplicate);';
2317
2318 // Show Cardboard Mode in Tour
2319 $html .= '
2320 var tim;
2321 var im = 0;
2322 var active_scene = "' . $default_scene . '";
2323 var c_time;
2324 c_time = new Date();
2325 var timer = c_time.getTime() + 2000;
2326 function panoShowCardBoardOnTrigger(data){
2327 if(scenes_duplicate) {
2328 var scenedata = scenes_duplicate.scenes;
2329 for(var i in scenedata) {
2330 if(active_scene === i) {
2331 var scenehotspot = scenedata[i].hotSpots;
2332 for(var j in scenehotspot) {
2333 var plusFiveYaw = Math.round(scenehotspot[j].yaw) + 5;
2334 var minusFiveYaw = Math.round(scenehotspot[j].yaw) - 5;
2335 var plusFivePitch = Math.round(scenehotspot[j].pitch) + 5;
2336 var minusFivePitch = Math.round(scenehotspot[j].pitch) - 5;
2337 var firstCondition = ( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ;
2338 var secCondition = (Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw);
2339 if(( Math.round(data.pitch) > minusFivePitch) && (Math.round(data.pitch) < plusFivePitch) ){
2340 if((Math.round(data.yaw) > minusFiveYaw) && (Math.round(data.yaw) < plusFiveYaw)){
2341 jQuery(".center-pointer").addClass("wpvr-pluse-effect")
2342 var getScene = scenehotspot[j].sceneId;
2343 if(scenehotspot[j].type == "scene"){
2344 panoshow' . $id . '.loadScene(getScene);
2345 panoshow2' . $id . '.loadScene(getScene);
2346 // var inside_current_time_object = new Date();
2347 // var inside_timer = inside_current_time_object.getTime();
2348 // if(inside_timer > timer) {
2349 // panoshow' . $id . '.loadScene(getScene);
2350 // panoshow2' . $id . '.loadScene(getScene);
2351 // jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2352 // }
2353 }else{
2354 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2355 }
2356 }
2357 else {
2358 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2359 c_time = new Date();
2360 timer = c_time.getTime() + 2000;
2361 }
2362 }
2363 else {
2364 c_time = new Date();
2365 timer = c_time.getTime() + 2000;
2366 }
2367 }
2368 }
2369 }
2370 }
2371 };
2372
2373 function vrDeviseOrientation(){
2374 var data = {
2375 pitch: panoshow' . $id . '.getPitch(),
2376 yaw: panoshow' . $id . '.getYaw(),
2377 };
2378 panoShowCardBoardOnTrigger(data);
2379 }
2380 ';
2381 $html .= '
2382
2383 function requestFullScreen(){
2384 var elem = document.getElementById("master-container");
2385 if (elem.requestFullscreen) {
2386 elem.requestFullscreen();
2387 } else if (elem.webkitRequestFullscreen) { /* Safari */
2388 elem.webkitRequestFullscreen();
2389 } else if (elem.msRequestFullscreen) { /* IE11 */
2390 elem.msRequestFullscreen();
2391 }
2392 }
2393 function requestExitFullscreen(){
2394 var elem = document.getElementById("master-container");
2395 if (document.exitFullscreen) {
2396 document.exitFullscreen();
2397 } else if (document.webkitExitFullscreen) { /* Safari */
2398 document.webkitExitFullscreen();
2399 } else if (document.msExitFullscreen) { /* IE11 */
2400 document.msExitFullscreen();
2401 }
2402 }
2403 jQuery(document).on("click",".fullscreen-button .expand",function() {
2404 jQuery(this).hide()
2405 jQuery(this).parent().find(".compress").show()
2406 requestFullScreen()
2407 screen.orientation.lock("landscape-primary")
2408 .then(function() {
2409 })
2410 .catch(function(error) {
2411 alert("Not Supported for this devise");
2412 });
2413
2414 });
2415 jQuery(document).on("click",".fullscreen-button .compress",function() {
2416 jQuery(this).hide()
2417 jQuery(this).parent().find(".expand").show()
2418 requestExitFullscreen()
2419 screen.orientation.unlock();
2420
2421 });
2422
2423 let onLoadAnalytics = false;
2424 let sceneLoadAnalytics = false;
2425 function storeAnalyticsData(data) {
2426 if(wpvr_public.is_pro_active) {
2427 jQuery.ajax({
2428 url: wpvrAnalyticsObj.ajaxUrl,
2429 type: "POST",
2430 data: {
2431 action: "store_scene_hotspot_data",
2432 scene_id: data.scene_id,
2433 tour_id: data.tour_id,
2434 type: data.type,
2435 hotspot_id: data.hotspot_id || "",
2436 user_agent: navigator.userAgent,
2437 device_type: getDeviceType() || "desktop",
2438 nonce: wpvrAnalyticsObj.nonce,
2439 },
2440 success: function (response) {
2441 console.log("Data stored successfully");
2442 },
2443 error: function (error) {
2444 console.log("Error in storing data");
2445 }
2446 });
2447 }
2448 }
2449
2450 function getDeviceType() {
2451 const userAgent = navigator.userAgent.toLowerCase();
2452
2453 if (/mobile|android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(userAgent)) {
2454 return "mobile";
2455 } else if (/tablet|ipad/i.test(userAgent)) {
2456 return "tablet";
2457 } else {
2458 return "desktop";
2459 }
2460 }
2461
2462 panoshow' . $id . '.on("scenechange", function(scene) {
2463 onLoadAnalytics = true;
2464 sceneLoadAnalytics = true;
2465 let scene_id = scene;
2466 let tour_id = ' . $id . ';
2467 let type = "scene";
2468 let hotspot_id = "";
2469 let user_agent = navigator.userAgent;
2470 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2471 storeAnalyticsData({
2472 scene_id: scene_id,
2473 tour_id: tour_id,
2474 type: type,
2475 hotspot_id: hotspot_id,
2476 user_agent: user_agent,
2477 device_type: device_type,
2478 });
2479 if(!wpvr_public.is_pro_active) {
2480 jQuery(".pnlm-panorama-info").hide();
2481 setTimeout(function() {
2482 jQuery(".pnlm-panorama-info").each(function() {
2483 jQuery(this).hide();
2484 });
2485 }, 500);
2486 }
2487 });
2488
2489 panoshow' . $id . '.on("load", function() {
2490 let scene_id = panoshow' . $id . '.getScene();
2491 let tour_id = ' . $id . ';
2492 let type = "scene";
2493 let hotspot_id = "";
2494 let user_agent = navigator.userAgent;
2495 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2496 if(!onLoadAnalytics && !sceneLoadAnalytics){
2497 storeAnalyticsData({
2498 scene_id: scene_id,
2499 tour_id: tour_id,
2500 type: type,
2501 hotspot_id: hotspot_id,
2502 user_agent: user_agent,
2503 device_type: device_type,
2504 });
2505 }
2506 if(!wpvr_public.is_pro_active) {
2507 jQuery(".pnlm-panorama-info").hide();
2508 setTimeout(function() {
2509 jQuery(".pnlm-panorama-info").each(function() {
2510 jQuery(this).hide();
2511 });
2512 }, 500);
2513 }
2514 })
2515
2516 function wpvrhotspotscene(hotSpotDiv, args) {
2517 onLoadAnalytics = true;
2518 let scene_id = panoshow' . $id . '.getScene();
2519 let tour_id = ' . $id . ';
2520 let type = "hotspot";
2521 let hotspot_id = args;
2522 let user_agent = navigator.userAgent;
2523 let device_type = getDeviceType() ? getDeviceType() : "desktop";
2524 storeAnalyticsData({
2525 scene_id: scene_id,
2526 tour_id: tour_id,
2527 type: type,
2528 hotspot_id: hotspot_id,
2529 user_agent: user_agent,
2530 device_type: device_type
2531 });
2532 }';
2533
2534 $html .= '
2535 panoshow' . $id . '.on("scenechange", function (scene){
2536 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2537 active_scene = scene;
2538 });
2539 var compassBlock = "";
2540 var infoBlock = "";
2541 var getValue = "";
2542 jQuery(document).on("click",".vr_mode_change' . $id . '",function (){
2543
2544 jQuery("#pano2' . $id . ' .pnlm-load-button").trigger("click");
2545 jQuery("#pano' . $id . ' .pnlm-load-button").trigger("click");
2546
2547 getValue = jQuery(this).val();
2548 var getParent = jQuery(this).parent().parent();
2549 var fullWidthParent = getParent.parent();
2550 var compass = getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display");
2551 var panoInfo = getParent.find("#pano' . $id . ' .pnlm-panorama-info").css("display");
2552 if(compass == "block"){
2553 compassBlock = "block";
2554 }
2555 if(panoInfo == "block"){
2556 infoBlock = "block";
2557 }
2558 if (getValue == "off") {
2559 requestFullScreen()
2560 screen.orientation.lock("landscape-primary")
2561 .then(function() {
2562 })
2563 .catch(function(error) {
2564 alert("VR Glass Mode not supported in this device");
2565 });
2566 getParent.find(".pano-wrap").addClass("wpvr-cardboard-disable-event");
2567 // localStorage.setItem("vr_mode", "on");
2568 vr_mode = "on";
2569 jQuery(".vr-mode-title").show();
2570 jQuery(this).val("on");
2571 getParent.find("#pano2' . $id . '").css({
2572 "opacity": "1",
2573 "visibility": "visible",
2574 "position": "relative",
2575 });
2576 gyroSwitch = true;
2577 panoshow' . $id . '.startOrientation();
2578 panoshow2' . $id . '.startOrientation();
2579 panoshow2' . $id . '.setPitch(panoshow' . $id . '.getPitch(), 0);
2580 panoshow2' . $id . '.setYaw(panoshow' . $id . '.getYaw(), 0);
2581 getParent.find("#pano' . $id . ' #zoom-in-out-controls' . $id . '").hide();
2582 getParent.find("#pano' . $id . ' #controls' . $id . '").hide();
2583 getParent.find("#pano' . $id . ' #explainer_button_' . $id . '").hide();
2584 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").hide();
2585 getParent.find("#pano' . $id . ' #floor_map_button_' . $id . '").hide();
2586 getParent.find("#pano' . $id . ' #vrgcontrols' . $id . '").hide();
2587 getParent.find("#pano' . $id . ' #sccontrols' . $id . '").hide();
2588 getParent.find("#pano' . $id . ' #adcontrol' . $id . '").hide();
2589 getParent.find("#pano' . $id . ' .owl-nav.wpvr_slider_nav").hide();
2590 getParent.find("#pano' . $id . ' #cp-logo-controls").hide();
2591
2592 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").hide();
2593
2594 getParent.find("#pano2' . $id . ' .pnlm-controls-container").hide();
2595 getParent.find("#pano' . $id . ' .pnlm-controls-container").hide();
2596
2597 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
2598 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").hide();
2599
2600 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").hide();
2601 getParent.find("#pano' . $id . ' .pnlm-panorama-info").hide();
2602 getParent.find("#pano' . $id . '").addClass("cardboard-half");
2603
2604 getParent.find("#center-pointer' . $id . '").show();
2605 getParent.find(".fullscreen-button").hide();
2606
2607
2608 if (window.DeviceOrientationEvent) {
2609 window.addEventListener("deviceorientation", vrDeviseOrientation);
2610 }
2611
2612 panoshow' . $id . '.on("mousemove", function (data){
2613 panoshow2' . $id . '.setPitch(data.pitch, 0);
2614 panoshow2' . $id . '.setYaw(data.yaw, 0);
2615 panoShowCardBoardOnTrigger(data);
2616
2617 });
2618 panoshow2' . $id . '.on("mousemove", function (data){
2619 panoshow2' . $id . '.setPitch(data.pitch, 0);
2620 panoshow' . $id . '.setYaw(data.yaw, 0);
2621 panoShowCardBoardOnTrigger(data);
2622
2623 });
2624
2625 panoshow' . $id . '.on("zoomchange", function (data){
2626 panoshow2' . $id . '.setHfov(data, 0);
2627 });
2628
2629 panoshow2' . $id . '.on("zoomchange", function (data){
2630 panoshow' . $id . '.setHfov(data, 0);
2631 });
2632
2633 panoshow' . $id . '.on("touchmove", function (data){
2634 panoshow' . $id . '.stopOrientation();
2635 panoshow2' . $id . '.stopOrientation();
2636 panoshow2' . $id . '.setPitch(data.pitch, 0);
2637 panoshow2' . $id . '.setYaw(data.yaw, 0);
2638 panoShowCardBoardOnTrigger(data);
2639
2640 });
2641
2642 panoshow2' . $id . '.on("touchmove", function (data){
2643 panoshow' . $id . '.stopOrientation();
2644 panoshow2' . $id . '.stopOrientation();
2645 panoshow' . $id . '.setPitch(data.pitch, 0);
2646 panoshow' . $id . '.setYaw(data.yaw, 0);
2647 panoShowCardBoardOnTrigger(data);
2648
2649 });
2650
2651 }
2652 else if(getValue == "on") {
2653 screen.orientation.unlock();
2654 requestExitFullscreen();
2655 // localStorage.setItem("vr_mode", "off");
2656 vr_mode = "off";
2657 jQuery(".vr-mode-title").hide();
2658 jQuery(this).val("off");
2659 getParent.find("#pano2' . $id . '").css({
2660 "opacity": "0",
2661 "visibility": "hidden",
2662 "position": "absolute",
2663 });
2664 panoshow' . $id . '.stopOrientation();
2665 panoshow2' . $id . '.stopOrientation();
2666 getParent.find(".pano-wrap").removeClass("wpvr-cardboard-disable-event");
2667 getParent.find("#pano' . $id . ' #zoom-in-out-controls' . $id . '").show();
2668 getParent.find("#pano' . $id . ' #controls' . $id . '").show();
2669 getParent.find("#pano' . $id . ' #explainer_button_' . $id . '").show();
2670 getParent.find("#pano' . $id . ' #generic_form_button_' . $id . '").show();
2671 getParent.find("#pano' . $id . ' #floor_map_button_' . $id . '").show();
2672
2673 getParent.find("#pano2' . $id . ' .pnlm-controls-container").show();
2674 getParent.find("#pano' . $id . ' .pnlm-controls-container").show();
2675 getParent.find("#pano' . $id . ' #vrgcontrols' . $id . '").show();
2676 getParent.find("#pano' . $id . ' #sccontrols' . $id . '").hide();
2677 getParent.find("#pano' . $id . ' #adcontrol' . $id . '").show();
2678 getParent.find("#pano' . $id . ' .owl-nav.wpvr_slider_nav").hide();
2679 getParent.find("#pano' . $id . ' #cp-logo-controls").show();
2680 getParent.find("#pano' . $id . ' #custom-scene-navigation' . $id . '").show();
2681
2682 if(compassBlock == "block"){
2683 getParent.find("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
2684 getParent.find("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").show();
2685 }
2686 if(infoBlock == "block"){
2687 getParent.find("#pano2' . $id . ' .pnlm-panorama-info").show();
2688 getParent.find("#pano' . $id . ' .pnlm-panorama-info").show();
2689 }
2690
2691 getParent.find("#pano' . $id . '").removeClass("cardboard-half");
2692 getParent.find("#center-pointer' . $id . '").hide();
2693 getParent.find(".fullscreen-button").hide();
2694 panoshow' . $id . '.off("mousemove");
2695 panoshow' . $id . '.off("touchmove");
2696 panoshow2' . $id . '.off("mousemove");
2697 panoshow2' . $id . '.off("touchmove");
2698 if (window.DeviceOrientationEvent) {
2699 window.removeEventListener("deviceorientation", vrDeviseOrientation);
2700 }
2701 }
2702 });';
2703
2704 $html .= 'panoshow2' . $id . '.on("load", function (){
2705 // if(localStorage.getItem("vr_mode") == "off") {
2706 if( vr_mode == "off") {
2707 jQuery(".vr-mode-title").hide();
2708 }
2709 else {
2710 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2711 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2712 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
2713 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
2714 jQuery(".vr-mode-title").show();
2715 }
2716 });';
2717 }
2718
2719 $html .= 'jQuery("#pano' . $id . ' .wpvr-floor-map .floor-plan-pointer").on("click",function(){
2720 var scene_id = jQuery(this).attr("scene_id");
2721 panoshow' . $id . '.loadScene(scene_id)
2722 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2723 jQuery(this).addClass("add-pulse")
2724 });';
2725
2726 if ($scene_animation == 'on' && is_plugin_active('wpvr-pro/wpvr-pro.php') ) {
2727 $animation_js = apply_filters('wpvr_scene_animation_js', $id, $animation_type, $animationDuration, $animationDelay);
2728 if (!empty($animation_js)) {
2729 $html .= $animation_js;
2730 $html .= 'panoshow' . $id . '.on("load", function (scene){
2731 if (typeof changeScene === "function") {
2732 changeScene();
2733 } else {
2734 console.warn("changeScene function is not defined.");
2735 }
2736 });';
2737 }
2738 }
2739
2740
2741 $html .= '
2742 panoshow' . $id . '.on("mousemove", function (data){
2743 jQuery(".add-pulse").css({"transform":"rotate("+data.yaw+"deg)"});
2744 });
2745 ';
2746
2747
2748
2749 $status = get_option('wpvr_edd_license_status');
2750 if ($status !== false && 'valid' == $status && $is_pro) {
2751 $html .= 'panoshow' . $id . '.on("scenechange", function (scene){
2752 jQuery(".center-pointer").removeClass("wpvr-pluse-effect")
2753 jQuery(".floor-plan-pointer").each(function(index ,element){
2754 var scene_id = jQuery(this).attr("scene_id");
2755 if( active_scene == scene_id ){
2756 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2757 jQuery(this).addClass("add-pulse")
2758 }
2759 });
2760
2761 });';
2762 $html .= 'panoshow' . $id . '.on("load", function (){
2763 if(jQuery(".floor-plan-pointer").length > 0){
2764 jQuery(".floor-plan-pointer").each(function(index ,element){
2765 var scene_id = jQuery(this).attr("scene_id");
2766 if( active_scene == scene_id ){
2767 jQuery(".floor-plan-pointer").removeClass("add-pulse")
2768 jQuery(this).addClass("add-pulse")
2769 }
2770 });
2771 }
2772 });';
2773 }
2774
2775 if ($status !== false && 'valid' == $status && $is_pro) {
2776 $scene_navigation_content_type = isset($postdata['scene_navigation_content_type']) ? $postdata['scene_navigation_content_type'] : 'scene_id';
2777 $html .= '
2778 jQuery("#pano' . $id . ' .custom-scene-navigation").on("click",function(){
2779 jQuery("#custom-scene-navigation-nav' . $id . ' ul").empty()
2780 if(scenes){
2781 var scene_navigation_content_type = ' . "'" . $scene_navigation_content_type . "'" . ';
2782 var sceneList = scenes.scenes;
2783 var getScene = panoshow' . $id . '.getScene();
2784 for (const key in sceneList) {
2785 let title;
2786 if (scene_navigation_content_type === "scene_title") {
2787 if (sceneList[key].title) {
2788 title = sceneList[key].title;
2789
2790 }else{
2791 if(title == "" || title == undefined){
2792 if (sceneList[key].panorama) {
2793 title = getImageNameWithoutExtension(sceneList[key].panorama);
2794 }
2795 }
2796 }
2797 } else if (scene_navigation_content_type === "scene_image_name") {
2798 if (sceneList[key].panorama) {
2799 title = getImageNameWithoutExtension(sceneList[key].panorama);
2800 }
2801 } else {
2802 title = key;
2803 }
2804 if (sceneList.hasOwnProperty(key)) {
2805 if( key === getScene){
2806 jQuery("#custom-scene-navigation-nav' . $id . ' ul").append("<li class=\"scene-navigation-list active\" scene_id= " + key + " >" + title + "</li>");
2807 }else{
2808 jQuery("#custom-scene-navigation-nav' . $id . ' ul").append("<li class=\"scene-navigation-list\" scene_id= " + key + " >" + title + "</li>");
2809 }
2810 }
2811 }
2812 }
2813 jQuery("#custom-scene-navigation-nav' . $id . '").toggleClass("visible");
2814 });
2815 ';
2816
2817 $html .= 'function getImageNameWithoutExtension(imageUrl) {
2818 // Split the URL by "/"
2819 var parts = imageUrl.split("/");
2820
2821 // Get the last part which contains the image name
2822 var imageNameWithExtension = parts[parts.length - 1];
2823
2824 // Split the image name by period (.)
2825 var imageNameParts = imageNameWithExtension.split(".");
2826
2827 // Remove the last part (which is the extension) and join the remaining parts
2828 var imageNameWithoutExtension = imageNameParts.slice(0, -1).join(".");
2829
2830 // Return the image name without extension
2831 return imageNameWithoutExtension;
2832 }';
2833
2834
2835 $html .= '
2836 jQuery("#pano' . $id . ' #custom-scene-navigation-nav' . $id . ' ul").on("click", "li.scene-navigation-list", function() {
2837 if (scenes) {
2838 jQuery(this).siblings("li").removeClass("active");
2839 jQuery(this).addClass("active");
2840
2841 var scene_key = jQuery(this).attr("scene_id");
2842 panoshow' . $id . '.loadScene(scene_key);
2843 }
2844 });
2845 ';
2846 }
2847
2848 //Duplicate mode only for vr mode end===//
2849 $html .= 'panoshow' . $id . '.on("load", function (){
2850
2851 // if(localStorage.getItem("vr_mode") == "off") {
2852 if( vr_mode == "off") {
2853 jQuery(".vr-mode-title").hide();
2854 }
2855 else {
2856 jQuery("#pano2' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2857 jQuery("#pano' . $id . ' .pnlm-compass.pnlm-controls.pnlm-control").css("display","none");
2858 jQuery("#pano2' . $id . ' .pnlm-panorama-info").hide();
2859 jQuery("#pano' . $id . ' .pnlm-panorama-info").hide();
2860 jQuery(".vr-mode-title").show();
2861 }
2862
2863
2864 if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
2865 jQuery("#controls' . $id . '").css("bottom", "80px");
2866 }
2867 else {
2868 jQuery("#controls' . $id . '").css("bottom", "5px");
2869 }
2870 });';
2871
2872
2873 $html .= '
2874 if (scenes.autoRotate) {
2875 panoshow' . $id . '.on("load", function (){
2876 setTimeout(function(){ panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0); }, 3000);
2877 });
2878 panoshow' . $id . '.on("scenechange", function (){
2879 setTimeout(function(){ panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0); }, 3000);
2880 });
2881 }
2882 ';
2883 $html .= 'var touchtime = 0;';
2884 if ($vrgallery) {
2885 if (isset($panodata["scene-list"])) {
2886 foreach ($panodata["scene-list"] as $panoscenes) {
2887 $scene_key = $panoscenes['scene-id'];
2888 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $id;
2889 $img_src_url = $panoscenes['scene-attachment-url'];
2890 // $html .= 'document.getElementById("' . $scene_key_gallery . '").addEventListener("click", function(e) { ';
2891 // $html .= 'if (touchtime == 0) {';
2892 // $html .= 'touchtime = new Date().getTime();';
2893 // $html .= '} else {';
2894 // $html .= 'if (((new Date().getTime()) - touchtime) < 800) {';
2895 // $html .= 'panoshow' . $id . '.loadScene("' . $scene_key . '");';
2896 // $html .= 'touchtime = 0;';
2897 // $html .= '} else {';
2898 // $html .= 'touchtime = new Date().getTime();';
2899 // $html .= '}';
2900 // $html .= '}';
2901 // $html .= '});';
2902 $html .= '
2903 jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
2904 panoshow' . $id . '.loadScene("' . $scene_key . '");
2905 });
2906 ';
2907 }
2908 }
2909 }
2910
2911
2912
2913 //===Custom Control===//
2914 if (isset($custom_control)) {
2915 if ($custom_control['panupSwitch'] == "on" && $status == 'valid' && $is_pro) {
2916 $html .= 'document.getElementById("pan-up' . $id . '").addEventListener("click", function(e) {';
2917 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() + 10);';
2918 $html .= '});';
2919 }
2920
2921 if ($custom_control['panDownSwitch'] == "on" && $status == 'valid' && $is_pro) {
2922 $html .= 'document.getElementById("pan-down' . $id . '").addEventListener("click", function(e) {';
2923 $html .= 'panoshow' . $id . '.setPitch(panoshow' . $id . '.getPitch() - 10);';
2924 $html .= '});';
2925 }
2926
2927 if ($custom_control['panLeftSwitch'] == "on" && $status == 'valid' && $is_pro) {
2928 $html .= 'document.getElementById("pan-left' . $id . '").addEventListener("click", function(e) {';
2929 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() - 10);';
2930 $html .= '});';
2931 }
2932
2933 if ($custom_control['panRightSwitch'] == "on" && $status == 'valid' && $is_pro) {
2934 $html .= 'document.getElementById("pan-right' . $id . '").addEventListener("click", function(e) {';
2935 $html .= 'panoshow' . $id . '.setYaw(panoshow' . $id . '.getYaw() + 10);';
2936 $html .= '});';
2937 }
2938
2939 if ($custom_control['panZoomInSwitch'] == "on") {
2940 $html .= 'document.getElementById("zoom-in' . $id . '").addEventListener("click", function(e) {';
2941 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() - 10);';
2942 $html .= '});';
2943 }
2944
2945 if ($custom_control['panZoomOutSwitch'] == "on") {
2946 $html .= 'document.getElementById("zoom-out' . $id . '").addEventListener("click", function(e) {';
2947 $html .= 'panoshow' . $id . '.setHfov(panoshow' . $id . '.getHfov() + 10);';
2948 $html .= '});';
2949 }
2950
2951 if ($custom_control['panFullscreenSwitch'] == "on" && $status == 'valid' && $is_pro) {
2952 $html .= 'document.getElementById("fullscreen' . $id . '").addEventListener("click", function(e) {';
2953 $html .= 'panoshow' . $id . '.toggleFullscreen();';
2954 $html .= '});';
2955 $html .= '(function() {';
2956 $html .= 'function wpvrFsChange' . $id . '() {';
2957 $html .= 'var fsIcon = document.querySelector("#fullscreen' . $id . ' i");';
2958 $html .= 'if (!fsIcon) return;';
2959 $html .= 'if (document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement) {';
2960 $html .= 'fsIcon.classList.remove("fa-expand"); fsIcon.classList.add("fa-minimize");';
2961 $html .= '} else {';
2962 $html .= 'fsIcon.classList.remove("fa-minimize"); fsIcon.classList.add("fa-expand");';
2963 $html .= '}';
2964 $html .= '}';
2965 $html .= 'document.addEventListener("fullscreenchange", wpvrFsChange' . $id . ');';
2966 $html .= 'document.addEventListener("webkitfullscreenchange", wpvrFsChange' . $id . ');';
2967 $html .= 'document.addEventListener("mozfullscreenchange", wpvrFsChange' . $id . ');';
2968 $html .= 'document.addEventListener("MSFullscreenChange", wpvrFsChange' . $id . ');';
2969 $html .= '})();';
2970 }
2971
2972 if ($custom_control['backToHomeSwitch'] == "on" && $status == 'valid' && $is_pro) {
2973 $html .= 'document.getElementById("backToHome' . $id . '").addEventListener("click", function(e) {';
2974 $html .= 'panoshow' . $id . '.loadScene("' . $default_scene . '");';
2975 $html .= '});';
2976 }
2977
2978 if ($custom_control['gyroSwitch'] == "on" && $custom_control['gyroscopeSwitch'] == "on" && 'valid' == $status && $is_pro) {
2979 $html .= '
2980 var element = document.getElementById("gyroscope' . $id . '");
2981 var gyroSwitch = true;
2982 var isIOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
2983 var permissionGranted = false;
2984
2985 function requestOrientationPermission() {
2986 if (isIOS) {
2987 if (typeof DeviceOrientationEvent.requestPermission === "function") {
2988 DeviceOrientationEvent.requestPermission()
2989 .then(function(state) {
2990 if (state === "granted") {
2991 permissionGranted = true;
2992 startOrientation();
2993 } else {
2994 element.children[0].style.color = "red";
2995 gyroSwitch = false;
2996 alert("Permission to use motion sensors was denied.");
2997 }
2998 })
2999 .catch(function(error) {
3000 element.children[0].style.color = "red";
3001 gyroSwitch = false;
3002 console.error("Error requesting device orientation permission:", error);
3003 });
3004 }
3005 } else {
3006 startOrientation();
3007 }
3008 }
3009
3010 function startOrientation() {
3011 panoshow' . $id . '.startOrientation();
3012 element.children[0].style.color = "'.$custom_control['gyroscopeColor'].'";
3013 gyroSwitch = true;
3014 }
3015
3016 panoshow' . $id . '.on("load", function() {
3017 if (!isIOS || permissionGranted) {
3018 if (gyroSwitch) {
3019 startOrientation();
3020 } else {
3021 panoshow' . $id . '.stopOrientation();
3022 element.children[0].style.color = "red";
3023 }
3024 }
3025 });
3026
3027 panoshow' . $id . '.on("scenechange", function() {
3028 if (!isIOS || permissionGranted) {
3029 if (panoshow' . $id . '.isOrientationActive()) {
3030 element.children[0].style.color = "'.$custom_control['gyroscopeColor'].'";
3031 } else {
3032 element.children[0].style.color = "red";
3033 }
3034 }
3035 });
3036
3037 panoshow' . $id . '.on("touchstart", function() {
3038 if (!isIOS || permissionGranted) {
3039 if (panoshow' . $id . '.isOrientationActive()) {
3040 gyroSwitch = true;
3041 element.children[0].style.color = "'.$custom_control['gyroscopeColor'].'";
3042 } else {
3043 gyroSwitch = false;
3044 element.children[0].style.color = "red";
3045 }
3046 }
3047 });';
3048
3049 $html .= 'document.getElementById("gyroscope' . $id . '").addEventListener("click", function(e) {
3050 var element = document.getElementById("gyroscope' . $id . '");
3051 if (isIOS && typeof DeviceOrientationEvent.requestPermission === "function" && !permissionGranted) {
3052 requestOrientationPermission();
3053 } else {
3054 if (panoshow' . $id . '.isOrientationActive()) {
3055 panoshow' . $id . '.stopOrientation();
3056 gyroSwitch = false;
3057 element.children[0].style.color = "red";
3058 } else {
3059 startOrientation();
3060 }
3061 }
3062 });';
3063 }
3064 }
3065
3066 $angle_up = '<i class="fa fa-angle-up"></i>';
3067 $angle_down = '<i class="fa fa-angle-down"></i>';
3068 $sin_qout = "'";
3069
3070 //===Explainer Script===//
3071 $html .= '
3072 jQuery(document).on("click","#explainer_button_' . $id . '",function() {
3073 jQuery("#explainer' . $id . '").slideToggle(function(){
3074 var $explainerVideoId = jQuery("#explainer' . $id . '");
3075 var $explainerVideoIframe = $explainerVideoId.find("iframe");
3076 var explainerVideoIframSrc = $explainerVideoIframe.attr("src");
3077 $explainerVideoIframe.attr("src", "");
3078 $explainerVideoIframe.attr("src", explainerVideoIframSrc);
3079 });
3080 });
3081
3082 jQuery(document).on("click", ".close-explainer-video", function() {
3083 var $explainer = jQuery(this).parent(".explainer");
3084 var $iframe = $explainer.find("iframe");
3085 var src = $iframe.attr("src");
3086 $iframe.attr("src", "");
3087 $explainer.hide();
3088 $iframe.attr("src", src);
3089 });
3090
3091 jQuery(document).on("click","#pano' . $id . '",function(event) {
3092 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3093 var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3094 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3095 if( isActiveModal == null && isForm == null && isHotspot == null){
3096 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3097 jQuery(".custom-ifram-wrapper").hide();
3098 jQuery(this).removeClass("show-modal");
3099 jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3100 }else if(isForm != null){
3101 jQuery(this).addClass("show-modal");
3102 }
3103 });
3104
3105 ';
3106 //===Explainer Script End===//
3107
3108 //===generic form script===//
3109 if (isset($postdata["genericform"]) && $postdata["genericform"] === 'on') {
3110 $html .= '
3111 jQuery(document).on("click","#generic_form_button_' . $id . '",function() {
3112 jQuery("#wpvr-generic-form' . $id . '").fadeToggle();
3113 });
3114
3115 jQuery(document).on("click",".close-generic-form",function() {
3116 jQuery(this).parent(".wpvr-generic-form").fadeOut()
3117 });
3118 ';
3119 }
3120
3121 //===generic from script===//
3122
3123 //===Floor map Script===//
3124 $html .= '
3125 jQuery(document).on("click","#floor_map_button_' . $id . '",function() {
3126 jQuery("#wpvr-floor-map' . $id . '").toggle().removeClass("fullwindow");
3127 });
3128
3129 jQuery(document).on("dblclick","#wpvr-floor-map' . $id . '",function(){
3130 jQuery(this).addClass("fullwindow");
3131 jQuery(this).parents(".pano-wrap").addClass("show-modal");
3132 });
3133
3134 jQuery(document).on("click",".close-floor-map-plan",function() {
3135 jQuery(this).parent(".wpvr-floor-map").hide();
3136 jQuery(this).parent(".wpvr-floor-map").removeClass("fullwindow");
3137 jQuery(this).parents(".pano-wrap").removeClass("show-modal");
3138 });
3139
3140 ';
3141 //===Floor map Script End===//
3142
3143 if ($vrgallery_display) {
3144 if (!$autoload) {
3145 $html .= '
3146 jQuery(document).ready(function($){
3147 jQuery("#sccontrols' . $id . '").hide();
3148 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3149 jQuery("#sccontrols' . $id . '").hide();
3150 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3151 });
3152 ';
3153
3154 $html .= '
3155 var slide' . $id . ' = "down";
3156 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3157
3158 if (slide' . $id . ' == "up") {
3159 jQuery(".vrgctrl' . $id . '").empty();
3160 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3161 slide' . $id . ' = "down";
3162 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3163 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3164 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3165 if (jQuery(this).is(":visible")) {
3166 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3167 "display": "flex",
3168 "justify-content": "center",
3169 "align-items": "center",
3170 "gap": "15px"
3171 });
3172 }
3173 }
3174 if (jQuery(".bricks-is-frontend").length) {
3175 if (jQuery(this).is(":visible")) {
3176 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3177 "display": "flex",
3178 "justify-content": "center",
3179 "align-items": "center"
3180 });
3181 }
3182 }
3183 });
3184 }
3185 else {
3186 jQuery(".vrgctrl' . $id . '").empty();
3187 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3188 slide' . $id . ' = "up";
3189 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3190 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3191 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3192 if (jQuery(this).is(":visible")) {
3193 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3194 "display": "flex",
3195 "justify-content": "center",
3196 "align-items": "center",
3197 "gap": "15px"
3198 });
3199 }
3200 }
3201 if (jQuery(".bricks-is-frontend").length) {
3202 if (jQuery(this).is(":visible")) {
3203 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3204 "display": "flex",
3205 "justify-content": "center",
3206 "align-items": "center"
3207 });
3208 }
3209 }
3210 });
3211 }
3212 });
3213 ';
3214 } else {
3215 $html .= '
3216 jQuery(document).ready(function($){
3217 jQuery("#sccontrols' . $id . '").show();
3218 jQuery("#pano' . $id . ' .wpvr_slider_nav").show();
3219 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3220 });
3221 ';
3222
3223 $html .= '
3224 var slide' . $id . ' = "down";
3225 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3226
3227 if (slide' . $id . ' == "up") {
3228 jQuery(".vrgctrl' . $id . '").empty();
3229 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3230 slide' . $id . ' = "down";
3231 }
3232 else {
3233 jQuery(".vrgctrl' . $id . '").empty();
3234 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3235 slide' . $id . ' = "up";
3236 }
3237 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3238 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3239 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3240 if (jQuery(this).is(":visible")) {
3241 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3242 "display": "flex",
3243 "justify-content": "center",
3244 "align-items": "center",
3245 "gap": "15px"
3246 });
3247 }
3248 }
3249 if (jQuery(".bricks-is-frontend").length) {
3250 if (jQuery(this).is(":visible")) {
3251 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3252 "display": "flex",
3253 "justify-content": "center",
3254 "align-items": "center"
3255 });
3256 }
3257 }
3258 });
3259 });
3260 ';
3261 }
3262 } else {
3263 $html .= '
3264 jQuery(document).ready(function($){
3265 jQuery("#sccontrols' . $id . '").hide();
3266 jQuery("#pano' . $id . ' .wpvr_slider_nav").hide();
3267 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3268 });
3269 ';
3270
3271 $html .= '
3272 var slide' . $id . ' = "down";
3273 jQuery(document).on("click","#vrgcontrols' . $id . '",function() {
3274
3275 if (slide' . $id . ' == "up") {
3276 jQuery(".vrgctrl' . $id . '").empty();
3277 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_up . $sin_qout . ');
3278 slide' . $id . ' = "down";
3279 }
3280 else {
3281 jQuery(".vrgctrl' . $id . '").empty();
3282 jQuery(".vrgctrl' . $id . '").html(' . $sin_qout . $angle_down . $sin_qout . ');
3283 slide' . $id . ' = "up";
3284 }
3285 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3286 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3287 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3288 if (jQuery(this).is(":visible")) {
3289 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3290 "display": "flex",
3291 "justify-content": "center",
3292 "align-items": "center",
3293 "gap": "15px"
3294 });
3295 }
3296 }
3297 if (jQuery(".bricks-is-frontend").length) {
3298 if (jQuery(this).is(":visible")) {
3299 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3300 "display": "flex",
3301 "justify-content": "center",
3302 "align-items": "center"
3303 });
3304 }
3305 }
3306 });
3307 });
3308 ';
3309 }
3310
3311 if (!$autoload) {
3312 $html .= '
3313
3314 jQuery(document).ready(function(){
3315 jQuery("#controls' . $id . '").hide();
3316 jQuery("#zoom-in-out-controls' . $id . '").hide();
3317 jQuery("#adcontrol' . $id . '").hide();
3318 jQuery("#explainer_button_' . $id . '").hide();
3319 jQuery("#generic_form_button_' . $id . '").hide();
3320 jQuery("#floor_map_button_' . $id . '").hide();
3321 jQuery("#vrgcontrols' . $id . '").hide();
3322 jQuery("#cp-logo-controls").hide();
3323 jQuery(".custom-scene-navigation").hide();
3324 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").hide();
3325 });
3326
3327 ';
3328
3329 if ($vrgallery_display) {
3330 $html .= 'var load_once = "true";';
3331 $html .= 'panoshow' . $id . '.on("load", function (){
3332 if (load_once == "true") {
3333 load_once = "false";
3334 jQuery("#sccontrols' . $id . '").slideToggle(function(){
3335 if (jQuery(".elementor-edit-mode .elementor-widget-container").length) {
3336 if (jQuery(this).is(":visible")) {
3337 jQuery(".elementor-edit-mode .elementor-widget-container .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css("display", "flex");
3338 }
3339 }
3340 if (jQuery(".bricks-is-frontend").length) {
3341 if (jQuery(this).is(":visible")) {
3342 jQuery(".bricks-is-frontend .wpvr-cardboard .pnlm-container #sccontrols' . $id . '").css({
3343 "display": "flex",
3344 "justify-content": "center",
3345 "align-items": "center"
3346 });
3347 }
3348 }
3349 });
3350 jQuery("#pano' . $id . ' .wpvr_slider_nav").slideToggle();
3351 }
3352 });';
3353 }
3354
3355 $html .= 'panoshow' . $id . '.on("load", function (){
3356 jQuery("#controls' . $id . '").show();
3357 jQuery("#zoom-in-out-controls' . $id . '").show();
3358 jQuery("#adcontrol' . $id . '").show();
3359 jQuery("#explainer_button_' . $id . '").show();
3360 jQuery("#generic_form_button_' . $id . '").show();
3361 jQuery("#floor_map_button_' . $id . '").show();
3362 jQuery("#vrgcontrols' . $id . '").show();
3363 jQuery("#cp-logo-controls").show();
3364 jQuery(".custom-scene-navigation").show();
3365 jQuery("#pano' . $id . '").find(".pnlm-panorama-info").show();
3366 });';
3367 }
3368
3369 $previewText = $postdata['previewtext'] ?? 'Click To Load Panorama';
3370 if ($previewText) {
3371 $html .= '
3372 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previewText. '")
3373 ';
3374 } else {
3375 $html .= '
3376 jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text("Click To Load Panorama")
3377 ';
3378 }
3379
3380 $html .= 'jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseenter", function(){
3381 jQuery(this).attr("title", jQuery(this).text());
3382 });
3383 jQuery("#pano' . $id . ' .pnlm-title-box").on("mouseleave", function(){
3384 jQuery(this).removeAttr("title");
3385 });';
3386 $html .= '});';
3387 $html .= '</script>';
3388
3389 $tour_data = [];
3390 if(defined("WPVR_PRO_VERSION")){
3391 $tour_data = array(
3392 'explainerControlSwitch' => ( isset( $custom_control['explainerSwitch'] ) && $custom_control['explainerSwitch'] === 'on' ) ? 'on' : 'off',
3393 'floor_plan_enable' => $floor_plan_enable ?? false,
3394 'floor_plan_image' => $floor_plan_image ?? '',
3395 'custom_control' => $custom_control ?? [],
3396 );
3397 }
3398 return apply_filters('wpvr_generate_tour_layout_html', $html ,$postdata ,$id, $tour_data);
3399 }
3400
3401 function sanitize_content_preserve_styles($content) {
3402 // Decode HTML entities first (in case content was encoded in database)
3403 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3404
3405 // Escape <script> blocks to display as text instead of removing them
3406 $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3407 return esc_html($matches[0]); // Convert to plain text
3408 }, $content);
3409
3410 // Strip dangerous URL-based attributes
3411 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3412
3413 // Escape inline event handlers (onclick, onhover, etc.) to display as text
3414 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*(["\'])([^"\']*)\2/i', function($matches) {
3415 // Escape the attribute value but keep the attribute name visible as text
3416 return ' ' . esc_html($matches[1]) . '=' . $matches[2] . esc_html($matches[3]) . $matches[2];
3417 }, $content);
3418 $content = preg_replace_callback('/\s*(on\w+)\s*=\s*([^>\s]+)/i', function($matches) {
3419 // Handle unquoted event handlers
3420 return ' ' . esc_html($matches[1]) . '=' . esc_html($matches[2]);
3421 }, $content);
3422
3423 // Remove all unsafe embedded/interactive elements except iframe
3424 $content = preg_replace('/<(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)\b[^>]*>/i', '', $content);
3425 $content = preg_replace('/<\/(object|embed|applet|frame|frameset|meta|link|base|form|input|button|textarea|select|option)>/i', '', $content);
3426
3427 // Clean style attributes safely
3428 $content = preg_replace_callback('/style\s*=\s*["\']([^"\']*)["\']/', function($matches) {
3429 $style = $matches[1];
3430 $style = preg_replace('/expression\s*\(/i', '', $style);
3431 $style = preg_replace('/(javascript|vbscript|data|about)\s*:/i', '', $style);
3432 $style = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $style);
3433 $style = preg_replace('/behavior\s*:/i', '', $style);
3434 $style = preg_replace('/-moz-binding\s*:/i', '', $style);
3435 return 'style="' . esc_attr($style) . '"';
3436 }, $content);
3437
3438 // Sanitize <style> blocks
3439 $content = preg_replace_callback('/<style\b[^>]*>(.*?)<\/style>/si', function($matches) {
3440 $css = $matches[1];
3441 $css = preg_replace('/(expression|javascript|vbscript|data|about)\s*:/i', '', $css);
3442 $css = preg_replace('/url\s*\(\s*["\']?\s*(javascript|vbscript|data):/i', '', $css);
3443 $css = preg_replace('/behavior\s*:/i', '', $css);
3444 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3445 return '<style>' . esc_html($css) . '</style>';
3446 }, $content);
3447
3448 // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3449 $allowed_tags = wp_kses_allowed_html('post');
3450 $allowed_tags['iframe'] = [
3451 'src' => true,
3452 'width' => true,
3453 'height' => true,
3454 'frameborder' => true,
3455 'allowfullscreen' => true,
3456 'class' => true,
3457 'style' => true,
3458 'title' => true,
3459 'allow' => true,
3460 'name' => true,
3461 'referrerpolicy' => true,
3462 'loading' => true,
3463 'sandbox' => true,
3464 ];
3465 $allowed_tags['img'] = [
3466 'src' => true,
3467 'alt' => true,
3468 'title' => true,
3469 'width' => true,
3470 'height' => true,
3471 'class' => true,
3472 'id' => true,
3473 'style' => true,
3474 'loading' => true,
3475 'srcset' => true,
3476 'sizes' => true,
3477 ];
3478
3479 // Apply wp_kses() to keep only allowed tags/attributes
3480 $content = wp_kses($content, $allowed_tags);
3481
3482 // Finally, validate iframe src for security (allow https only, block javascript: etc.)
3483 $content = preg_replace_callback('/<iframe[^>]+src=["\']([^"\']+)["\'][^>]*>(?:<\/iframe>)?/i', function($matches) {
3484 $src = $matches[1];
3485 // Allow any https:// or http:// URL, but block javascript:, data:, vbscript:, etc.
3486 if (preg_match('/^(https?:)?\/\//i', $src) && !preg_match('/^(javascript|data|vbscript|about):/i', $src)) {
3487 return $matches[0]; // keep safe iframe
3488 }
3489 // Strip unsafe iframe
3490 return '';
3491 }, $content);
3492
3493 return $content;
3494 }
3495 function wpvr_hex2rgb($colour)
3496 {
3497 if (isset($colour[0]) && $colour[0] == '#') {
3498 $colour = substr($colour, 1);
3499 }
3500 if (strlen($colour) == 6) {
3501 list($r, $g, $b) = array($colour[0] . $colour[1], $colour[2] . $colour[3], $colour[4] . $colour[5]);
3502 } elseif (strlen($colour) == 3) {
3503 list($r, $g, $b) = array($colour[0] . $colour[0], $colour[1] . $colour[1], $colour[2] . $colour[2]);
3504 } else {
3505 return false;
3506 }
3507 $r = hexdec($r);
3508 $g = hexdec($g);
3509 $b = hexdec($b);
3510 return array($r . ', ' . $g . ', ' . $b);
3511 }
3512
3513 function wpvr_HTMLToRGB($htmlCode)
3514 {
3515 $r = 0;
3516 $g = 0;
3517 $b = 0;
3518 if (isset($htmlCode[0]) && $htmlCode[0] == '#') {
3519 $htmlCode = substr($htmlCode, 1);
3520 }
3521
3522 if (strlen($htmlCode) == 3) {
3523 $htmlCode = $htmlCode[0] . $htmlCode[0] . $htmlCode[1] . $htmlCode[1] . $htmlCode[2] . $htmlCode[2];
3524 }
3525
3526 if (isset($htmlCode[0]) && isset($htmlCode[1])) {
3527 $r = hexdec($htmlCode[0] . $htmlCode[1]);
3528 }
3529 if (isset($htmlCode[2]) && isset($htmlCode[3])) {
3530 $g = hexdec($htmlCode[2] . $htmlCode[3]);
3531 }
3532 if (isset($htmlCode[4]) && isset($htmlCode[5])) {
3533 $b = hexdec($htmlCode[4] . $htmlCode[5]);
3534 }
3535
3536 return $b + ($g << 0x8) + ($r << 0x10);
3537 }
3538
3539 function wpvr_RGBToHSL($RGB)
3540 {
3541 $r = 0xFF & ($RGB >> 0x10);
3542 $g = 0xFF & ($RGB >> 0x8);
3543 $b = 0xFF & $RGB;
3544
3545 $r = ((float)$r) / 255.0;
3546 $g = ((float)$g) / 255.0;
3547 $b = ((float)$b) / 255.0;
3548
3549 $maxC = max($r, $g, $b);
3550 $minC = min($r, $g, $b);
3551
3552 $l = ($maxC + $minC) / 2.0;
3553
3554 if ($maxC == $minC) {
3555 $s = 0;
3556 $h = 0;
3557 } else {
3558 if ($l < .5) {
3559 $s = ($maxC - $minC) / ($maxC + $minC);
3560 } else {
3561 $s = ($maxC - $minC) / (2.0 - $maxC - $minC);
3562 }
3563 if ($r == $maxC) {
3564 $h = ($g - $b) / ($maxC - $minC);
3565 }
3566 if ($g == $maxC) {
3567 $h = 2.0 + ($b - $r) / ($maxC - $minC);
3568 }
3569 if ($b == $maxC) {
3570 $h = 4.0 + ($r - $g) / ($maxC - $minC);
3571 }
3572
3573 $h = $h / 6.0;
3574 }
3575
3576 $h = (int)round(255.0 * $h);
3577 $s = (int)round(255.0 * $s);
3578 $l = (int)round(255.0 * $l);
3579
3580 return (object) array('hue' => $h, 'saturation' => $s, 'lightness' => $l);
3581 }
3582
3583 add_action('rest_api_init', 'wpvr_rest_data_route');
3584 function wpvr_rest_data_route()
3585 {
3586 register_rest_route('wpvr/v1', '/panodata/', array(
3587 'methods' => 'GET',
3588 'callback' => 'wpvr_rest_data_set',
3589 'permission_callback' => 'wpvr_rest_route_permission'
3590 ));
3591 }
3592
3593 function wpvr_rest_route_permission()
3594 {
3595 return true;
3596 }
3597
3598 function wpvr_rest_data_set()
3599 {
3600 $query = new WP_Query(array(
3601 'post_type' => 'wpvr_item',
3602 'posts_per_page' => -1,
3603 ));
3604
3605 $wpvr_list = array();
3606 $list_none = array('value' => 0, 'label' => 'None');
3607 array_push($wpvr_list, $list_none);
3608 while ($query->have_posts()) {
3609 $query->the_post();
3610 $title = mb_convert_encoding(get_the_title(), 'UTF-8', 'HTML-ENTITIES');
3611 $post_id = get_the_ID();
3612 $title = $post_id . ' : ' . $title;
3613 $list_ob = array('value' => $post_id, 'label' => $title);
3614 array_push($wpvr_list, $list_ob);
3615 }
3616
3617 return $wpvr_list;
3618 }
3619
3620 function wpvr_isMobileDevice()
3621 {
3622 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"]);
3623 }
3624
3625 function wpvr_directory()
3626 {
3627 $upload = wp_upload_dir();
3628 $upload_dir = $upload['basedir'];
3629 $upload_dir_temp = $upload_dir . '/wpvr/temp/';
3630 if (!is_dir($upload_dir_temp)) {
3631 wp_mkdir_p($upload_dir_temp, 0700);
3632 }
3633 }
3634
3635 add_action('admin_init', 'wpvr_directory');
3636
3637
3638 function wpvr_add_role_cap()
3639 {
3640 $editor_active = get_option('wpvr_editor_active');
3641
3642 $author_active = get_option('wpvr_author_active');
3643
3644 $admin = get_role('administrator');
3645 $admin->add_cap('publish_wpvr_tour');
3646 $admin->add_cap('edit_wpvr_tours');
3647 $admin->add_cap('read_wpvr_tour');
3648 $admin->add_cap('edit_wpvr_tour');
3649 $admin->add_cap('edit_wpvr_tours');
3650 $admin->add_cap('publish_wpvr_tours');
3651 $admin->add_cap('publish_wpvr_tour');
3652 $admin->add_cap('delete_wpvr_tour');
3653 $admin->add_cap('edit_other_wpvr_tours');
3654 $admin->add_cap('delete_other_wpvr_tours');
3655
3656 if ($editor_active == "true") {
3657 $editor = get_role('editor');
3658 if ($editor) {
3659 $editor->add_cap('publish_wpvr_tour');
3660 $editor->add_cap('edit_wpvr_tours');
3661 $editor->add_cap('read_wpvr_tour');
3662 $editor->add_cap('edit_wpvr_tour');
3663 $editor->add_cap('edit_wpvr_tours');
3664 $editor->add_cap('publish_wpvr_tours');
3665 $editor->add_cap('publish_wpvr_tour');
3666 $editor->add_cap('delete_wpvr_tour');
3667 $editor->add_cap('edit_other_wpvr_tours');
3668 $editor->add_cap('delete_other_wpvr_tours');
3669 }
3670 } else {
3671 $editor = get_role('editor');
3672 if ($editor) {
3673 $editor->remove_cap('publish_wpvr_tour');
3674 $editor->remove_cap('edit_wpvr_tours');
3675 $editor->remove_cap('read_wpvr_tour');
3676 $editor->remove_cap('edit_wpvr_tour');
3677 $editor->remove_cap('edit_wpvr_tours');
3678 $editor->remove_cap('publish_wpvr_tours');
3679 $editor->remove_cap('publish_wpvr_tour');
3680 $editor->remove_cap('delete_wpvr_tour');
3681 $editor->remove_cap('edit_other_wpvr_tours');
3682 $editor->remove_cap('delete_other_wpvr_tours');
3683 }
3684 }
3685
3686 if ($author_active == "true") {
3687 $author = get_role('author');
3688 if ($author) {
3689 $author->add_cap('read_wpvr_tour');
3690 $author->add_cap('edit_wpvr_tour');
3691 $author->add_cap('edit_wpvr_tours');
3692 $author->add_cap('publish_wpvr_tours');
3693 $author->add_cap('publish_wpvr_tour');
3694 $author->add_cap('delete_wpvr_tour');
3695 }
3696 } else {
3697 $author = get_role('author');
3698 if ($author) {
3699 $author->remove_cap('read_wpvr_tour');
3700 $author->remove_cap('edit_wpvr_tour');
3701 $author->remove_cap('edit_wpvr_tours');
3702 $author->remove_cap('publish_wpvr_tours');
3703 $author->remove_cap('publish_wpvr_tour');
3704 $author->remove_cap('delete_wpvr_tour');
3705 }
3706 }
3707
3708 if(is_plugin_active( 'dokan-lite/dokan.php' ) || is_plugin_active( 'dokan-pro/dokan.php' )){
3709 $dokan_vendor_active = get_option('dokan_vendor_active');
3710
3711 if( 'true' === $dokan_vendor_active){
3712 $seller = get_role('seller');
3713 if ($seller) {
3714 $seller->add_cap('read_wpvr_tour');
3715 $seller->add_cap('edit_wpvr_tour');
3716 $seller->add_cap('edit_wpvr_tours');
3717 $seller->add_cap('publish_wpvr_tours');
3718 $seller->add_cap('publish_wpvr_tour');
3719 $seller->add_cap('delete_wpvr_tour');
3720 }
3721 } else{
3722 $seller = get_role('seller');
3723 if ($seller) {
3724 $seller->remove_cap('read_wpvr_tour');
3725 $seller->remove_cap('edit_wpvr_tour');
3726 $seller->remove_cap('edit_wpvr_tours');
3727 $seller->remove_cap('publish_wpvr_tours');
3728 $seller->remove_cap('publish_wpvr_tour');
3729 $seller->remove_cap('delete_wpvr_tour');
3730 }
3731 }
3732 }
3733
3734
3735 }
3736
3737 add_action('admin_init', 'wpvr_add_role_cap', 999);
3738
3739 function wpvr_role_management_from_post_type($args, $post_type)
3740 {
3741 if ('wpvr_item' !== $post_type) {
3742 return $args;
3743 }
3744
3745 $editor_active = get_option('wpvr_editor_active');
3746 $author_active = get_option('wpvr_author_active');
3747 $user = wp_get_current_user();
3748
3749 if ($editor_active == "true") {
3750 if (in_array('editor', (array) $user->roles)) {
3751 $args['show_in_menu'] = true;
3752 }
3753 }
3754
3755 if ($author_active == "true") {
3756 if (in_array('author', (array) $user->roles)) {
3757 $args['show_in_menu'] = true;
3758 }
3759 }
3760
3761 if(is_plugin_active( 'dokan-lite/dokan.php' ) || is_plugin_active( 'dokan-pro/dokan.php' )){
3762 $dokan_vendor_active = get_option('dokan_vendor_active');
3763 if( 'true' === $dokan_vendor_active){
3764 if (in_array('seller', (array) $user->roles)) {
3765 $args['show_in_menu'] = true;
3766 }
3767 }
3768
3769 }
3770
3771 return $args;
3772 }
3773 add_filter('register_post_type_args', 'wpvr_role_management_from_post_type', 10, 2);
3774
3775 function wpvr_cache_admin_notice()
3776 {
3777 $option = get_option('wpvr_warning');
3778 if (!$option) {
3779 ?>
3780 <div class="notice notice-warning" id="wpvr-warning" style="position: relative;">
3781 <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>
3782 <button type="button" id="wpvr-dismissible" class="notice-dismiss"><span class="screen-reader-text">Dismiss this notice.</span></button>
3783 </div>
3784 <?php
3785 }
3786 }
3787 // add_action('admin_notices', 'wpvr_cache_admin_notice');
3788
3789 //===Oxygen widget===//
3790 add_action('plugins_loaded', function () {
3791 if (!class_exists('OxyEl')) {
3792 return;
3793 }
3794 require_once __DIR__ . '/oxygen/oxy-manager.php';
3795 });
3796
3797 add_action('init', 'wpvr_mobile_media_handle');
3798 function wpvr_mobile_media_handle()
3799 {
3800 add_image_size('wpvr_mobile', 4096, 2048); //mobile
3801 }
3802
3803
3804 add_action(
3805 /**
3806 * @param $api \VisualComposer\Modules\Api\Factory
3807 */
3808 'vcv:api',
3809 function ($api) {
3810 $elementsToRegister = [
3811 'wpvrelement',
3812 ];
3813 $pluginBaseUrl = rtrim(plugins_url(basename(__DIR__)), '\\/');
3814 /** @var \VisualComposer\Modules\Elements\ApiController $elementsApi */
3815 $elementsApi = $api->elements;
3816 foreach ($elementsToRegister as $tag) {
3817 $manifestPath = __DIR__ . '/vc/' . $tag . '/manifest.json';
3818 $elementBaseUrl = $pluginBaseUrl . '/vc/' . $tag;
3819 $elementsApi->add($manifestPath, $elementBaseUrl);
3820 }
3821 }
3822 );
3823
3824 function wpvr_redirect_after_activation($plugin)
3825 {
3826 if ($plugin == plugin_basename(__FILE__)) {
3827 $url = admin_url('admin.php?page=rex-wpvr-setup-wizard');
3828 $url = esc_url($url, FILTER_SANITIZE_URL);
3829 exit(wp_safe_redirect($url));
3830 }
3831 }
3832 //add_action('activated_plugin', 'wpvr_redirect_after_activation');
3833
3834 function replace_callback($matches)
3835 {
3836 foreach ($matches as $match) {
3837 return str_replace('<img', '<img decoding="async" ', $match);
3838 }
3839 }
3840
3841
3842 function wpvr_sanitize_iframe_only( $input ) {
3843 // Start with standard allowed post HTML (p, a, strong, etc.)
3844 $allowed_tags = wp_kses_allowed_html( 'post' );
3845
3846 // Explicitly allow <iframe> with specific safe attributes
3847 $allowed_tags['iframe'] = array(
3848 'src' => true,
3849 'width' => true,
3850 'height' => true,
3851 'title' => true,
3852 'frameborder' => true,
3853 'allow' => true,
3854 'allowfullscreen' => true,
3855 'referrerpolicy' => true,
3856 );
3857
3858 // Sanitize input
3859 return wp_kses( $input, $allowed_tags );
3860 }
3861
3862
3863