$autoplay,
'loop' => $loop
);
}
/**
* Prepare meta data when video url has youtube
*
* @param string $videourl
*
* @return string
* @since 8.0.0
*/
public function prepare_youtube_video_meta_data($videourl, $videodata)
{
$explodeid = '';
$explodeid = explode("=", $videourl);
if ($videodata['autoplay'] == 'on') {
$autoplay = '&autoplay=1';
} else {
$autoplay = '';
}
if ($videodata['loop'] == 'on') {
$loop = '&loop=1';
} else {
$loop = '';
}
$foundid = '';
$foundid = $explodeid[1] . '?' . $autoplay . $loop;
$html = '';
$html .= '';
return $html;
}
/**
* Prepare meta data when video url has youtu.be
*
* @param string $videourl
*
* @return string
* @since 8.0.0
*/
public function prepare_youtu_be_video_meta_data($videourl, $videodata)
{
$explodeid = '';
$explodeid = explode("/", $videourl);
if ($videodata['autoplay'] == 'on') {
$autoplay = '&autoplay=1';
} else {
$autoplay = '';
}
if ($videodata['loop'] == 'on') {
$loop = '&loop=1';
} else {
$loop = '';
}
$foundid = '';
$foundid = $explodeid[3] . '?' . $autoplay . $loop;
$html = '';
$html .= '';
return $html;
}
/**
* Prepare meta data when video url has vimeo
*
* @param string $videourl
*
* @return string
* @since 8.0.0
*/
public function prepare_vimeo_video_meta_data($videourl, $videodata)
{
$vid_parts = explode( '/', rtrim( $videourl, '/' ) );
$vid_id = end( $vid_parts );
$do_autoplay = ( $videodata['autoplay'] === 'on' ) ? 'true' : 'false';
$do_loop = ( $videodata['loop'] === 'on' ) ? 'true' : 'false';
$autoplay_param = ( $videodata['autoplay'] === 'on' ) ? 'autoplay=1&muted=1' : '';
$loop_param = '';
$query_parts = array_filter( [ $autoplay_param, $loop_param ] );
$foundid = ! empty( $query_parts ) ? $vid_id . '?' . implode( '&', $query_parts ) : $vid_id;
$iframe_id = 'wpvr-vimeo-preview-' . wp_rand( 10000, 99999 );
$html = '';
$html .= '';
$html .= '';
return $html;
}
/**
* Prepare meta data when video is selfhosted
*
* @param string $videourl
*
* @return string
* @since 8.0.0
*/
public function prepare_selfhost_video_meta_data($videourl, $vidid, $videodata)
{
if ($videodata['autoplay'] == 'on') {
$autoplay = 'autoplay muted';
} else {
$autoplay = '';
}
if ($videodata['loop'] == 'on') {
$loop = 'loop';
} else {
$loop = '';
}
$html = '';
$html .= '';
return $html;
}
/**
* Prepare scene data for Tour preview
*
* @param array $panodata
*
* @return array
* @since 8.0.0
*/
public function prepare_scene_data_for_preview($panodata)
{
$scene_data = array();
foreach ($panodata["scene-list"] as $panoscenes) {
if (!empty($panoscenes['scene-id'])) {
$scene_ititle = sanitize_text_field(@$panoscenes["scene-ititle"]);
$scene_author = sanitize_text_field(@$panoscenes["scene-author"]);
$scene_vaov = isset($panoscenes["scene-vaov"]) ? (float)$panoscenes["scene-vaov"] : 180;
$scene_haov = isset($panoscenes["scene-vaov"]) ? (float)$panoscenes["scene-haov"] : 360;
$scene_vertical_offset = isset($panoscenes["scene-vertical-offset"]) ? (float)$panoscenes["scene-vertical-offset"] : 0;
$default_scene_pitch = isset($panoscenes["scene-pitch"]) ? (float)$panoscenes["scene-pitch"] : null;
$default_scene_yaw = isset($panoscenes["scene-yaw"]) ? (float)$panoscenes["scene-yaw"] : null;
$scene_max_pitch = isset($panoscenes["scene-maxpitch"]) ? (float)$panoscenes["scene-maxpitch"] : '';
$scene_min_pitch = isset($panoscenes["scene-minpitch"]) ? (float)$panoscenes["scene-minpitch"] : '';
$scene_max_yaw = isset($panoscenes["scene-maxyaw"]) ? (float)$panoscenes["scene-maxyaw"] : '';
$scene_min_yaw = isset($panoscenes["scene-minyaw"]) ? (float)$panoscenes["scene-minyaw"] : '';
$default_zoom = isset($panoscenes["scene-zoom"]) ? $panoscenes["scene-zoom"] : 100;
if (!empty($default_zoom)) {
$default_zoom = isset($panoscenes["scene-zoom"]) ? (int)$panoscenes["scene-zoom"] : (int)$default_zoom;
} else {
$default_zoom = 100;
}
$max_zoom = isset($panoscenes["scene-maxzoom"]) ? $panoscenes["scene-maxzoom"] : 120;
if (!empty($max_zoom)) {
$max_zoom = isset($panoscenes["scene-maxzoom"]) ? (int)$panoscenes["scene-maxzoom"] : (int)$max_zoom;
} else {
$max_zoom = 120;
}
$min_zoom = isset($panoscenes["scene-minzoom"]) ? $panoscenes["scene-minzoom"] : 50;
if (!empty($min_zoom)) {
$min_zoom = isset($panoscenes["scene-minzoom"]) ? (int)$panoscenes["scene-minzoom"] : (int)$min_zoom;
} else {
$min_zoom = 50;
}
$hotspot_datas = $panoscenes["hotspot-list"];
$hotspots = $this->prepare_hotspot_data_for_preview($hotspot_datas);
$scene_info = array();
if ($panoscenes["scene-type"] == 'cubemap') {
$pano_type = 'cubemap';
$pano_attachment = array(
$panoscenes["scene-attachment-url-face0"],
$panoscenes["scene-attachment-url-face1"],
$panoscenes["scene-attachment-url-face2"],
$panoscenes["scene-attachment-url-face3"],
$panoscenes["scene-attachment-url-face4"],
$panoscenes["scene-attachment-url-face5"]
);
$scene_info = array("type" => $panoscenes["scene-type"], "cubeMap" => $pano_attachment, "pitch" => $default_scene_pitch, "maxPitch" => $scene_max_pitch, "minPitch" => $scene_min_pitch, "maxYaw" => $scene_max_yaw, "minYaw" => $scene_min_yaw, "yaw" => $default_scene_yaw, "hfov" => $default_zoom, "maxHfov" => $max_zoom, "minHfov" => $min_zoom, "title" => $scene_ititle, "author" => $scene_author, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
} else {
$scene_info = array("type" => $panoscenes["scene-type"], "panorama" => $panoscenes["scene-attachment-url"], "pitch" => $default_scene_pitch, "maxPitch" => $scene_max_pitch, "minPitch" => $scene_min_pitch, "maxYaw" => $scene_max_yaw, "minYaw" => $scene_min_yaw, "yaw" => $default_scene_yaw, "hfov" => $default_zoom, "maxHfov" => $max_zoom, "minHfov" => $min_zoom, "title" => $scene_ititle, "author" => $scene_author, "vaov" => $scene_vaov, "haov" => $scene_haov, "vOffset" => $scene_vertical_offset, "hotSpots" => $hotspots);
}
if (empty($panoscenes["scene-ititle"])) {
unset($scene_info['title']);
}
if (empty($panoscenes["scene-author"])) {
unset($scene_info['author']);
}
if (empty($scene_vaov)) {
unset($scene_info['vaov']);
}
if (empty($scene_haov)) {
unset($scene_info['haov']);
}
if (empty($scene_vertical_offset)) {
unset($scene_info['vOffset']);
}
if (isset($panoscenes["cvgscene"])) {
if ($panoscenes["cvgscene"] == "off") {
unset($scene_info['maxPitch']);
unset($scene_info['minPitch']);
}
}
if (empty($panoscenes["scene-maxpitch"])) {
unset($scene_info['maxPitch']);
}
if (empty($panoscenes["scene-minpitch"])) {
unset($scene_info['minPitch']);
}
if (isset($panoscenes["chgscene"])) {
if ($panoscenes["chgscene"] == "off") {
unset($scene_info['maxYaw']);
unset($scene_info['minYaw']);
}
}
if (empty($panoscenes["scene-maxyaw"])) {
unset($scene_info['maxYaw']);
}
if (empty($panoscenes["scene-minyaw"])) {
unset($scene_info['minYaw']);
}
$scene_array = array();
$scene_array = array(
$panoscenes["scene-id"] => $scene_info
);
$scene_data[$panoscenes["scene-id"]] = $scene_info;
}
}
return $scene_data;
}
/**
* Preapre hotspot data for Tour preview
*
* @param array $hotspot_datas
*
* @return array
* @since 8.0.0
*/
private function prepare_hotspot_data_for_preview($hotspot_datas)
{
$hotspots = array();
foreach ($hotspot_datas as $hotspot_data) {
if (!empty($hotspot_data["hotspot-title"])) {
$hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
$hotspot_content = '';
ob_start();
do_action('wpvr_hotspot_content_admin', $hotspot_data);
$hotspot_content = ob_get_clean();
$is_fluent_form = ($hotspot_data['hotspot-type'] ?? '') === 'fluent_form';
if ($is_fluent_form) {
if ($hotspot_content) {
$hotspot_content = preg_replace('/';
return $html;
}
/**
* Extract YouTube video ID from various URL formats.
*
* Handles youtube.com/watch?v=, youtu.be/, youtube.com/embed/, and youtube.com/v/ formats.
* Strips extra query parameters and sanitizes the ID to only valid YouTube characters.
*
* @param string $url The YouTube video URL.
*
* @return string The sanitized YouTube video ID, or empty string on failure.
* @since 8.0.0
*/
private function extract_youtube_video_id( $url ) {
$url = trim( $url );
$parsed = wp_parse_url( $url );
// Handle youtu.be short URLs.
if ( isset( $parsed['host'] ) && 'youtu.be' === $parsed['host'] ) {
$video_id = isset( $parsed['path'] ) ? ltrim( $parsed['path'], '/' ) : '';
return preg_replace( '/[^A-Za-z0-9_\-]/', '', $video_id );
}
// Handle youtube.com/embed/VIDEO_ID or youtube.com/v/VIDEO_ID.
if ( isset( $parsed['path'] ) && preg_match( '#/(embed|v)/([A-Za-z0-9_\-]+)#', $parsed['path'], $matches ) ) {
return $matches[2];
}
// Handle youtube.com/watch?v=VIDEO_ID (standard format).
if ( isset( $parsed['query'] ) ) {
parse_str( $parsed['query'], $query_params );
if ( ! empty( $query_params['v'] ) ) {
return preg_replace( '/[^A-Za-z0-9_\-]/', '', $query_params['v'] );
}
}
// Fallback: try naive extraction for edge cases.
if ( preg_match( '/[?&]v=([A-Za-z0-9_\-]+)/', $url, $matches ) ) {
return $matches[1];
}
return '';
}
/**
* Prepare shortcode data for youtube video url
*
* @param array $postdata
* @param mixed $width
* @param mixed $height
*
* @return string
* @since 8.0.0
*/
public function prepare_youtube_video_shortcode_data($postdata, $width, $height, $autoplay, $loop, $radius)
{
$muted = ($autoplay == 'on') ? '&mute=1' : '';
$autoplay = ($autoplay == 'on') ? '&autoplay=1' : '';
$loop = ($loop == 'on') ? '&loop=1' : '';
$origin = '&origin=' . rawurlencode( home_url() );
$expdata = $this->extract_youtube_video_id( $postdata['vidurl'] );
$playlist = '&playlist=' . $expdata;
$html = '';
$html .= '
';
// Add browser compatibility detection script
$html .= '';
$random_id = 'video-container-' . wp_rand(10000, 99999);
$html .= '
';
// First, always check browser compatibility before showing anything
$html .= '
Checking browser compatibility...
';
// Add animation for spinner
$html .= '';
// Add the iframe (visible by default so YouTube 360° WebGL context gets correct dimensions)
$html .= '
';
$html .= '';
$html .= '
';
$html .= '
';
// Custom control bar
$html .= '
';
// Play/Pause button
$html .= '
';
// Time current
$html .= '
0:00';
// Progress bar
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
// Time duration
$html .= '
0:00';
// Mute button
$html .= '
';
// Volume slider (popup on mute hover)
$html .= '';
$html .= '
';
$html .= '';
$html .= '
';
// Fullscreen button
$html .= '
';
$html .= '
'; // Close controls
// Add browser compatibility warning message
$html .= '
';
$html .= '
';
$html .= '
For the best experience, use a browser with WebGL support.
';
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
YouTube 360 is limited in mobile browser embeds.
';
$html .= '
For proper 360 playback, open this video in the YouTube app.
';
$html .= '
Open in YouTube';
$html .= '
Show Here Anyway';
$html .= '
';
// Main script for handling compatibility and permissions
$html .= '';
$html .= '
'; // Close container
$html .= '
'; // Close outer container
return $html;
}
/**
* Prepare shortcode data for Vimeo url
*
* @param array $postdata
* @param mixed $width
* @param mixed $height
*
* @return string
* @since 8.0.0
*/
public function prepare_vimeo_video_shortcode_data($postdata, $width, $height, $autoplay, $loop, $radius)
{
$autoplay_param = ($autoplay == 'on') ? 'autoplay=1&muted=1' : '';
$loop_param = ($loop == 'on') ? 'loop=1' : '';
$vidurl_parts = explode('/', rtrim( $postdata['vidurl'], '/' ) );
$vid_id = end($vidurl_parts);
$query_parts = array_filter( [ $autoplay_param, $loop_param ] );
$foundid = !empty($query_parts) ? $vid_id . '?' . implode('&', $query_parts) : $vid_id;
$iframe_id = 'wpvr-vimeo-' . wp_rand( 10000, 99999 );
$do_autoplay = ( $autoplay == 'on' ) ? 'true' : 'false';
$do_loop = ( $loop == 'on' ) ? 'true' : 'false';
$html = '';
$html .= '';
$html .= '';
$html .= '
';
$html .= '';
return $html;
}
/**
* Prepare shortcode data from regular postdata
*
* @param integer $id
* @param array $postdata
* @param string $width
* @param string $height
*
* @return string
* @since 8.0.0
*/
public function prepare_regular_video_shortcode_data($id, $postdata, $width, $height, $radius)
{
$unique_suffix = wp_rand(1000, 99999);
$pano_id = 'pano' . $id . '_' . $unique_suffix;
$vid_id = 'wpvr-vid-' . $id . '-' . $unique_suffix;
if ( ! empty( $postdata['vidurl'] ) ) {
$panoviddata = $this->prepare_selfhost_video_meta_data( $postdata['vidurl'], $vid_id, $postdata );
} elseif ( ! empty( $postdata['panoviddata'] ) ) {
$panoviddata = preg_replace( '/\bid=["\'][^"\']*["\']/i', 'id="' . esc_attr( $vid_id ) . '"', $postdata['panoviddata'], 1 );
} else {
$panoviddata = '';
}
$html = '';
$html .= '';
$html .= '
' . $panoviddata . '
';
$html .= '
';
$html .= '
';
//video js vr setup //
$html .= '';
//video js vr end //
return $html;
}
/**
* Prepare scene data for shortcode
*
* @param array $panodata
*
* @return array
* @since 8.0.0
*/
public function prepare_shortcode_scene_data($panodata)
{
$scene_data = array();
if (!empty($panodata["scene-list"])) {
$scene_data = $this->prepare_shortcode_scene_list($panodata);
}
return $scene_data;
}
/**
* Prepare scene lists data for shortcode
*
* @param array $panodata
*
* @return array
* @since 8.0.0
*/
private function prepare_shortcode_scene_list($panodata)
{
$scene_data = array();
foreach ($panodata["scene-list"] as $panoscenes) {
$hotspot_datas = array();
if (isset($panoscenes["hotspot-list"])) {
$hotspot_datas = $panoscenes["hotspot-list"];
}
$hotspots = $this->prepare_shortcode_hotspots_list($hotspot_datas);
$device_scene = $this->get_shortcode_device_scene($panoscenes['scene-attachment-url']);
$scene_info = $this->get_shortcode_scene_info($panoscenes, $hotspots, $device_scene);
$scene_data[$panoscenes["scene-id"]] = $scene_info;
}
return $scene_data;
}
/**
* Prepare hotspots list for shortcode
*
* @param array $hotspot_datas
*
* @return array
* @since 8.0.0
*/
private function prepare_shortcode_hotspots_list($hotspot_datas)
{
$hotspots = array();
foreach ($hotspot_datas as $hotspot_data) {
$hotspot_type = $hotspot_data["hotspot-type"] !== 'scene' ? 'info' : $hotspot_data["hotspot-type"];
$hotspot_content = ($hotspot_data["hotspot-type"] ?? '') === 'fluent_form' ? '' : ($hotspot_data["hotspot-content"] ?? '');
$hotspot_info = $this->get_shortcode_hotspot_info($hotspot_data, $hotspot_type, $hotspot_content);
array_push($hotspots, $hotspot_info);
}
return $hotspots;
}
/**
* Return hotspot info array to hotspot list
*
* @param array $hotspot_data
* @param string $hotspot_type
* @param string $hotspot_content
*
* @return array
* @since 8.0.0
*/
private function get_shortcode_hotspot_info($hotspot_data, $hotspot_type, $hotspot_content)
{
$is_sticker = ( ( $hotspot_data['hotspot-type'] ?? '' ) === 'sticker' );
$hotspot_info = array(
"text" => $hotspot_data["hotspot-title"],
"pitch" => $hotspot_data["hotspot-pitch"],
"yaw" => $hotspot_data["hotspot-yaw"],
"type" => $hotspot_type,
"cssClass" => $hotspot_data["hotspot-customclass"],
"URL" => $hotspot_data["hotspot-url"],
"wpvr_url_open" => isset($hotspot_data["wpvr_url_open"][0]) ? $hotspot_data["wpvr_url_open"][0] : 'off',
"clickHandlerArgs" => sanitize_content_preserve_styles($hotspot_content, ($hotspot_data['hotspot-type'] ?? '') === 'fluent_form'),
"createTooltipArgs" => sanitize_content_preserve_styles($hotspot_data["hotspot-hover"] ?? '', false),
"sceneId" => $hotspot_data["hotspot-scene"],
'hotspot_type' => $hotspot_data['hotspot-type'],
'scale' => isset($hotspot_data['hotspot-scale']) ? ($hotspot_data['hotspot-scale'] === 'on' || $hotspot_data['hotspot-scale'] === true) : $is_sticker
);
$hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
if ( $is_sticker ) {
$custom_class_pro = ! empty( $hotspot_data['hotspot-customclass'] ) && $hotspot_data['hotspot-customclass'] !== 'none'
? ' ' . $hotspot_data['hotspot-customclass']
: '';
$hotspot_info['cssClass'] = 'wpvr-hs-custom wpvr-hs-sticker' . $custom_class_pro;
$hotspot_info['stickerTemplate'] = $hotspot_data['hotspot-sticker-template'] ?? 'social_proof';
$hotspot_info['stickerReviewText'] = $hotspot_data['hotspot-sticker-review-text'] ?? 'The support is super responsive and responds without worries to our requests and needs! Big up to the entire RexTheme team!';
$hotspot_info['stickerClientName'] = $hotspot_data['hotspot-sticker-client-name'] ?? 'Elena R.';
$hotspot_info['stickerClientAvatar'] = $hotspot_data['hotspot-sticker-client-avatar'] ?? '';
$hotspot_info['stickerRating'] = isset( $hotspot_data['hotspot-sticker-rating'] ) ? (int) $hotspot_data['hotspot-sticker-rating'] : 5;
$is_separate_icon = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'button_with_separate_icon';
$is_add_to_cart = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'add_to_cart';
$is_social_share = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'social_share';
$hotspot_info['stickerBgColor'] = $hotspot_data['hotspot-sticker-bg-color'] ?? '#201b2c';
$hotspot_info['stickerBgOpacity'] = isset( $hotspot_data['hotspot-sticker-bg-opacity'] ) ? (float) $hotspot_data['hotspot-sticker-bg-opacity'] : ( ( $is_separate_icon || $is_add_to_cart || $is_social_share ) ? 75 : 95 );
$hotspot_info['stickerBlur'] = isset( $hotspot_data['hotspot-sticker-blur'] ) ? (float) $hotspot_data['hotspot-sticker-blur'] : 12;
$hotspot_info['stickerBrightness'] = isset( $hotspot_data['hotspot-sticker-brightness'] ) ? (float) $hotspot_data['hotspot-sticker-brightness'] : 100;
$hotspot_info['stickerTextColor'] = $hotspot_data['hotspot-sticker-text-color'] ?? '#ffffff';
$hotspot_info['stickerBorderColor'] = $hotspot_data['hotspot-sticker-border-color'] ?? ( ( $is_separate_icon || $is_add_to_cart || $is_social_share ) ? '#40355a' : '#3a3051' );
$default_radius = $is_separate_icon ? 135 : ( ( $is_add_to_cart || $is_social_share ) ? 15 : 20 );
$hotspot_info['stickerBorderRadius'] = $hotspot_data['hotspot-sticker-border-radius'] ?? [
'topLeft' => $default_radius,
'topRight' => $default_radius,
'bottomRight' => $default_radius,
'bottomLeft' => $default_radius,
];
$hotspot_info['stickerPadding'] = $hotspot_data['hotspot-sticker-padding'] ?? [
'top' => 21,
'right' => 21,
'bottom' => 21,
'left' => 21,
];
$hotspot_info['stickerStarColor'] = $hotspot_data['hotspot-sticker-star-color'] ?? '#EF991F';
// Text before button (for add_to_cart)
$hotspot_info['stickerPrefixText'] = $hotspot_data['hotspot-sticker-prefix-text'] ?? '$1,090 -';
$hotspot_info['stickerSubText'] = $hotspot_data['hotspot-sticker-sub-text'] ?? 'Ready to ship';
// Discount button, add to cart & social share sticker fields
$hotspot_info['stickerBtnText'] = $hotspot_data['hotspot-sticker-btn-text'] ?? ( $is_social_share ? 'SHARE EXPERIENCE' : ( $is_add_to_cart ? 'ADD TO CART' : ( $is_separate_icon ? 'Limited “Midnight Horizon” Edition' : 'GET 20% OFF NOW' ) ) );
$hotspot_info['stickerBtnColor'] = $hotspot_data['hotspot-sticker-btn-color'] ?? ( $is_social_share ? '#201a2b' : ( $is_add_to_cart ? '#3f04fe' : ( $is_separate_icon ? '#ffffff' : '#EF991F' ) ) );
$hotspot_info['stickerBtnTextColor'] = $hotspot_data['hotspot-sticker-btn-text-color'] ?? ( ( $is_add_to_cart || $is_social_share ) ? '#ffffff' : '#000000' );
$hotspot_info['stickerBtnIconColor'] = $hotspot_data['hotspot-sticker-btn-icon-color'] ?? '#000000';
$hotspot_info['stickerBtnUrl'] = $hotspot_data['hotspot-sticker-btn-url'] ?? '';
$hotspot_info['stickerBtnNewTab'] = $hotspot_data['hotspot-sticker-btn-new-tab'] ?? 'off';
$hotspot_info['stickerMainBg'] = $hotspot_data['hotspot-sticker-main-bg'] ?? ( $hotspot_data['hotspot-sticker-card-bg'] ?? 'on' );
$hotspot_info['stickerCardBg'] = $hotspot_info['stickerMainBg'];
$hotspot_info['stickerBtnBg'] = $hotspot_data['hotspot-sticker-btn-bg'] ?? 'on';
$hotspot_info['stickerBtnWidth'] = isset( $hotspot_data['hotspot-sticker-btn-width'] ) && $hotspot_data['hotspot-sticker-btn-width'] !== '' ? $hotspot_data['hotspot-sticker-btn-width'] : ( $is_social_share ? 222 : ( $is_add_to_cart ? 163 : ( $is_separate_icon ? 356 : '' ) ) );
$hotspot_info['stickerBtnHeight'] = isset( $hotspot_data['hotspot-sticker-btn-height'] ) && $hotspot_data['hotspot-sticker-btn-height'] !== '' ? $hotspot_data['hotspot-sticker-btn-height'] : ( ( $is_social_share || $is_add_to_cart || $is_separate_icon ) ? 60 : '' );
$hotspot_info['stickerBtnRadius'] = isset( $hotspot_data['hotspot-sticker-btn-radius'] ) && $hotspot_data['hotspot-sticker-btn-radius'] !== '' ? (float) $hotspot_data['hotspot-sticker-btn-radius'] : ( $is_separate_icon ? 30 : 10 );
$hotspot_info['stickerBtnBorder'] = isset( $hotspot_data['hotspot-sticker-btn-border'] ) && $hotspot_data['hotspot-sticker-btn-border'] !== '' ? (float) $hotspot_data['hotspot-sticker-btn-border'] : ( $is_social_share ? 1 : 0 );
$hotspot_info['stickerBtnBorderColor'] = $hotspot_data['hotspot-sticker-btn-border-color'] ?? ( $is_social_share ? '#3a3051' : ( ( $is_add_to_cart || $is_separate_icon ) ? '#ffffff' : '#EF991F' ) );
$hotspot_info['stickerBtnTextSize'] = isset( $hotspot_data['hotspot-sticker-btn-text-size'] ) && $hotspot_data['hotspot-sticker-btn-text-size'] !== '' ? (float) $hotspot_data['hotspot-sticker-btn-text-size'] : 18;
$hotspot_info['stickerBtnTextWeight'] = $hotspot_data['hotspot-sticker-btn-text-weight'] ?? ( ( $is_social_share || $is_add_to_cart || $is_separate_icon ) ? '600' : '700' );
$hotspot_info['stickerBtnIcon'] = ( $is_add_to_cart || $is_social_share ) ? 'none' : ( $hotspot_data['hotspot-sticker-btn-icon'] ?? 'fas fa-tag' );
// Button with separate icon fields
$hotspot_info['stickerIconBoxBgColor'] = $hotspot_data['hotspot-sticker-icon-box-bg-color'] ?? '#ffffff';
$hotspot_info['stickerIconBoxRadius'] = isset( $hotspot_data['hotspot-sticker-icon-box-radius'] ) && $hotspot_data['hotspot-sticker-icon-box-radius'] !== '' ? (float) $hotspot_data['hotspot-sticker-icon-box-radius'] : 30;
$hotspot_info['stickerIconBoxBorder'] = isset( $hotspot_data['hotspot-sticker-icon-box-border'] ) && $hotspot_data['hotspot-sticker-icon-box-border'] !== '' ? (float) $hotspot_data['hotspot-sticker-icon-box-border'] : 0;
$hotspot_info['stickerIconBoxBorderColor'] = $hotspot_data['hotspot-sticker-icon-box-border-color'] ?? '#ffffff';
$hotspot_info['stickerIconBoxSize'] = isset( $hotspot_data['hotspot-sticker-icon-box-size'] ) && $hotspot_data['hotspot-sticker-icon-box-size'] !== '' ? (float) $hotspot_data['hotspot-sticker-icon-box-size'] : 60;
// Social share sticker fields
$hotspot_info['stickerSocialColor'] = $hotspot_data['hotspot-sticker-social-color'] ?? '#ffffff';
$hotspot_info['stickerSocialSize'] = isset( $hotspot_data['hotspot-sticker-social-size'] ) && $hotspot_data['hotspot-sticker-social-size'] !== '' ? (float) $hotspot_data['hotspot-sticker-social-size'] : 20;
$hotspot_info['stickerSocialGap'] = isset( $hotspot_data['hotspot-sticker-social-gap'] ) && $hotspot_data['hotspot-sticker-social-gap'] !== '' ? (float) $hotspot_data['hotspot-sticker-social-gap'] : 16;
$hotspot_info['stickerSocialLinks'] = isset( $hotspot_data['hotspot-sticker-social-links'] ) ? ( is_array( $hotspot_data['hotspot-sticker-social-links'] ) ? $hotspot_data['hotspot-sticker-social-links'] : json_decode( (string) $hotspot_data['hotspot-sticker-social-links'], true ) ) : [
[ 'id' => '1', 'icon' => 'fab fa-linkedin-in', 'customSvg' => '', 'url' => 'https://linkedin.com', 'openNewTab' => 'on' ],
[ 'id' => '2', 'icon' => 'fab fa-facebook-f', 'customSvg' => '', 'url' => 'https://facebook.com', 'openNewTab' => 'on' ],
[ 'id' => '3', 'icon' => 'fab fa-instagram', 'customSvg' => '', 'url' => 'https://instagram.com', 'openNewTab' => 'on' ],
[ 'id' => '4', 'icon' => 'fab fa-dribbble', 'customSvg' => '', 'url' => 'https://dribbble.com', 'openNewTab' => 'on' ],
];
$hotspot_info['stickerShowPlaceholderText'] = $hotspot_data['hotspot-sticker-show-placeholder-text'] ?? 'on';
} else {
if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
unset($hotspot_info["cssClass"]);
}
}
if (empty($hotspot_data["hotspot-scene"])) {
unset($hotspot_info['targetPitch']);
unset($hotspot_info['targetYaw']);
}
return $hotspot_info;
}
/**
* Return scene info array for scene list
*
* @param array $panoscenes
* @param array $hotspots
* @param string $device_scene
*
* @return array
* @since 8.0.0
*/
private function get_shortcode_scene_info($panoscenes, $hotspots, $device_scene)
{
$scene_info = array();
if ($panoscenes["scene-type"] == 'cubemap') {
$pano_attachment = array(
$panoscenes["scene-attachment-url-face0"],
$panoscenes["scene-attachment-url-face1"],
$panoscenes["scene-attachment-url-face2"],
$panoscenes["scene-attachment-url-face3"],
$panoscenes["scene-attachment-url-face4"],
$panoscenes["scene-attachment-url-face5"]
);
$scene_info = array("type" => $panoscenes["scene-type"], "cubeMap" => $pano_attachment, "hotSpots" => $hotspots);
} else {
$scene_info = array("type" => $panoscenes["scene-type"], "panorama" => $device_scene, "hotSpots" => $hotspots);
}
return $scene_info;
}
/**
* Return device scene for shortcode
*
* @param string $device_scene
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_device_scene($device_scene)
{
$mobile_media_resize = get_option('mobile_media_resize');
if ($mobile_media_resize == "true" && !empty($device_scene)) {
$attachment_id = attachment_url_to_postid($device_scene);
if ($attachment_id) {
$image_width = 0;
$image_meta = wp_get_attachment_metadata($attachment_id);
if (isset($image_meta['width'])) {
$image_width = (int) $image_meta['width'];
} elseif (function_exists('get_attached_file')) {
// Local file fallback only if attachment metadata is missing (no network request)
$file_path = get_attached_file($attachment_id);
if ($file_path && file_exists($file_path)) {
$image_info = @getimagesize($file_path);
if (isset($image_info[0])) {
$image_width = (int) $image_info[0];
}
}
}
if ($image_width > 4096) {
if (wpvr_isMobileDevice()) {
$mobile_scene = wp_get_attachment_image_src($attachment_id, 'wpvr_mobile');
if (!empty($mobile_scene[3])) {
$device_scene = $mobile_scene[0];
}
} else {
$desktop_scene = wp_get_attachment_image_src($attachment_id, 'full');
if (isset($desktop_scene[0])) {
$device_scene = $desktop_scene[0];
}
}
}
}
}
return $device_scene;
}
/**
* Prepare json response for shortcode
*
* @param string $autorotation
* @param array $pano_response
* @param string $panoid
* @param integer $autorotationinactivedelay
* @param integer $autorotationstopdelay
*
* @return array
* @since 8.0.0
*/
public function prepare_shortcode_response($autorotation, $pano_response, $panoid, $autorotationinactivedelay, $autorotationstopdelay)
{
$pano_id_array = array("panoid" => $panoid);
if (empty($autorotation)) {
unset($pano_response['autoRotate']);
unset($pano_response['autoRotateInactivityDelay']);
unset($pano_response['autoRotateStopDelay']);
}
if (empty($autorotationinactivedelay)) {
unset($pano_response['autoRotateInactivityDelay']);
}
if (empty($autorotationstopdelay)) {
unset($pano_response['autoRotateStopDelay']);
}
$response = array();
$response = array($pano_id_array, $pano_response);
if (!empty($response)) {
$response = json_encode($response);
}
return $response;
}
/**
* Prepare HTML and script contents for scene shortcode
*
* @param mixed $width
* @param mixed $panoid
* @param mixed $hotspoticoncolor
* @param mixed $foreground_color
* @param mixed $hotspotblink
* @param mixed $pulse_color
* @param mixed $radius
* @param mixed $id
* @param mixed $height
* @param mixed $scene_data
* @param mixed $response
* @param mixed $autoload
* @param mixed $default_scene
* @param mixed $postdata
*
* @return string
* @since 8.0.0
*/
public function prepare_scene_shortcode_html_content($width, $panoid, $hotspoticoncolor, $foreground_color, $hotspotblink, $pulse_color, $radius, $id, $height, $scene_data, $response, $autoload, $default_scene, $postdata, $mobile_height, $gyro)
{
$html = '';
$html .= '';
// Render pano wrapper contents //
$html = $this->get_shortcode_pano_wrap_content($width, $radius, $html, $id, $height, $mobile_height);
// Render hotspots contents //
$html = $this->render_shortcode_hotspot_content($html, $id, $scene_data);
// Render custom iframe content //
$html = $this->render_shortcode_custom_iframe_wrapper($html, $id);
$html .= '';
//script started
$html = $this->get_shortcode_script_content($html, $response, $id, $autoload, $default_scene, $postdata);
//script end
return $html;
}
/**
* Return ID and Classes for CSS styling
*
* @param mixed $html
* @param mixed $panoid
* @param mixed $hotspoticoncolor
* @param mixed $foreground_color
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_content_classes($html, $panoid, $hotspoticoncolor, $foreground_color)
{
$html .= '#' . $panoid . ' div.pnlm-hotspot-base.fas,
#' . $panoid . ' div.pnlm-hotspot-base.fab,
#' . $panoid . ' div.pnlm-hotspot-base.fa,
#' . $panoid . ' div.pnlm-hotspot-base.fa-solid,
#' . $panoid . ' div.pnlm-hotspot-base.far {
display: block !important;
background-color: ' . $hotspoticoncolor . ';
color: ' . $foreground_color . ';
border-radius: 100%;
width: 30px;
height: 30px;
animation: icon-pulse' . $panoid . ' 1.5s infinite cubic-bezier(.25, 0, 0, 1);
}';
return $html;
}
/**
* Resturn webkit keyframes CSS styling
*
* @param mixed $html
* @param mixed $panoid
* @param mixed $pulse_color
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_webkit_keyframes($html, $panoid, $pulse_color)
{
$html .= '@-webkit-keyframes icon-pulse' . $panoid . ' {
0% {
box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
}
100% {
box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
}
}
@keyframes icon-pulse' . $panoid . ' {
0% {
box-shadow: 0 0 0 0px rgba(' . $pulse_color[0] . ', 1);
}
100% {
box-shadow: 0 0 0 10px rgba(' . $pulse_color[0] . ', 0);
}
}';
return $html;
}
/**
* Render pano wrapper content depending on Tour Width, Height and radius
*
* @param mixed $width
* @param mixed $radius
* @param mixed $html
* @param mixed $id
* @param mixed $height
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_pano_wrap_content($width, $radius, $html, $id, $height, $mobile_height)
{
if ($width == 'fullwidth') {
if (wpvr_isMobileDevice()) {
if ($radius) {
$html .= '';
} else {
$html .= '
';
}
} else {
if ($radius) {
$html .= '
';
} else {
$html .= '
';
}
}
} elseif ($width == 'embed') {
$html .= '
';
} else {
if (wpvr_isMobileDevice()) {
if ($radius) {
$html .= '
';
} else {
$html .= '
';
}
} else {
if ($radius) {
$html .= '
';
} else {
$html .= '
';
}
}
}
return $html;
}
/**
* Render hotspot contents inside pano wrapper
*
* @param string $html
* @param mixed $id
* @param array $scene_data
*
* @return string
* @since 8.0.0
*/
private function render_shortcode_hotspot_content($html, $id, $scene_data)
{
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
ob_start();
do_action('wpvr_hotspot_tweak_contents', $scene_data);
$hotspot_content = ob_get_clean();
$html .= $hotspot_content;
$html .= '
';
$html .= '
';
$html .= '
';
return $html;
}
/**
* Render custom iframe wrapper inside pano wrapper
*
* @param string $html
* @param mixed $id
*
* @return string
* @since 8.0.0
*/
private function render_shortcode_custom_iframe_wrapper($html, $id)
{
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
$html .= '
';
return $html;
}
/**
* Return scripts contents for shortcode
*
* @param string $html
* @param mixed $response
* @param mixed $id
* @param mixed $autoload
* @param mixed $default_scene
* @param mixed $postdata
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_script_content($html, $response, $id, $autoload, $default_scene, $postdata)
{
$html .= '';
return $html;
}
/**
* Return scripts content for hotspot data on shortcode
*
* @param mixed $html
*
* @return string
* @since 8.0.0
*/
private function get_shortcode_hotspot_script_content($html)
{
$html .= 'if(scenes) {';
$html .= 'var scenedata = scenes.scenes;';
$html .= 'for(var scId in scenedata) {';
$html .= 'if(!scenedata.hasOwnProperty(scId)) continue;';
$html .= 'var scenehotspot = scenedata[scId].hotSpots;';
$html .= 'if(scenehotspot && scenehotspot.length) {';
$html .= 'for(var hIdx = 0; hIdx < scenehotspot.length; hIdx++) {';
$html .= 'if(scenehotspot[hIdx]["clickHandlerArgs"] != "") {';
$html .= 'scenehotspot[hIdx]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
$html .= '}';
$html .= 'if(scenehotspot[hIdx].hotspot_type === "sticker" || scenehotspot[hIdx].type === "sticker" || scenehotspot[hIdx].stickerTemplate) {';
$html .= ' (function(hs) {';
$html .= ' hs["createTooltipFunc"] = function(div) {';
$html .= ' if (typeof window.wpvrRenderStickerHotspot === "function") {';
$html .= ' window.wpvrRenderStickerHotspot(div, hs);';
$html .= ' }';
$html .= ' };';
$html .= ' })(scenehotspot[hIdx]);';
$html .= '}';
if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
} else {
$html .= 'else if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
$html .= ' scenehotspot[hIdx]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
$html .= '}';
}
$html .= '}';
$html .= '}';
$html .= '}';
$html .= '}';
return $html;
}
/**
* Render scripts content for panaromic show on shortcode
*
* @param mixed $html
* @param mixed $id
*
* @return string
* @since 8.0.0
*/
private function render_shortcode_panoshow_script_content($html, $id)
{
$html .= 'panoshow' . $id . '.on("load", function (){
setTimeout(() => {
window.dispatchEvent(new Event("resize"));
}, 200);
if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
jQuery("#controls' . $id . '").css("bottom", "55px");
}
else {
jQuery("#controls' . $id . '").css("bottom", "5px");
}
});';
$html .= 'panoshow' . $id . '.on("render", function (){
window.dispatchEvent(new Event("resize"));
});';
return $html;
}
/**
* Return auto rotation scripts content on shortcode
*
* @param mixed $html
* @param mixed $id
*
* @return string
* @since 8.0.0
*/
private function render_shortcode_autoRotate_content($html, $id)
{
$html .= 'if (scenes.autoRotate) {
var wpvrAutoRotateTimer' . $id . ' = null;
var wpvrAutoRotateStopDelay' . $id . ' = parseInt(scenes.autoRotateStopDelay, 10) || 0;
var wpvrScheduleAutoRotate' . $id . ' = function () {
clearTimeout(wpvrAutoRotateTimer' . $id . ');
if (wpvrAutoRotateStopDelay' . $id . ' > 0) {
wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
panoshow' . $id . '.stopAutoRotate();
}, wpvrAutoRotateStopDelay' . $id . ');
} else {
wpvrAutoRotateTimer' . $id . ' = setTimeout(function () {
panoshow' . $id . '.startAutoRotate(scenes.autoRotate, 0);
}, 3000);
}
};
panoshow' . $id . '.on("load", wpvrScheduleAutoRotate' . $id . ');
panoshow' . $id . '.on("scenechange", wpvrScheduleAutoRotate' . $id . ');
}';
return $html;
}
/**
* Return autoload scripts content on shortcode
*
* @param mixed $html
* @param mixed $id
*
* @return string
* @since 8.0.0
*/
private function render_shortcode_autoload_content($html, $id)
{
$html .= 'jQuery(document).ready(function(){
jQuery("#controls' . $id . '").hide();
jQuery("#zoom-in-out-controls' . $id . '").hide();
jQuery("#adcontrol' . $id . '").hide();
jQuery("#pano' . $id . '").find(".pnlm-panorama-info").hide();
});';
$html .= 'panoshow' . $id . '.on("load", function (){
jQuery("#controls' . $id . '").show();
jQuery("#zoom-in-out-controls' . $id . '").show();
jQuery("#adcontrol' . $id . '").show();
jQuery("#pano' . $id . '").find(".pnlm-panorama-info").show();
});';
return $html;
}
/**
* JQuery scripts for on-click content for elementor tab
*
* @param mixed $html
* @param mixed $id
* @param mixed $default_scene
*
* @return string
* @since 8.0.0
*/
private function render_elementor_tab_title_click_content($html, $id, $default_scene, $previeword)
{
$html .= 'jQuery(".elementor-tab-title").click(function(){
var element_id;
var pano_id;
var element_id = this.id;
element_id = element_id.split("-");
element_id = element_id[3];
jQuery("#elementor-tab-content-"+element_id).children("div").addClass("awwww");
var pano_id = jQuery(".awwww").attr("id");
jQuery("#elementor-tab-content-"+element_id).children("div").removeClass("awwww");
if (pano_id != undefined) {
pano_id = pano_id.split("o");
pano_id = pano_id[1];
if (pano_id == "' . $id . '") {
jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
jQuery("#pano' . $id . '").children(".pnlm-ui").find(".pnlm-load-button p").text(' . wp_json_encode( (string) $previeword ) . ');
setTimeout(function() {
// panoshow' . $id . '.loadScene("' . $default_scene . '");
window.dispatchEvent(new Event("resize"));
if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
jQuery("#controls' . $id . '").css("bottom", "55px");
}
else {
jQuery("#controls' . $id . '").css("bottom", "5px");
}
}, 200);
}
}
});';
return $html;
}
/**
* JQuery scripts for on-click content for vr tour tab
*
* @param mixed $html
* @param mixed $id
* @param mixed $default_scene
*
* @return string
* @since 8.0.0
*/
private function render_vr_tour_tab_click_content($html, $id, $default_scene)
{
$html .= 'jQuery(".geodir-tab-head dd, #vr-tour-tab").click(function(){
jQuery("#pano' . $id . '").children(".pnlm-render-container").remove();
jQuery("#pano' . $id . '").children(".pnlm-ui").remove();
panoshow' . $id . ' = pannellum.viewer(response[0]["panoid"], scenes);
setTimeout(function() {
panoshow' . $id . '.loadScene("' . $default_scene . '");
window.dispatchEvent(new Event("resize"));
if (jQuery("#pano' . $id . '").children().children(".pnlm-panorama-info:visible").length > 0) {
jQuery("#controls' . $id . '").css("bottom", "55px");
}
else {
jQuery("#controls' . $id . '").css("bottom", "5px");
}
}, 200);
});';
return $html;
}
}