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 +99 -49 9.1.19.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,16 +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%";
1532 + } elseif ($width == 'embed') {
1533 + $container_width = "100%";
1534 + $container_height = "100%";
1535 + $container_mobile_height = "100%";
1521 1536 }
1522 1537
1523 1538 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; ">';
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; ">';
1525 1540 } 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; ">';
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; ">';
1527 1542 }
1528 1543 $is_pro = apply_filters('is_wpvr_pro_active',false);
1529 1544 $status = get_option('wpvr_edd_license_status');
1530 1545 $is_cardboard = get_option('wpvr_cardboard_disable');
@@ -1569,9 +1584,9 @@
1569 1584 }
1570 1585 } elseif ($width == 'embed') {
1571 1586 $html .= '<div class="cardboard-vrembed vrembed">';
1572 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>';
1573 - $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;" >';
1574 1589 } else {
1575 1590 if (wpvr_isMobileDevice()) {
1576 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>';
1577 1592 if ($radius) {
@@ -2011,9 +2026,10 @@
2011 2026 border: '.$border_width.'px '.$border_style.' '.$border_color.';
2012 2027 border-radius: '.$border_radius.'px;
2013 2028 padding: '.$button_pt.'px '.$button_pr.'px '.$button_pb.'px '.$button_pl.'px;
2014 2029 ';
2015 - $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 . '">
2016 2032 <a href="'.$buttonurl.'" style="'.$style.'" target="'.$target.'">'.$buttontext.'</a>
2017 2033 </div>';
2018 2034
2019 2035 }
@@ -2867,9 +2883,9 @@
2867 2883 $scene_key = $panoscenes['scene-id'];
2868 2884 $gallery_scene_ids[] = (string) $scene_key;
2869 2885 $scene_key_gallery = $panoscenes['scene-id'] . '_gallery_' . $pano_suffix;
2870 2886 $html .= 'jQuery(document).on("click","#' . $scene_key_gallery . '",function() {
2871 - panoshow' . $pano_suffix . '.loadScene("' . $scene_key . '");
2887 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $scene_key ) . ');
2872 2888 });';
2873 2889 }
2874 2890 }
2875 2891
@@ -3094,9 +3110,9 @@
3094 3110 $html .= '})();';
3095 3111 }
3096 3112 if ($custom_control['backToHomeSwitch'] == "on" && 'valid' == $status && $is_pro) {
3097 3113 $html .= 'document.getElementById("backToHome' . $pano_suffix . '").addEventListener("click", function(e) {';
3098 - $html .= 'panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");';
3114 + $html .= 'panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');';
3099 3115 $html .= '});';
3100 3116 }
3101 3117 if ($gyro_button_enabled && 'valid' == $status && $is_pro) {
3102 3118 $html .= '
@@ -3205,11 +3221,15 @@
3205 3221 }
3206 3222
3207 3223 $html .= '
3208 3224 jQuery(document).on("click","#' . $panoid . '",function(event) {
3225 + var isCross = event.target.closest(".cross");
3209 3226 var isActiveModal = event.target.closest(".custom-ifram-wrapper");
3210 - var isForm = event.target.closest(".wpvr-hotspot-tweak-contents");
3227 + var isForm = event.target.closest(".wpvr-hotspot-tweak-contents-wrapper");
3211 3228 var isHotspot = event.target.closest(".pnlm-hotspot-base");
3229 + if(isCross != null){
3230 + return;
3231 + }
3212 3232 if(isForm != null){
3213 3233 jQuery(this).addClass("show-modal");
3214 3234 }else if(isActiveModal == null){
3215 3235 if(isHotspot == null){
@@ -3215,9 +3235,9 @@
3215 3235 if(isHotspot == null){
3216 3236 jQuery(".custom-ifram-wrapper .custom-ifram").empty();
3217 3237 jQuery(".custom-ifram-wrapper").hide();
3218 3238 jQuery(this).removeClass("show-modal");
3219 - jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide("show-modal");
3239 + jQuery(".wpvr-hotspot-tweak-contents-wrapper").hide();
3220 3240 }
3221 3241 }
3222 3242 });';
3223 3243
@@ -3477,9 +3497,9 @@
3477 3497 window.wpvrViewers[response[0]["panoid"]] = panoshow' . $pano_suffix . ';
3478 3498 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3479 3499 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3480 3500 }));
3481 - 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 ) . ')
3482 3502 setTimeout(function() {
3483 3503 // panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3484 3504 window.dispatchEvent(new Event("resize"));
3485 3505 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
@@ -3500,9 +3520,9 @@
3500 3520 document.dispatchEvent(new CustomEvent("wpvr:viewer-ready", {
3501 3521 detail: { containerId: response[0]["panoid"], viewer: panoshow' . $pano_suffix . ' }
3502 3522 }));
3503 3523 setTimeout(function() {
3504 - panoshow' . $pano_suffix . '.loadScene("' . $default_scene . '");
3524 + panoshow' . $pano_suffix . '.loadScene(' . wp_json_encode( (string) $default_scene ) . ');
3505 3525 window.dispatchEvent(new Event("resize"));
3506 3526 if (jQuery("#' . $panoid . '").children().children(".pnlm-panorama-info:visible").length > 0) {
3507 3527 jQuery("#controls' . $pano_suffix . '").css("bottom", "55px");
3508 3528 }
@@ -3512,9 +3532,9 @@
3512 3532 }, 200);
3513 3533 });';
3514 3534 if (isset($previeword) && $previeword != '') {
3515 3535 $html .= '
3516 - 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 ) . ')
3517 3537 ';
3518 3538 }
3519 3539 if ($default_global_zoom != '' || $max_global_zoom != '' || $min_global_zoom != '') {
3520 3540 $html .= 'jQuery(".globalzoom").val("on").change();';
@@ -3558,12 +3578,16 @@
3558 3578 private function sanitize_content_preserve_styles($content, $allow_forms = false) {
3559 3579 // Decode HTML entities first (in case content was encoded in database)
3560 3580 $content = html_entity_decode($content, ENT_QUOTES | ENT_HTML5, 'UTF-8');
3561 3581
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);
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 + }
3566 3590
3567 3591 // Strip dangerous URL-based attributes
3568 3592 $content = preg_replace('/(href|action|formaction)\s*=\s*["\']?\s*(javascript|vbscript|data|about):/i', '$1=""', $content);
3569 3593
@@ -3606,10 +3630,16 @@
3606 3630 $css = preg_replace('/-moz-binding\s*:/i', '', $css);
3607 3631 return '<style>' . esc_html($css) . '</style>';
3608 3632 }, $content);
3609 3633
3610 - // Allow iframes from safe sources only (e.g., YouTube, Vimeo)
3634 + // Allow iframes and styles from safe sources only
3611 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 + ];
3612 3642 $allowed_tags['iframe'] = [
3613 3643 'src' => true,
3614 3644 'width' => true,
3615 3645 'height' => true,
@@ -3639,37 +3669,47 @@
3639 3669 ];
3640 3670
3641 3671 if ($allow_forms) {
3642 3672 $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,
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,
3672 3712 ];
3673 3713 $allowed_tags['form'] = $form_attributes;
3674 3714 $allowed_tags['input'] = $form_attributes;
3675 3715 $allowed_tags['button'] = $form_attributes;
@@ -3679,8 +3719,18 @@
3679 3719 $allowed_tags['optgroup'] = $form_attributes;
3680 3720 $allowed_tags['label'] = $form_attributes;
3681 3721 $allowed_tags['fieldset'] = $form_attributes;
3682 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;
3683 3733 }
3684 3734
3685 3735 // Apply wp_kses() to keep only allowed tags/attributes
3686 3736 $content = wp_kses($content, $allowed_tags);