PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 9.1.3
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v9.1.3
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 8.5.38 8.5.39 All 222 releases
← All changes | legacy/admin/classes/class-wpvr-scene.php +98 -52 9.1.29.1.3 View file →
@@ -1051,10 +1051,18 @@
1051 1051 ob_start();
1052 1052 do_action('wpvr_hotspot_content', $hotspot_data);
1053 1053 $hotspot_content = ob_get_clean();
1054 1054
1055 - if (!$hotspot_content) {
1056 - $hotspot_content = $hotspot_data["hotspot-content"];
1055 + $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1056 +
1057 + if ($is_fluent_form) {
1058 + if (!empty($hotspot_content)) {
1059 + $hotspot_content = preg_replace('/<script\b[^>]*>[\s\S]*?<\/script>/i', '', $hotspot_content);
1060 + }
1061 + } else {
1062 + if (!$hotspot_content) {
1063 + $hotspot_content = $hotspot_data["hotspot-content"] ?? '';
1064 + }
1057 1065 }
1058 1066
1059 1067 $hotspot_url = $this->normalize_hotspot_external_url($hotspot_data["hotspot-url"] ?? '');
1060 1068
@@ -1074,9 +1082,8 @@
1074 1082 $hotspot_data['hotspot-hover'] ?? ''
1075 1083 );
1076 1084
1077 1085
1078 - $is_fluent_form = isset($hotspot_data["hotspot-type"]) && 'fluent_form' === $hotspot_data["hotspot-type"];
1079 1086 $on_hover_content = $this->sanitize_content_preserve_styles($on_hover_content ?? '', false);
1080 1087 $on_click_content = preg_replace_callback('/<img[^>]*>/', "replace_callback", $hotspot_content ?? '');
1081 1088 $on_click_content = $this->sanitize_content_preserve_styles($on_click_content ?? '', $is_fluent_form);
1082 1089
@@ -1515,20 +1522,24 @@
1515 1522 $animation_css = apply_filters('wpvr_tour_scene_animation',$animation_type,$animationDuration,$animationDelay,$postdata,$id);
1516 1523 $html .= $animation_css;
1517 1524 }
1518 1525
1526 + $container_width = $width;
1527 + $container_height = $height;
1528 + $container_mobile_height = $mobile_height;
1529 +
1519 1530 if ($width == 'fullwidth') {
1520 - $width = "100%";
1531 + $container_width = "100%";
1521 1532 } elseif ($width == 'embed') {
1522 - $width = "100%";
1523 - $height = "100%";
1524 - $mobile_height = "100%";
1533 + $container_width = "100%";
1534 + $container_height = "100%";
1535 + $container_mobile_height = "100%";
1525 1536 }
1526 1537
1527 1538 if (wpvr_isMobileDevice()) {
1528 - $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; ">';
1539 + $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; ">';
1529 1540 } else {
1530 - $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; ">';
1541 + $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; ">';
1531 1542 }
1532 1543 $is_pro = apply_filters('is_wpvr_pro_active',false);
1533 1544 $status = get_option('wpvr_edd_license_status');
1534 1545 $is_cardboard = get_option('wpvr_cardboard_disable');
@@ -1573,9 +1584,9 @@
1573 1584 }
1574 1585 } elseif ($width == 'embed') {
1575 1586 $html .= '<div class="cardboard-vrembed vrembed">';
1576 1587 $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>';
1577 - $html .= '<div id="' . $panoid . '" class="pano-wrap pano-right pano' . $id . '" style=" text-align:center; direction:ltr;" >';
1588 + $html .= '<div id="' . $panoid . '" class="pano-wrap pano-right pano' . $id . '" style="width: 100%; height: 100%; text-align:center; direction:ltr;" >';
1578 1589 } else {
1579 1590 if (wpvr_isMobileDevice()) {
1580 1591 $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>';
1581 1592 if ($radius) {
@@ -2015,9 +2026,10 @@
2015 2026 border: '.$border_width.'px '.$border_style.' '.$border_color.';
2016 2027 border-radius: '.$border_radius.'px;
2017 2028 padding: '.$button_pt.'px '.$button_pr.'px '.$button_pb.'px '.$button_pl.'px;
2018 2029 ';
2019 - $html .= '<div class="wpvr-call-to-action-button position-'.$text_align.'" style="max-width:' . $width.'">
2030 + $cta_width = ( $width === 'fullwidth' || $width === 'embed' ) ? '100%' : $width;
2031 + $html .= '<div class="wpvr-call-to-action-button position-'.$text_align.'" style="max-width:' . $cta_width . '">
2020 2032 <a href="'.$buttonurl.'" style="'.$style.'" target="'.$target.'">'.$buttontext.'</a>
2021 2033 </div>';
2022 2034
2023 2035 }
@@ -2871,9 +2883,9 @@
2871 2883 $scene_key = $panoscenes['scene-id'];
2872 2884 $gallery_scene_ids[] = (string) $scene_key;
2873 2885 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $pano_suffix;
2874 2886 $html .= 'jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
2875 - panoshow' . $pano_suffix . '.loadScene("' . $scene_key . '");
2887 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $scene_key ) . ');
2876 2888 });';
2877 2889 }
2878 2890 }
2879 2891
@@ -3098,9 +3110,9 @@
3098 3110 $html .= '})();';
3099 3111 }
3100 3112 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
3101 3113 $html .= 'document.getElementById("backToHome' . $pano_suffix . '").addEventListener("click", function(e) {';
3102 - $html .= 'panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");';
3114 + $html .= 'panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');';
3103 3115 $html .= '});';
3104 3116 }
3105 3117 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
3106 3118 $html .= '
@@ -3209,11 +3221,15 @@
3209 3221 }
3210 3222
3211 3223 $html .= '
3212 3224 jQuery(document).on("click","#' . $panoid . '",function(event) {
3225 + var isCross = event.target.closest(".cross");
3213 3226 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3214 - var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3227 + var isForm = event.target.closest(".wpvr-hotspot-tweak-contents-wrapper");
3215 3228 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3229 + if(isCross != null){
3230 + return;
3231 + }
3216 3232 if(isForm != null){
3217 3233 jQuery(this).addClass("show-modal");
3218 3234 }else if(isActiveModal == null){
3219 3235 if(isHotspot == null){
@@ -3219,9 +3235,9 @@
3219 3235 if(isHotspot == null){
3220 3236 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3221 3237 jQuery(".custom-ifram-wrapper").hide();
3222 3238 jQuery(this).removeClass("show-modal");
3223 - jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3239 + jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide();
3224 3240 }
3225 3241 }
3226 3242 });';
3227 3243
@@ -3481,9 +3497,9 @@
3481 3497 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $pano_suffix . ';
3482 3498 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3483 3499 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3484 3500 }));
3485 - jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3501 + jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text(' . wp_json_encode( (string) $previeword ) . ')
3486 3502 setTimeout(function() {
3487 3503 // panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3488 3504 window.dispatchEvent(new Event("resize"));
3489 3505 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
@@ -3504,9 +3520,9 @@
3504 3520 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3505 3521 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3506 3522 }));
3507 3523 setTimeout(function() {
3508 - panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3524 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');
3509 3525 window.dispatchEvent(new Event("resize"));
3510 3526 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3511 3527 jQuery("#controls' . $pano_suffix . '").css("bottom", "55px");
3512 3528 }
@@ -3516,9 +3532,9 @@
3516 3532 }, 200);
3517 3533 });';
3518 3534 if (isset($previeword) && $previeword != '') {
3519 3535 $html .= '
3520 - jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text("' . $previeword . '")
3536 + jQuery("#' . $panoid . '").children(".pnlm-ui").find(".pnlm-load-button p").text(' . wp_json_encode( (string) $previeword ) . ')
3521 3537 ';
3522 3538 }
3523 3539 if ($default_global_zoom != '' || $max_global_zoom != '' || $min_global_zoom != '') {
3524 3540 $html .= 'jQuery(".globalzoom").val("on").change();';
@@ -3562,12 +3578,16 @@
3562 3578 private function sanitize_content_preserve_styles($content, $allow_forms = false) {
3563 3579 // Decode HTML entities first (in case content was encoded in database)
3564 3580 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3565 3581
3566 - // Escape <script> blocks to display as text instead of removing them
3567 - $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3568 - return esc_html($matches[0]); // Convert to plain text
3569 - }, $content);
3582 + // Escape or strip <script> blocks
3583 + if ($allow_forms) {
3584 + $content = preg_replace('/<script\b[^>]*>[\s\S]*?<\/script>/i', '', $content);
3585 + } else {
3586 + $content = preg_replace_callback('/<script\b[^>]*>(.*?)<\/script>/si', function($matches) {
3587 + return esc_html($matches[0]); // Convert to plain text
3588 + }, $content);
3589 + }
3570 3590
3571 3591 // Strip dangerous URL-based attributes
3572 3592 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3573 3593
@@ -3610,10 +3630,16 @@
3610 3630 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3611 3631 return '<style>' . esc_html($css) . '</style>';
3612 3632 }, $content);
3613 3633
3614 - // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3634 + // Allow iframes and styles from safe sources only
3615 3635 $allowed_tags = wp_kses_allowed_html('post');
3636 + $allowed_tags['style'] = [
3637 + 'type' => true,
3638 + 'id' => true,
3639 + 'class' => true,
3640 + 'media' => true,
3641 + ];
3616 3642 $allowed_tags['iframe'] = [
3617 3643 'src' => true,
3618 3644 'width' => true,
3619 3645 'height' => true,
@@ -3643,37 +3669,47 @@
3643 3669 ];
3644 3670
3645 3671 if ($allow_forms) {
3646 3672 $form_attributes = [
3647 - 'id' => true,
3648 - 'class' => true,
3649 - 'style' => true,
3650 - 'name' => true,
3651 - 'value' => true,
3652 - 'type' => true,
3653 - 'placeholder' => true,
3654 - 'action' => true,
3655 - 'method' => true,
3656 - 'target' => true,
3657 - 'enctype' => true,
3658 - 'disabled' => true,
3659 - 'readonly' => true,
3660 - 'required' => true,
3661 - 'checked' => true,
3662 - 'selected' => true,
3663 - 'multiple' => true,
3664 - 'size' => true,
3665 - 'rows' => true,
3666 - 'cols' => true,
3667 - 'maxlength' => true,
3668 - 'minlength' => true,
3669 - 'min' => true,
3670 - 'max' => true,
3671 - 'step' => true,
3672 - 'pattern' => true,
3673 - 'autocomplete'=> true,
3674 - 'autofocus' => true,
3675 - 'for' => true,
3673 + 'id' => true,
3674 + 'class' => true,
3675 + 'style' => true,
3676 + 'name' => true,
3677 + 'value' => true,
3678 + 'type' => true,
3679 + 'placeholder' => true,
3680 + 'action' => true,
3681 + 'method' => true,
3682 + 'target' => true,
3683 + 'enctype' => true,
3684 + 'disabled' => true,
3685 + 'readonly' => true,
3686 + 'required' => true,
3687 + 'checked' => true,
3688 + 'selected' => true,
3689 + 'multiple' => true,
3690 + 'size' => true,
3691 + 'rows' => true,
3692 + 'cols' => true,
3693 + 'maxlength' => true,
3694 + 'minlength' => true,
3695 + 'min' => true,
3696 + 'max' => true,
3697 + 'step' => true,
3698 + 'pattern' => true,
3699 + 'autocomplete' => true,
3700 + 'autofocus' => true,
3701 + 'for' => true,
3702 + 'data-*' => true,
3703 + 'data-form_id' => true,
3704 + 'data-form_instance' => true,
3705 + 'data-name' => true,
3706 + 'data-type' => true,
3707 + 'aria-invalid' => true,
3708 + 'aria-required' => true,
3709 + 'aria-label' => true,
3710 + 'aria-describedby' => true,
3711 + 'aria-labelledby' => true,
3676 3712 ];
3677 3713 $allowed_tags['form'] = $form_attributes;
3678 3714 $allowed_tags['input'] = $form_attributes;
3679 3715 $allowed_tags['button'] = $form_attributes;
@@ -3683,8 +3719,18 @@
3683 3719 $allowed_tags['optgroup'] = $form_attributes;
3684 3720 $allowed_tags['label'] = $form_attributes;
3685 3721 $allowed_tags['fieldset'] = $form_attributes;
3686 3722 $allowed_tags['legend'] = $form_attributes;
3723 + if (!isset($allowed_tags['div'])) {
3724 + $allowed_tags['div'] = [];
3725 + }
3726 + $allowed_tags['div']['data-*'] = true;
3727 + $allowed_tags['div']['data-form_id'] = true;
3728 + $allowed_tags['div']['data-form_instance'] = true;
3729 + if (!isset($allowed_tags['span'])) {
3730 + $allowed_tags['span'] = [];
3731 + }
3732 + $allowed_tags['span']['data-*'] = true;
3687 3733 }
3688 3734
3689 3735 // Apply wp_kses() to keep only allowed tags/attributes
3690 3736 $content = wp_kses($content, $allowed_tags);