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 +405 -119 9.1.1 → 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 = '';
@@ -1051,10 +1052,18 @@
1051 1052 ob_start();
1052 1053 do_action('wpvr_hotspot_content', $hotspot_data);
1053 1054 $hotspot_content = ob_get_clean();
1054 1055
1055 - if (!$hotspot_content) {
1056 - $hotspot_content = $hotspot_data["hotspot-content"];
1056 + $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1057 +
1058 + if ($is_fluent_form) {
1059 + if (!empty($hotspot_content)) {
1060 + $hotspot_content = preg_replace('/<script\b[^>]*>[\s\S]*?<\/script>/i', '', $hotspot_content);
1061 + }
1062 + } else {
1063 + if (!$hotspot_content) {
1064 + $hotspot_content = $hotspot_data["hotspot-content"] ?? '';
1065 + }
1057 1066 }
1058 1067
1059 1068 $hotspot_url = $this->normalize_hotspot_external_url($hotspot_data["hotspot-url"] ?? '');
1060 1069
@@ -1074,9 +1083,8 @@
1074 1083 $hotspot_data['hotspot-hover'] ?? ''
1075 1084 );
1076 1085
1077 1086
1078 - $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1079 1087 $on_hover_content = $this->sanitize_content_preserve_styles($on_hover_content ?? '', false);
1080 1088 $on_click_content = preg_replace_callback('/<img[^>]*>/', "replace_callback", $hotspot_content ?? '');
1081 1089 $on_click_content = $this->sanitize_content_preserve_styles($on_click_content ?? '', $is_fluent_form);
1082 1090
@@ -1131,41 +1139,134 @@
1131 1139 }
1132 1140 }
1133 1141 $hotspot_info['URL'] = ($hotspot_data['hotspot-type'] === 'fluent_form' || $hotspot_data['hotspot-type'] === 'wc_product') ? '' : $hotspot_info['URL'];
1134 1142
1135 - if ($hotspot_data["hotspot-customclass"] == 'none' || $hotspot_data["hotspot-customclass"] == '') {
1136 - 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 + }
1137 1223 }
1138 1224 array_push($hotspots, $hotspot_info);
1139 1225 }
1140 1226
1141 - $device_scene = $panoscenes['scene-attachment-url'];
1142 - $mobile_media_resize = get_option('mobile_media_resize');
1143 - $file_accessible = ini_get('allow_url_fopen');
1144 - if ($mobile_media_resize == "true" && $device_scene ) {
1145 - if ($file_accessible == "1") {
1146 - $image_info = getimagesize($device_scene);
1147 - if ( isset($image_info[0]) && $image_info[0] > 4096) {
1148 - $src_to_id_for_mobile = '';
1149 - $src_to_id_for_desktop = '';
1150 - if (wpvr_isMobileDevice()) {
1151 - $src_to_id_for_mobile = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1152 - if ($src_to_id_for_mobile) {
1153 - $mobile_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'wpvr_mobile');
1154 - if ($mobile_scene[3]) {
1155 - $device_scene = $mobile_scene[0];
1156 - }
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];
1157 1249 }
1158 - } else {
1159 - $src_to_id_for_desktop = attachment_url_to_postid($panoscenes['scene-attachment-url']);
1160 - if ($src_to_id_for_desktop) {
1161 - $desktop_scene = wp_get_attachment_image_src($src_to_id_for_mobile, 'full');
1162 - if (isset($desktop_scene[0])) {
1163 - $device_scene = $desktop_scene[0];
1164 - }
1165 - }
1166 1250 }
1167 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 + }
1168 1269 }
1169 1270 }
1170 1271
1171 1272 $scene_info = array();
@@ -1182,8 +1283,13 @@
1182 1283
1183 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);
1184 1285 } else {
1185 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 + }
1186 1292 }
1187 1293
1188 1294
1189 1295 if (isset($panoscenes["ptyscene"])) {
@@ -1319,8 +1425,11 @@
1319 1425 if ( empty( $panoscenes['hotspot-list'] ) || ! is_array( $panoscenes['hotspot-list'] ) ) {
1320 1426 continue;
1321 1427 }
1322 1428 foreach($panoscenes['hotspot-list'] as $hotspot){
1429 + if ( ( $hotspot['hotspot-type'] ?? '' ) === 'sticker' ) {
1430 + continue;
1431 + }
1323 1432 if (isset($hotspot['hotspot-customclass-color-icon-value']) && !empty($hotspot['hotspot-customclass-color-icon-value'])) {
1324 1433 $hotspoticoncolor = $hotspot['hotspot-customclass-color-icon-value'];
1325 1434 } else {
1326 1435 $hotspoticoncolor = "#00b4ff";
@@ -1515,16 +1624,24 @@
1515 1624 $animation_css = apply_filters('wpvr_tour_scene_animation',$animation_type,$animationDuration,$animationDelay,$postdata,$id);
1516 1625 $html .= $animation_css;
1517 1626 }
1518 1627
1628 + $container_width = $width;
1629 + $container_height = $height;
1630 + $container_mobile_height = $mobile_height;
1631 +
1519 1632 if ($width == 'fullwidth') {
1520 - $width = "100%";
1633 + $container_width = "100%";
1634 + } elseif ($width == 'embed') {
1635 + $container_width = "100%";
1636 + $container_height = "100%";
1637 + $container_mobile_height = "100%";
1521 1638 }
1522 1639
1523 1640 if (wpvr_isMobileDevice()) {
1524 - $html .= '<div id="' . $master_container_id . '" class="wpvr-master-container wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $width . '; width: 100%; height: ' . $mobile_height . '; border-radius:' . $radius . '; direction:ltr; ">';
1641 + $html .= '<div id="' . $master_container_id . '" class="wpvr-master-container wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $container_width . '; width: 100%; height: ' . $container_mobile_height . '; border-radius:' . $radius . '; direction:ltr; ">';
1525 1642 } else {
1526 - $html .= '<div id="' . $master_container_id . '" class="wpvr-master-container wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $width . '; width: 100%; height: ' . $height . '; border-radius:' . $radius . '; direction:ltr; ">';
1643 + $html .= '<div id="' . $master_container_id . '" class="wpvr-master-container wpvr-cardboard '.$enable_cardboard.'" style="max-width:' . $container_width . '; width: 100%; height: ' . $container_height . '; border-radius:' . $radius . '; direction:ltr; ">';
1527 1644 }
1528 1645 $is_pro = apply_filters('is_wpvr_pro_active',false);
1529 1646 $status = get_option('wpvr_edd_license_status');
1530 1647 $is_cardboard = get_option('wpvr_cardboard_disable');
@@ -1569,9 +1686,9 @@
1569 1686 }
1570 1687 } elseif ($width == 'embed') {
1571 1688 $html .= '<div class="cardboard-vrembed vrembed">';
1572 1689 $html .= '<div id="' . $panoid2 . '" class="pano-wrap pano-left pano2' . $id . '" style=" width: 49%!important; text-align:center; direction:ltr;" ><div id="center-pointer2' . $pano_suffix . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1573 - $html .= '<div id="' . $panoid . '" class="pano-wrap pano-right pano' . $id . '" style=" text-align:center; direction:ltr;" >';
1690 + $html .= '<div id="' . $panoid . '" class="pano-wrap pano-right pano' . $id . '" style="width: 100%; height: 100%; text-align:center; direction:ltr;" >';
1574 1691 } else {
1575 1692 if (wpvr_isMobileDevice()) {
1576 1693 $html .= '<div id="' . $panoid2 . '" class="pano-wrap pano-left cardboard-half pano2' . $id . '" style="width: 49%; border-radius:' . $radius . '"><div id="center-pointer2' . $pano_suffix . '" class="vr-pointer-container"><span class="center-pointer"></span></div></div>';
1577 1694 if ($radius) {
@@ -1750,14 +1867,13 @@
1750 1867 //===explainer button end===//
1751 1868
1752 1869 //===Floor map button===//
1753 1870 $status = get_option('wpvr_edd_license_status');
1754 - if ($status !== false && 'valid' == $status && $is_pro){
1755 - if ($floor_plan_enable == "on" && !empty($floor_plan_image)) {
1756 - $html .= '<div class="floor_map_button" id="floor_map_button_' . $pano_suffix . '" style="right:'.$floor_map_right.'">';
1757 - $html .= '<div class="ctrl" id="floor_map_target_' . $pano_suffix . '"><i class="fas fa-map" style="color:#f7fffb;"></i></div>';
1758 - $html .= '</div>';
1759 - }
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>';
1760 1876 }
1761 1877 //===floor map button===//
1762 1878
1763 1879 if ($vrgallery && 'valid' == $status && $is_pro ) {
@@ -1893,45 +2009,88 @@
1893 2009 </div>';
1894 2010 }
1895 2011 }
1896 2012 //===Floor plan section===//
1897 - $floor_map_image = "";
1898 - $floor_map_pointer = array();
1899 - $floor_map_scene_id = '';
1900 - $floor_plan_custom_color = '#cca92c';
1901 - $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';
1902 2019
1903 - if (isset($postdata['floor_plan_attachment_url'])) {
1904 - $floor_map_image = $postdata['floor_plan_attachment_url'];
1905 - $floor_map_pointer = $postdata['floor_plan_pointer_position'];
1906 - $floor_map_scene_id = $postdata['floor_plan_data_list'];
1907 - $floor_plan_custom_color = $postdata['floor_plan_custom_color'];
1908 - }
1909 - $html .= '<div class="wpvr-floor-map" id="wpvr-floor-map' . $pano_suffix . '" style="display: none">';
1910 - $html .= '<span class="close-floor-map-plan"><i class="fa fa-times"></i></span>';
1911 - $html .= '<img loading="lazy" src="'.$floor_map_image.'">';
1912 - foreach($floor_map_pointer as $key=> $pointer_position){
1913 - $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.'">
1914 - <svg class="floor-pointer-circle" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
1915 - <circle cx="12" cy="12" r="11.5" stroke="'.$floor_plan_custom_color.'"/>
1916 - <circle cx="12" cy="12" r="5" fill="'.$foreground_color_pointer.'"/>
1917 - </svg>';
1918 -
1919 - // Only add the floor pointer flash SVG if floor_plan_direction_indicator is "on"
1920 - if ($floor_plan_direction_indicator === "on") {
1921 - $html .= '<svg class="floor-pointer-flash" width="54" height="35" viewBox="0 0 54 35" fill="none" xmlns="http://www.w3.org/2000/svg">
1922 - <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)"/>
1923 - <defs>
1924 - <linearGradient id="paint0_linear_1_10" x1="27" y1="4.59807e-08" x2="26.5" y2="28" gradientUnits="userSpaceOnUse">
1925 - <stop stop-color="' . esc_attr( $floor_plan_custom_color ) . '" stop-opacity="0"/>
1926 - <stop offset="1" stop-color="' . esc_attr( $floor_plan_custom_color ) . '"/>
1927 - </linearGradient>
1928 - </defs>
1929 - </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;
1930 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 + }
1931 2091 $html .= '</div>';
1932 2092 }
1933 - $html .= '</div>';
1934 2093 //===Floor plan section===//
1935 2094
1936 2095 $html .= '<div class="wpvr-hotspot-tweak-contents-wrapper" style="display: none">';
1937 2096 $html .= '<i class="fa fa-times cross" data-id="' . $id . '"></i>';
@@ -2011,9 +2170,10 @@
2011 2170 border: '.$border_width.'px '.$border_style.' '.$border_color.';
2012 2171 border-radius: '.$border_radius.'px;
2013 2172 padding: '.$button_pt.'px '.$button_pr.'px '.$button_pb.'px '.$button_pl.'px;
2014 2173 ';
2015 - $html .= '<div class="wpvr-call-to-action-button position-'.$text_align.'" style="max-width:' . $width.'">
2174 + $cta_width = ( $width === 'fullwidth' || $width === 'embed' ) ? '100%' : $width;
2175 + $html .= '<div class="wpvr-call-to-action-button position-'.$text_align.'" style="max-width:' . $cta_width . '">
2016 2176 <a href="'.$buttonurl.'" style="'.$style.'" target="'.$target.'">'.$buttontext.'</a>
2017 2177 </div>';
2018 2178
2019 2179 }
@@ -2186,8 +2346,40 @@
2186 2346 $html .= '(function ($) {';
2187 2347 $html .= 'jQuery(document).ready(function() {';
2188 2348 $html .= 'var response = ' . $response . ';';
2189 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);';
2190 2382 $html .= 'if(scenes) {';
2191 2383 $html .= 'var scenedata = scenes.scenes;';
2192 2384 $html .= 'for(var scId in scenedata) {';
2193 2385 $html .= 'if(!scenedata.hasOwnProperty(scId)) continue;';
@@ -2207,12 +2399,22 @@
2207 2399 $html .='}';
2208 2400 }
2209 2401 $html .= '}';
2210 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 +
2211 2413 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2212 2414 } else {
2213 - $html .= 'if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2214 - $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); } };';
2215 2417 $html .= '}';
2216 2418 }
2217 2419
2218 2420 $html .= '}';
@@ -2262,8 +2464,9 @@
2262 2464 $response2[1]->autoRotate = false;
2263 2465 $response = json_encode($response2);
2264 2466 $html .= 'var response_duplicate = ' . $response . ';';
2265 2467 $html .= 'var scenes_duplicate = response_duplicate[1];';
2468 + $html .= 'wpvrResolveDevicePanorama(scenes_duplicate);';
2266 2469
2267 2470 $html .= 'if(scenes_duplicate) {';
2268 2471 $html .= 'var scenedata = scenes_duplicate.scenes;';
2269 2472 $html .= 'for(var scId in scenedata) {';
@@ -2273,12 +2476,22 @@
2273 2476 $html .= 'for(var hIdx = 0; hIdx < scenehotspot.length; hIdx++) {';
2274 2477 $html .= 'if(scenehotspot[hIdx]["clickHandlerArgs"] != "") {';
2275 2478 $html .= 'scenehotspot[hIdx]["clickHandlerFunc"] = function(div, args) { if (typeof window.wpvrhotspot === "function") { window.wpvrhotspot(div, args); } };';
2276 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 +
2277 2490 if (wpvr_isMobileDevice() && get_option('dis_on_hover') == "true") {
2278 2491 } else {
2279 - $html .= 'if(scenehotspot[hIdx]["createTooltipArgs"] != "") {';
2280 - $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); } };';
2281 2494 $html .= '}';
2282 2495 }
2283 2496 $html .= '}';
2284 2497 $html .= '}';
@@ -2839,8 +3052,13 @@
2839 3052 if (!hotspot) {
2840 3053 return;
2841 3054 }
2842 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 +
2843 3061 var hotspotLink = hotspot.closest("a[href]");
2844 3062 if (!hotspotLink) {
2845 3063 hotspotLink = hotspot.querySelector("a[href]");
2846 3064 }
@@ -2867,9 +3085,9 @@
2867 3085 $scene_key = $panoscenes['scene-id'];
2868 3086 $gallery_scene_ids[] = (string) $scene_key;
2869 3087 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $pano_suffix;
2870 3088 $html .= 'jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
2871 - panoshow' . $pano_suffix . '.loadScene("' . $scene_key . '");
3089 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $scene_key ) . ');
2872 3090 });';
2873 3091 }
2874 3092 }
2875 3093
@@ -3094,9 +3312,9 @@
3094 3312 $html .= '})();';
3095 3313 }
3096 3314 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
3097 3315 $html .= 'document.getElementById("backToHome' . $pano_suffix . '").addEventListener("click", function(e) {';
3098 - $html .= 'panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");';
3316 + $html .= 'panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');';
3099 3317 $html .= '});';
3100 3318 }
3101 3319 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
3102 3320 $html .= '
@@ -3205,11 +3423,15 @@
3205 3423 }
3206 3424
3207 3425 $html .= '
3208 3426 jQuery(document).on("click","#' . $panoid . '",function(event) {
3427 + var isCross = event.target.closest(".cross");
3209 3428 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3210 - var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3429 + var isForm = event.target.closest(".wpvr-hotspot-tweak-contents-wrapper");
3211 3430 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3431 + if(isCross != null){
3432 + return;
3433 + }
3212 3434 if(isForm != null){
3213 3435 jQuery(this).addClass("show-modal");
3214 3436 }else if(isActiveModal == null){
3215 3437 if(isHotspot == null){
@@ -3215,9 +3437,9 @@
3215 3437 if(isHotspot == null){
3216 3438 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3217 3439 jQuery(".custom-ifram-wrapper").hide();
3218 3440 jQuery(this).removeClass("show-modal");
3219 - jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3441 + jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide();
3220 3442 }
3221 3443 }
3222 3444 });';
3223 3445
@@ -3477,9 +3699,9 @@
3477 3699 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $pano_suffix . ';
3478 3700 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3479 3701 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3480 3702 }));
3481 - jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3703 + jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text(' . wp_json_encode( (string) $previeword ) . ')
3482 3704 setTimeout(function() {
3483 3705 // panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3484 3706 window.dispatchEvent(new Event("resize"));
3485 3707 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
@@ -3500,9 +3722,9 @@
3500 3722 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3501 3723 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3502 3724 }));
3503 3725 setTimeout(function() {
3504 - panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3726 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');
3505 3727 window.dispatchEvent(new Event("resize"));
3506 3728 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3507 3729 jQuery("#controls' . $pano_suffix . '").css("bottom", "55px");
3508 3730 }
@@ -3512,9 +3734,9 @@
3512 3734 }, 200);
3513 3735 });';
3514 3736 if (isset($previeword) && $previeword != '') {
3515 3737 $html .= '
3516 - jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3738 + jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text(' . wp_json_encode( (string) $previeword ) . ')
3517 3739 ';
3518 3740 }
3519 3741 if ($default_global_zoom != '' || $max_global_zoom != '' || $min_global_zoom != '') {
3520 3742 $html .= 'jQuery(".globalzoom").val("on").change();';
@@ -3558,12 +3780,16 @@
3558 3780 private function sanitize_content_preserve_styles($content, $allow_forms = false) {
3559 3781 // Decode HTML entities first (in case content was encoded in database)
3560 3782 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3561 3783
3562 - // Escape <script> blocks to display as text instead of removing them
3563 - $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3564 - return esc_html($matches[0]); // Convert to plain text
3565 - }, $content);
3784 + // Escape or strip <script> blocks
3785 + if ($allow_forms) {
3786 + $content = preg_replace('/<script\b[^>]*>[\s\S]*?<\/script>/i', '', $content);
3787 + } else {
3788 + $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3789 + return esc_html($matches[0]); // Convert to plain text
3790 + }, $content);
3791 + }
3566 3792
3567 3793 // Strip dangerous URL-based attributes
3568 3794 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3569 3795
@@ -3606,10 +3832,16 @@
3606 3832 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3607 3833 return '<style>' . esc_html($css) . '</style>';
3608 3834 }, $content);
3609 3835
3610 - // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3836 + // Allow iframes and styles from safe sources only
3611 3837 $allowed_tags = wp_kses_allowed_html('post');
3838 + $allowed_tags['style'] = [
3839 + 'type' => true,
3840 + 'id' => true,
3841 + 'class' => true,
3842 + 'media' => true,
3843 + ];
3612 3844 $allowed_tags['iframe'] = [
3613 3845 'src' => true,
3614 3846 'width' => true,
3615 3847 'height' => true,
@@ -3639,37 +3871,47 @@
3639 3871 ];
3640 3872
3641 3873 if ($allow_forms) {
3642 3874 $form_attributes = [
3643 - 'id' => true,
3644 - 'class' => true,
3645 - 'style' => true,
3646 - 'name' => true,
3647 - 'value' => true,
3648 - 'type' => true,
3649 - 'placeholder' => true,
3650 - 'action' => true,
3651 - 'method' => true,
3652 - 'target' => true,
3653 - 'enctype' => true,
3654 - 'disabled' => true,
3655 - 'readonly' => true,
3656 - 'required' => true,
3657 - 'checked' => true,
3658 - 'selected' => true,
3659 - 'multiple' => true,
3660 - 'size' => true,
3661 - 'rows' => true,
3662 - 'cols' => true,
3663 - 'maxlength' => true,
3664 - 'minlength' => true,
3665 - 'min' => true,
3666 - 'max' => true,
3667 - 'step' => true,
3668 - 'pattern' => true,
3669 - 'autocomplete'=> true,
3670 - 'autofocus' => true,
3671 - 'for' => true,
3875 + 'id' => true,
3876 + 'class' => true,
3877 + 'style' => true,
3878 + 'name' => true,
3879 + 'value' => true,
3880 + 'type' => true,
3881 + 'placeholder' => true,
3882 + 'action' => true,
3883 + 'method' => true,
3884 + 'target' => true,
3885 + 'enctype' => true,
3886 + 'disabled' => true,
3887 + 'readonly' => true,
3888 + 'required' => true,
3889 + 'checked' => true,
3890 + 'selected' => true,
3891 + 'multiple' => true,
3892 + 'size' => true,
3893 + 'rows' => true,
3894 + 'cols' => true,
3895 + 'maxlength' => true,
3896 + 'minlength' => true,
3897 + 'min' => true,
3898 + 'max' => true,
3899 + 'step' => true,
3900 + 'pattern' => true,
3901 + 'autocomplete' => true,
3902 + 'autofocus' => true,
3903 + 'for' => true,
3904 + 'data-*' => true,
3905 + 'data-form_id' => true,
3906 + 'data-form_instance' => true,
3907 + 'data-name' => true,
3908 + 'data-type' => true,
3909 + 'aria-invalid' => true,
3910 + 'aria-required' => true,
3911 + 'aria-label' => true,
3912 + 'aria-describedby' => true,
3913 + 'aria-labelledby' => true,
3672 3914 ];
3673 3915 $allowed_tags['form'] = $form_attributes;
3674 3916 $allowed_tags['input'] = $form_attributes;
3675 3917 $allowed_tags['button'] = $form_attributes;
@@ -3679,8 +3921,18 @@
3679 3921 $allowed_tags['optgroup'] = $form_attributes;
3680 3922 $allowed_tags['label'] = $form_attributes;
3681 3923 $allowed_tags['fieldset'] = $form_attributes;
3682 3924 $allowed_tags['legend'] = $form_attributes;
3925 + if (!isset($allowed_tags['div'])) {
3926 + $allowed_tags['div'] = [];
3927 + }
3928 + $allowed_tags['div']['data-*'] = true;
3929 + $allowed_tags['div']['data-form_id'] = true;
3930 + $allowed_tags['div']['data-form_instance'] = true;
3931 + if (!isset($allowed_tags['span'])) {
3932 + $allowed_tags['span'] = [];
3933 + }
3934 + $allowed_tags['span']['data-*'] = true;
3683 3935 }
3684 3936
3685 3937 // Apply wp_kses() to keep only allowed tags/attributes
3686 3938 $content = wp_kses($content, $allowed_tags);
@@ -3714,7 +3966,41 @@
3714 3966 return 'https://' . $url;
3715 3967 }
3716 3968
3717 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;
3718 4004 }
3719 4005
3720 4006 }