PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 9.2.0
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v9.2.0
9.2.0 9.1.4 9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 All 224 releases
← All changes | legacy/admin/classes/class-wpvr-scene.php +306 -70 9.1.3 → 9.2.0 View file →
@@ -922,9 +922,10 @@
922 922 } else {
923 923 $default_data = array("firstScene" => $default_scene, "sceneFadeDuration" => $scene_fade_duration);
924 924 }
925 925
926 - $scene_data = array();
926 + $scene_data = array();
927 + $mobile_media_resize = get_option('mobile_media_resize');
927 928
928 929 if (!empty($panodata["scene-list"])) {
929 930 foreach ($panodata["scene-list"] as $panoscenes) {
930 931 $scene_ititle = '';
@@ -1138,41 +1139,134 @@
1138 1139 }
1139 1140 }
1140 1141 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1141 1142
1142 - if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1143 - unset($hotspot_info["cssClass"]);
1143 + $is_sticker = ( ( $hotspot_data['hotspot-type'] ?? '' ) === 'sticker' );
1144 + if ( $is_sticker ) {
1145 + $custom_class_pro = ! empty( $hotspot_data['hotspot-customclass'] ) && $hotspot_data['hotspot-customclass'] !== 'none'
1146 + ? ' ' . $hotspot_data['hotspot-customclass']
1147 + : '';
1148 + $hotspot_info['cssClass'] = 'wpvr-hs-custom wpvr-hs-sticker' . $custom_class_pro;
1149 + $hotspot_info['scale'] = true;
1150 + $hotspot_info['stickerTemplate'] = $hotspot_data['hotspot-sticker-template'] ?? 'social_proof';
1151 + $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!';
1152 + $hotspot_info['stickerClientName'] = $hotspot_data['hotspot-sticker-client-name'] ?? 'Elena R.';
1153 + $hotspot_info['stickerClientAvatar'] = $hotspot_data['hotspot-sticker-client-avatar'] ?? '';
1154 + $hotspot_info['stickerRating'] = isset( $hotspot_data['hotspot-sticker-rating'] ) ? (int) $hotspot_data['hotspot-sticker-rating'] : 5;
1155 + $is_separate_icon = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'button_with_separate_icon';
1156 + $is_add_to_cart = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'add_to_cart';
1157 + $is_social_share = ( $hotspot_data['hotspot-sticker-template'] ?? '' ) === 'social_share';
1158 + $hotspot_info['stickerBgColor'] = $hotspot_data['hotspot-sticker-bg-color'] ?? '#201b2c';
1159 + $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 );
1160 + $hotspot_info['stickerBlur'] = isset( $hotspot_data['hotspot-sticker-blur'] ) ? (float) $hotspot_data['hotspot-sticker-blur'] : 12;
1161 + $hotspot_info['stickerBrightness'] = isset( $hotspot_data['hotspot-sticker-brightness'] ) ? (float) $hotspot_data['hotspot-sticker-brightness'] : 100;
1162 + $hotspot_info['stickerTextColor'] = $hotspot_data['hotspot-sticker-text-color'] ?? '#ffffff';
1163 + $hotspot_info['stickerBorderColor'] = $hotspot_data['hotspot-sticker-border-color'] ?? ( ( $is_separate_icon || $is_add_to_cart || $is_social_share ) ? '#40355a' : '#3a3051' );
1164 + $default_radius = $is_separate_icon ? 135 : ( ( $is_add_to_cart || $is_social_share ) ? 15 : 20 );
1165 + $hotspot_info['stickerBorderRadius'] = $hotspot_data['hotspot-sticker-border-radius'] ?? [
1166 + 'topLeft' => $default_radius,
1167 + 'topRight' => $default_radius,
1168 + 'bottomRight' => $default_radius,
1169 + 'bottomLeft' => $default_radius,
1170 + ];
1171 + $hotspot_info['stickerPadding'] = $hotspot_data['hotspot-sticker-padding'] ?? [
1172 + 'top' => 21,
1173 + 'right' => 21,
1174 + 'bottom' => 21,
1175 + 'left' => 21,
1176 + ];
1177 + $hotspot_info['stickerStarColor'] = $hotspot_data['hotspot-sticker-star-color'] ?? '#EF991F';
1178 + // Text before button (for add_to_cart)
1179 + $hotspot_info['stickerPrefixText'] = $hotspot_data['hotspot-sticker-prefix-text'] ?? '$1,090 -';
1180 + $hotspot_info['stickerSubText'] = $hotspot_data['hotspot-sticker-sub-text'] ?? 'Ready to ship';
1181 + // Discount button, add to cart & social share sticker fields
1182 + $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' ) ) );
1183 + $hotspot_info['stickerBtnColor'] = $hotspot_data['hotspot-sticker-btn-color'] ?? ( $is_social_share ? '#201a2b' : ( $is_add_to_cart ? '#3f04fe' : ( $is_separate_icon ? '#ffffff' : '#EF991F' ) ) );
1184 + $hotspot_info['stickerBtnTextColor'] = $hotspot_data['hotspot-sticker-btn-text-color'] ?? ( ( $is_add_to_cart || $is_social_share ) ? '#ffffff' : '#000000' );
1185 + $hotspot_info['stickerBtnIconColor'] = $hotspot_data['hotspot-sticker-btn-icon-color'] ?? '#000000';
1186 + $hotspot_info['stickerBtnUrl'] = $hotspot_data['hotspot-sticker-btn-url'] ?? '';
1187 + $hotspot_info['stickerBtnNewTab'] = $hotspot_data['hotspot-sticker-btn-new-tab'] ?? 'off';
1188 + $hotspot_info['stickerMainBg'] = $hotspot_data['hotspot-sticker-main-bg'] ?? ( $hotspot_data['hotspot-sticker-card-bg'] ?? 'on' );
1189 + $hotspot_info['stickerCardBg'] = $hotspot_info['stickerMainBg'];
1190 + $hotspot_info['stickerBtnBg'] = $hotspot_data['hotspot-sticker-btn-bg'] ?? 'on';
1191 + $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 : '' ) ) );
1192 + $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 : '' );
1193 + $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 );
1194 + $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 );
1195 + $hotspot_info['stickerBtnBorderColor'] = $hotspot_data['hotspot-sticker-btn-border-color'] ?? ( $is_social_share ? '#3a3051' : ( ( $is_add_to_cart || $is_separate_icon ) ? '#ffffff' : '#EF991F' ) );
1196 + $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;
1197 + $hotspot_info['stickerBtnTextWeight'] = $hotspot_data['hotspot-sticker-btn-text-weight'] ?? ( ( $is_social_share || $is_add_to_cart || $is_separate_icon ) ? '600' : '700' );
1198 + $hotspot_info['stickerBtnIcon'] = ( $is_add_to_cart || $is_social_share ) ? 'none' : ( $hotspot_data['hotspot-sticker-btn-icon'] ?? 'fas fa-tag' );
1199 + // Button with separate icon fields
1200 + $hotspot_info['stickerIconBoxBgColor'] = $hotspot_data['hotspot-sticker-icon-box-bg-color'] ?? '#ffffff';
1201 + $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;
1202 + $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;
1203 + $hotspot_info['stickerIconBoxBorderColor'] = $hotspot_data['hotspot-sticker-icon-box-border-color'] ?? '#ffffff';
1204 + $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;
1205 + // Social share sticker fields
1206 + $hotspot_info['stickerSocialColor'] = $hotspot_data['hotspot-sticker-social-color'] ?? '#ffffff';
1207 + $hotspot_info['stickerSocialSize'] = isset( $hotspot_data['hotspot-sticker-social-size'] ) && $hotspot_data['hotspot-sticker-social-size'] !== '' ? (float) $hotspot_data['hotspot-sticker-social-size'] : 20;
1208 + $hotspot_info['stickerSocialGap'] = isset( $hotspot_data['hotspot-sticker-social-gap'] ) && $hotspot_data['hotspot-sticker-social-gap'] !== '' ? (float) $hotspot_data['hotspot-sticker-social-gap'] : 16;
1209 + $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 ) ) : [
1210 + [ 'id' => '1', 'icon' => 'fab fa-linkedin-in', 'customSvg' => '', 'url' => 'https://linkedin.com', 'openNewTab' => 'on' ],
1211 + [ 'id' => '2', 'icon' => 'fab fa-facebook-f', 'customSvg' => '', 'url' => 'https://facebook.com', 'openNewTab' => 'on' ],
1212 + [ 'id' => '3', 'icon' => 'fab fa-instagram', 'customSvg' => '', 'url' => 'https://instagram.com', 'openNewTab' => 'on' ],
1213 + [ 'id' => '4', 'icon' => 'fab fa-dribbble', 'customSvg' => '', 'url' => 'https://dribbble.com', 'openNewTab' => 'on' ],
1214 + ];
1215 + $hotspot_info['stickerShowPlaceholderText'] = $hotspot_data['hotspot-sticker-show-placeholder-text'] ?? 'on';
1216 + } else {
1217 + if ( isset( $hotspot_data['hotspot-scale'] ) && ( $hotspot_data['hotspot-scale'] === 'on' || $hotspot_data['hotspot-scale'] === true ) ) {
1218 + $hotspot_info['scale'] = true;
1219 + }
1220 + if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1221 + unset($hotspot_info["cssClass"]);
1222 + }
1144 1223 }
1145 1224 array_push($hotspots, $hotspot_info);
1146 1225 }
1147 1226
1148 - $device_scene = $panoscenes['scene-attachment-url'];
1149 - $mobile_media_resize = get_option('mobile_media_resize');
1150 - $file_accessible = ini_get('allow_url_fopen');
1151 - if ($mobile_media_resize == "true" && $device_scene ) {
1152 - if ($file_accessible == "1") {
1153 - $image_info = getimagesize($device_scene);
1154 - if ( isset($image_info[0]) && $image_info[0] > 4096) {
1155 - $src_to_id_for_mobile = '';
1156 - $src_to_id_for_desktop = '';
1157 - if (wpvr_isMobileDevice()) {
1158 - $src_to_id_for_mobile = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1159 - if ($src_to_id_for_mobile) {
1160 - $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1161 - if ($mobile_scene[3]) {
1162 - $device_scene = $mobile_scene[0];
1163 - }
1227 + $device_scene = $panoscenes['scene-attachment-url'];
1228 + $mobile_scene_url = '';
1229 + $desktop_scene_url = $device_scene;
1230 +
1231 + if ($mobile_media_resize == "true" && !empty($device_scene)) {
1232 + $attachment_id = !empty($panoscenes['scene-attachment-id'])
1233 + ? (int) $panoscenes['scene-attachment-id']
1234 + : $this->get_attachment_id_by_url($device_scene);
1235 +
1236 + if ($attachment_id) {
1237 + $image_width = 0;
1238 + $image_meta = wp_get_attachment_metadata($attachment_id);
1239 +
1240 + if (isset($image_meta['width'])) {
1241 + $image_width = (int) $image_meta['width'];
1242 + } elseif (function_exists('get_attached_file')) {
1243 + // Local file fallback only if attachment metadata is missing (no network request)
1244 + $file_path = get_attached_file($attachment_id);
1245 + if ($file_path && file_exists($file_path)) {
1246 + $image_info = @getimagesize($file_path);
1247 + if (isset($image_info[0])) {
1248 + $image_width = (int) $image_info[0];
1164 1249 }
1165 - } else {
1166 - $src_to_id_for_desktop = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1167 - if ($src_to_id_for_desktop) {
1168 - $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1169 - if (isset($desktop_scene[0])) {
1170 - $device_scene = $desktop_scene[0];
1171 - }
1172 - }
1173 1250 }
1174 1251 }
1252 +
1253 + if ($image_width > 4096) {
1254 + $mobile_scene = wp_get_attachment_image_src($attachment_id, 'wpvr_mobile');
1255 + if (!empty($mobile_scene[3])) { // is_intermediate verifies resized image exists
1256 + $mobile_scene_url = $mobile_scene[0];
1257 + }
1258 +
1259 + $desktop_scene = wp_get_attachment_image_src($attachment_id, 'full');
1260 + if (isset($desktop_scene[0])) {
1261 + $desktop_scene_url = $desktop_scene[0];
1262 + $device_scene = $desktop_scene[0];
1263 + }
1264 +
1265 + if (wpvr_isMobileDevice() && !empty($mobile_scene_url)) {
1266 + $device_scene = $mobile_scene_url;
1267 + }
1268 + }
1175 1269 }
1176 1270 }
1177 1271
1178 1272 $scene_info = array();
@@ -1189,8 +1283,13 @@
1189 1283
1190 1284 $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);
1191 1285 } else {
1192 1286 $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);
1287 + if (!empty($mobile_scene_url)) {
1288 + $scene_info['mobile_panorama'] = $mobile_scene_url;
1289 + $scene_info['desktop_panorama'] = $desktop_scene_url;
1290 + $scene_info['desktop_width'] = $image_width;
1291 + }
1193 1292 }
1194 1293
1195 1294
1196 1295 if (isset($panoscenes["ptyscene"])) {
@@ -1326,8 +1425,11 @@
1326 1425 if ( empty( $panoscenes['hotspot-list'] ) || ! is_array( $panoscenes['hotspot-list'] ) ) {
1327 1426 continue;
1328 1427 }
1329 1428 foreach($panoscenes['hotspot-list'] as $hotspot){
1429 + if ( ( $hotspot['hotspot-type'] ?? '' ) === 'sticker' ) {
1430 + continue;
1431 + }
1330 1432 if (isset($hotspot['hotspot-customclass-color-icon-value']) && !empty($hotspot['hotspot-customclass-color-icon-value'])) {
1331 1433 $hotspoticoncolor = $hotspot['hotspot-customclass-color-icon-value'];
1332 1434 } else {
1333 1435 $hotspoticoncolor = "#00b4ff";
@@ -1765,14 +1867,13 @@
1765 1867 //===explainer button end===//
1766 1868
1767 1869 //===Floor map button===//
1768 1870 $status = get_option('wpvr_edd_license_status');
1769 - if ($status !== false && 'valid' == $status && $is_pro){
1770 - if ($floor_plan_enable == "on" && !empty($floor_plan_image)) {
1771 - $html .= '<div class="floor_map_button" id="floor_map_button_' . $pano_suffix . '" style="right:'.$floor_map_right.'">';
1772 - $html .= '<div class="ctrl" id="floor_map_target_' . $pano_suffix . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
1773 - $html .= '</div>';
1774 - }
1871 + $has_floor_plan = ( $status !== false && 'valid' == $status && $is_pro && 'on' == $floor_plan_enable && ! empty( $floor_plan_image ) );
1872 + if ( $has_floor_plan ) {
1873 + $html .= '<div class="floor_map_button" id="floor_map_button_' . $pano_suffix . '" style="right:'.$floor_map_right.'">';
1874 + $html .= '<div class="ctrl" id="floor_map_target_' . $pano_suffix . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
1875 + $html .= '</div>';
1775 1876 }
1776 1877 //===floor map button===//
1777 1878
1778 1879 if ($vrgallery && 'valid' == $status && $is_pro ) {
@@ -1908,45 +2009,88 @@
1908 2009 </div>';
1909 2010 }
1910 2011 }
1911 2012 //===Floor plan section===//
1912 - $floor_map_image = "";
1913 - $floor_map_pointer = array();
1914 - $floor_map_scene_id = '';
1915 - $floor_plan_custom_color = '#cca92c';
1916 - $floor_plan_direction_indicator = isset($postdata['floor_plan_direction_indicator']) ? $postdata['floor_plan_direction_indicator'] : 'on';
2013 + if ( $has_floor_plan ) {
2014 + $floor_map_image = $floor_plan_image;
2015 + $floor_map_pointer = isset($postdata['floor_plan_pointer_position']) && is_array($postdata['floor_plan_pointer_position']) ? $postdata['floor_plan_pointer_position'] : array();
2016 + $floor_map_scene_id = isset($postdata['floor_plan_data_list']) && is_array($postdata['floor_plan_data_list']) ? $postdata['floor_plan_data_list'] : array();
2017 + $floor_plan_custom_color = isset($postdata['floor_plan_custom_color']) && ! empty($postdata['floor_plan_custom_color']) ? $postdata['floor_plan_custom_color'] : '#cca92c';
2018 + $floor_plan_direction_indicator = isset($postdata['floor_plan_direction_indicator']) ? $postdata['floor_plan_direction_indicator'] : 'on';
1917 2019
1918 - if (isset($postdata['floor_plan_attachment_url'])) {
1919 - $floor_map_image = $postdata['floor_plan_attachment_url'];
1920 - $floor_map_pointer = $postdata['floor_plan_pointer_position'];
1921 - $floor_map_scene_id = $postdata['floor_plan_data_list'];
1922 - $floor_plan_custom_color = $postdata['floor_plan_custom_color'];
1923 - }
1924 - $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $pano_suffix . '" style="display: none">';
1925 - $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
1926 - $html .= '<img loading="lazy" src="'.$floor_map_image.'">';
1927 - foreach($floor_map_pointer as $key=> $pointer_position){
1928 - $html .= '<div class="floor-plan-pointer ui-draggable ui-draggable-handle" scene_id = "'.$floor_map_scene_id[$key]->value.'" id="'.$pointer_position->id.'" data-top="'.$pointer_position->data_top.'" data-left="'.$pointer_position->data_left.'" style="'.$pointer_position->style.'">
1929 - <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1930 - <circle cx="12" cy="12" r="11.5" stroke="'.$floor_plan_custom_color.'"/>
1931 - <circle cx="12" cy="12" r="5" fill="'.$foreground_color_pointer.'"/>
1932 - </svg>';
1933 -
1934 - // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
1935 - if ($floor_plan_direction_indicator === "on") {
1936 - $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
1937 - <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)"/>
1938 - <defs>
1939 - <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
1940 - <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
1941 - <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
1942 - </linearGradient>
1943 - </defs>
1944 - </svg>';
2020 + $media_alt = '';
2021 + $attachment_id = attachment_url_to_postid( $floor_map_image );
2022 +
2023 + if ( $attachment_id ) {
2024 + $media_alt = sanitize_text_field( get_post_meta( $attachment_id, '_wp_attachment_image_alt', true ) );
2025 + }
2026 +
2027 + if ( ! empty( $media_alt ) ) {
2028 + $floor_map_alt = $media_alt;
2029 + } else {
2030 + $tour_title = sanitize_text_field( get_the_title( $id ) );
2031 +
2032 + $floor_map_alt = ! empty( $tour_title )
2033 + /* translators: %s: tour title */
2034 + ? sprintf( __( '%s - Floor Plan', 'wpvr' ), $tour_title )
2035 + : __( 'Floor Plan', 'wpvr' );
2036 + }
2037 +
2038 + $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $pano_suffix . '" style="display: none">';
2039 + $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
2040 + $html .= '<img loading="lazy" src="' . esc_url( $floor_map_image ) . '" alt="' . esc_attr( $floor_map_alt ) . '">';
2041 + foreach ( $floor_map_pointer as $key => $pointer_position ) {
2042 + $pointer_id = '';
2043 + $data_top = '';
2044 + $data_left = '';
2045 + $style = '';
2046 +
2047 + if ( is_object( $pointer_position ) ) {
2048 + $pointer_id = isset( $pointer_position->id ) ? (string) $pointer_position->id : '';
2049 + $data_top = isset( $pointer_position->data_top ) ? (string) $pointer_position->data_top : '';
2050 + $data_left = isset( $pointer_position->data_left ) ? (string) $pointer_position->data_left : '';
2051 + $style = isset( $pointer_position->style ) ? (string) $pointer_position->style : '';
2052 + } elseif ( is_array( $pointer_position ) ) {
2053 + $pointer_id = isset( $pointer_position['id'] ) ? (string) $pointer_position['id'] : '';
2054 + $data_top = isset( $pointer_position['data_top'] ) ? (string) $pointer_position['data_top'] : '';
2055 + $data_left = isset( $pointer_position['data_left'] ) ? (string) $pointer_position['data_left'] : '';
2056 + $style = isset( $pointer_position['style'] ) ? (string) $pointer_position['style'] : '';
2057 + }
2058 +
2059 + $scene_id_val = '';
2060 + if ( isset( $floor_map_scene_id[ $key ] ) ) {
2061 + $scene_item = $floor_map_scene_id[ $key ];
2062 + if ( is_object( $scene_item ) && isset( $scene_item->value ) ) {
2063 + $scene_id_val = (string) $scene_item->value;
2064 + } elseif ( is_array( $scene_item ) && isset( $scene_item['value'] ) ) {
2065 + $scene_id_val = (string) $scene_item['value'];
2066 + } elseif ( is_scalar( $scene_item ) ) {
2067 + $scene_id_val = (string) $scene_item;
1945 2068 }
2069 + }
2070 +
2071 + $html .= '<div class="floor-plan-pointer ui-draggable ui-draggable-handle" scene_id="' . esc_attr( $scene_id_val ) . '" id="' . esc_attr( $pointer_id ) . '" data-top="' . esc_attr( $data_top ) . '" data-left="' . esc_attr( $data_left ) . '" style="' . esc_attr( $style ) . '">
2072 + <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
2073 + <circle cx="12" cy="12" r="11.5" stroke="' . esc_attr( $floor_plan_custom_color ) . '"/>
2074 + <circle cx="12" cy="12" r="5" fill="' . esc_attr( $foreground_color_pointer ) . '"/>
2075 + </svg>';
2076 +
2077 + // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
2078 + if ( $floor_plan_direction_indicator === 'on' ) {
2079 + $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
2080 + <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)"/>
2081 + <defs>
2082 + <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
2083 + <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
2084 + <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
2085 + </linearGradient>
2086 + </defs>
2087 + </svg>';
2088 + }
2089 + $html .= '</div>';
2090 + }
1946 2091 $html .= '</div>';
1947 2092 }
1948 - $html .= '</div>';
1949 2093 //===Floor plan section===//
1950 2094
1951 2095 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
1952 2096 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
@@ -2202,8 +2346,40 @@
2202 2346 $html .= '(function ($) {';
2203 2347 $html .= 'jQuery(document).ready(function() {';
2204 2348 $html .= 'var response = ' . $response . ';';
2205 2349 $html .= 'var scenes = response[1];';
2350 + $html .= 'function wpvrResolveDevicePanorama(scenesConfig) {';
2351 + $html .= ' if (!scenesConfig || !scenesConfig.scenes) return;';
2352 + $html .= ' var isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) || (navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);';
2353 + $html .= ' var isSmallScreen = (window.innerWidth <= 768);';
2354 + $html .= ' if (typeof window.wpvrMaxTexture === "undefined") {';
2355 + $html .= ' window.wpvrMaxTexture = 16384;';
2356 + $html .= ' try {';
2357 + $html .= ' var testCanvas = document.createElement("canvas");';
2358 + $html .= ' var gl = testCanvas.getContext("webgl") || testCanvas.getContext("experimental-webgl");';
2359 + $html .= ' if (gl) {';
2360 + $html .= ' window.wpvrMaxTexture = gl.getParameter(gl.MAX_TEXTURE_SIZE) || 16384;';
2361 + $html .= ' var ext = gl.getExtension("WEBGL_lose_context");';
2362 + $html .= ' if (ext) { ext.loseContext(); }';
2363 + $html .= ' }';
2364 + $html .= ' } catch (e) {}';
2365 + $html .= ' }';
2366 + $html .= ' var maxTexture = window.wpvrMaxTexture;';
2367 + $html .= ' for (var scId in scenesConfig.scenes) {';
2368 + $html .= ' if (!scenesConfig.scenes.hasOwnProperty(scId)) continue;';
2369 + $html .= ' var sc = scenesConfig.scenes[scId];';
2370 + $html .= ' if (!sc) continue;';
2371 + $html .= ' var exceedsGpu = sc.desktop_width && (sc.desktop_width > maxTexture);';
2372 + $html .= ' if (isMobile || isSmallScreen || exceedsGpu) {';
2373 + $html .= ' if (sc.mobile_panorama) {';
2374 + $html .= ' sc.panorama = sc.mobile_panorama;';
2375 + $html .= ' }';
2376 + $html .= ' } else if (sc.desktop_panorama) {';
2377 + $html .= ' sc.panorama = sc.desktop_panorama;';
2378 + $html .= ' }';
2379 + $html .= ' }';
2380 + $html .= '}';
2381 + $html .= 'wpvrResolveDevicePanorama(scenes);';
2206 2382 $html .= 'if(scenes) {';
2207 2383 $html .= 'var scenedata = scenes.scenes;';
2208 2384 $html .= 'for(var scId in scenedata) {';
2209 2385 $html .= 'if(!scenedata.hasOwnProperty(scId)) continue;';
@@ -2223,12 +2399,22 @@
2223 2399 $html .='}';
2224 2400 }
2225 2401 $html .= '}';
2226 2402
2403 + $html .= 'if(scenehotspot[hIdx].hotspot_type === "sticker" || scenehotspot[hIdx].type === "sticker" || scenehotspot[hIdx].stickerTemplate) {';
2404 + $html .= ' (function(hs) {';
2405 + $html .= ' hs["createTooltipFunc"] = function(div) {';
2406 + $html .= ' if (typeof window.wpvrRenderStickerHotspot === "function") {';
2407 + $html .= ' window.wpvrRenderStickerHotspot(div, hs);';
2408 + $html .= ' }';
2409 + $html .= ' };';
2410 + $html .= ' })(scenehotspot[hIdx]);';
2411 + $html .= '}';
2412 +
2227 2413 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2228 2414 } else {
2229 - $html .= 'if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2230 - $html .= 'scenehotspot[hIdx]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2415 + $html .= 'else if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2416 + $html .= ' scenehotspot[hIdx]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2231 2417 $html .= '}';
2232 2418 }
2233 2419
2234 2420 $html .= '}';
@@ -2278,8 +2464,9 @@
2278 2464 $response2[1]->autoRotate = false;
2279 2465 $response = json_encode($response2);
2280 2466 $html .= 'var response_duplicate = ' . $response . ';';
2281 2467 $html .= 'var scenes_duplicate = response_duplicate[1];';
2468 + $html .= 'wpvrResolveDevicePanorama(scenes_duplicate);';
2282 2469
2283 2470 $html .= 'if(scenes_duplicate) {';
2284 2471 $html .= 'var scenedata = scenes_duplicate.scenes;';
2285 2472 $html .= 'for(var scId in scenedata) {';
@@ -2289,12 +2476,22 @@
2289 2476 $html .= 'for(var hIdx = 0; hIdx < scenehotspot.length; hIdx++) {';
2290 2477 $html .= 'if(scenehotspot[hIdx]["clickHandlerArgs"] != "") {';
2291 2478 $html .= 'scenehotspot[hIdx]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2292 2479 $html .= '}';
2480 + $html .= 'if(scenehotspot[hIdx].hotspot_type === "sticker" || scenehotspot[hIdx].type === "sticker" || scenehotspot[hIdx].stickerTemplate) {';
2481 + $html .= ' (function(hs) {';
2482 + $html .= ' hs["createTooltipFunc"] = function(div) {';
2483 + $html .= ' if (typeof window.wpvrRenderStickerHotspot === "function") {';
2484 + $html .= ' window.wpvrRenderStickerHotspot(div, hs);';
2485 + $html .= ' }';
2486 + $html .= ' };';
2487 + $html .= ' })(scenehotspot[hIdx]);';
2488 + $html .= '}';
2489 +
2293 2490 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2294 2491 } else {
2295 - $html .= 'if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2296 - $html .= 'scenehotspot[hIdx]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2492 + $html .= 'else if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2493 + $html .= ' scenehotspot[hIdx]["createTooltipFunc"] = function(div, args) { if (typeof window.wpvrtooltip === "function") { window.wpvrtooltip(div, args); } };';
2297 2494 $html .= '}';
2298 2495 }
2299 2496 $html .= '}';
2300 2497 $html .= '}';
@@ -2855,8 +3052,13 @@
2855 3052 if (!hotspot) {
2856 3053 return;
2857 3054 }
2858 3055
3056 + // Social share icons navigate independently using their own links and targets.
3057 + if (hotspot.querySelector(".wpvr-sticker-card--social-share")) {
3058 + return;
3059 + }
3060 +
2859 3061 var hotspotLink = hotspot.closest("a[href]");
2860 3062 if (!hotspotLink) {
2861 3063 hotspotLink = hotspot.querySelector("a[href]");
2862 3064 }
@@ -3764,7 +3966,41 @@
3764 3966 return 'https://' . $url;
3765 3967 }
3766 3968
3767 3969 return $url;
3970 +}
3971 +
3972 +/**
3973 + * Get attachment ID from URL with in-memory static cache and WordPress object cache.
3974 + *
3975 + * @param string $url Image URL.
3976 + * @return int Attachment ID or 0.
3977 + */
3978 +private function get_attachment_id_by_url($url)
3979 +{
3980 + static $memory_cache = array();
3981 +
3982 + if (empty($url) || !is_string($url)) {
3983 + return 0;
3984 + }
3985 +
3986 + if (isset($memory_cache[$url])) {
3987 + return $memory_cache[$url];
3988 + }
3989 +
3990 + $cache_key = 'wpvr_att_id_' . md5($url);
3991 + $cached_id = wp_cache_get($cache_key, 'wpvr');
3992 + if (false !== $cached_id) {
3993 + $memory_cache[$url] = (int) $cached_id;
3994 + return (int) $cached_id;
3995 + }
3996 +
3997 + $attachment_id = attachment_url_to_postid($url);
3998 + $attachment_id = $attachment_id ? (int) $attachment_id : 0;
3999 +
4000 + wp_cache_set($cache_key, $attachment_id, 'wpvr', HOUR_IN_SECONDS);
4001 + $memory_cache[$url] = $attachment_id;
4002 +
4003 + return $attachment_id;
3768 4004 }
3769 4005
3770 4006 }