PluginProbe
WP VR – 360 Panorama and Virtual Tour Builder / 8.5.74
WP VR – 360 Panorama and Virtual Tour Builder v8.5.74
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.74, at wpvr.php

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