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 | src/Api/Transformers/TourTransformer.php +37 -6 9.1.19.1.3 View file →
@@ -53,8 +53,9 @@
53 53 'previewImage' => $raw['preview'] ?? '',
54 54 'sceneFadeDuration' => isset( $raw['scenefadeduration'] ) ? (int) $raw['scenefadeduration'] : 0,
55 55 'showSceneInfo' => ( $raw['scene-info-enabled'] ?? 'on' ) !== 'off',
56 56 'autoRotate' => $auto_rotate,
57 + 'socialShare' => ( $raw['wpvr_social_share'] ?? 'off' ) === 'on',
57 58 ],
58 59 'floorPlan' => $this->floor_plan_to_api( $raw ),
59 60 'backgroundTour' => [
60 61 'enabled' => ( $raw['bg_tour_enabler'] ?? 'off' ) === 'on',
@@ -172,8 +173,9 @@
172 173 $default_scene_id,
173 174 ( $settings['showSceneInfo'] ?? true ) !== false
174 175 ),
175 176 ],
177 + 'wpvr_social_share' => ! empty( $settings['socialShare'] ) ? 'on' : 'off',
176 178 ];
177 179
178 180 if ( $tour_type === 'video' && ! empty( $video_data['url'] ) ) {
179 181 $raw['vidid'] = 'vid' . ( $data['tourId'] ?? $data['id'] ?? wp_rand( 1000, 99999 ) );
@@ -568,8 +570,17 @@
568 570 : null;
569 571 $scene_yaw = isset( $hotspot['hotspot-scene-yaw'] ) && $hotspot['hotspot-scene-yaw'] !== ''
570 572 ? (float) $hotspot['hotspot-scene-yaw']
571 573 : null;
574 + $product_id = isset( $hotspot['hotspot-product-id'] ) ? (string) $hotspot['hotspot-product-id'] : '';
575 + $product_name = '';
576 + if ( ! empty( $product_id ) && function_exists( 'wc_get_product' ) ) {
577 + $product_obj = wc_get_product( $product_id );
578 + if ( is_object( $product_obj ) ) {
579 + $product_name = $product_obj->get_formatted_name();
580 + }
581 + }
582 +
572 583 $hotspots[] = [
573 584 'id' => $hotspot['hotspot-id'] ?? wp_generate_uuid4(),
574 585 'type' => $hotspot['hotspot-type'] ?? 'info',
575 586 'pitch' => isset( $hotspot['hotspot-pitch'] ) ? (float) $hotspot['hotspot-pitch'] : 0,
@@ -580,8 +591,11 @@
580 591 'urlOpen' => $hotspot['hotspot-url-open'] ?? 'off',
581 592 'hover' => $hotspot['hotspot-hover'] ?? '',
582 593 'targetSceneId' => $hotspot['hotspot-scene'] ?? '',
583 594 'customClass' => $hotspot['hotspot-customclass'] ?? '',
595 + 'fluentFormId' => isset( $hotspot['fluent-form-id'] ) ? (string) $hotspot['fluent-form-id'] : '',
596 + 'productId' => $product_id,
597 + 'productName' => $product_name,
584 598 // Pro styling fields
585 599 'iconClass' => ( ( $hotspot['hotspot-customclass-pro'] ?? '' ) === 'none' || ( $hotspot['hotspot-customclass-pro'] ?? '' ) === '' ) ? '' : $hotspot['hotspot-customclass-pro'],
586 600 'iconBgColor' => $hotspot['hotspot-customclass-color-icon-value'] ?? '#00b4ff',
587 601 'iconColor' => $hotspot['hotspot-custom-icon-color-value'] ?? '#ffffff',
@@ -607,11 +621,17 @@
607 621 $is_fluent_form = $hotspot_type === 'fluent_form';
608 622 $raw_content = (string) ( $hotspot['content'] ?? '' );
609 623 $raw_hover = (string) ( $hotspot['hover'] ?? '' );
610 624
611 - $content = function_exists( 'sanitize_content_preserve_styles' )
612 - ? sanitize_content_preserve_styles( $raw_content, $is_fluent_form )
613 - : wp_kses_post( $raw_content );
625 + // For fluent_form hotspots, content is dynamically rendered server-side from fluent-form-id.
626 + // User-supplied content is never used and must not be saved, completely eliminating stored XSS.
627 + if ( $is_fluent_form ) {
628 + $content = '';
629 + } else {
630 + $content = function_exists( 'sanitize_content_preserve_styles' )
631 + ? sanitize_content_preserve_styles( $raw_content, false )
632 + : wp_kses_post( $raw_content );
633 + }
614 634 $hover = function_exists( 'sanitize_content_preserve_styles' )
615 635 ? sanitize_content_preserve_styles( $raw_hover, false )
616 636 : wp_kses_post( $raw_hover );
617 637
@@ -629,8 +649,20 @@
629 649 'hotspot-customclass' => sanitize_text_field( $hotspot['customClass'] ?? '' ),
630 650 'hotspot-scene-list' => 'none',
631 651 ];
632 652
653 + if ( isset( $hotspot['fluentFormId'] ) ) {
654 + $hs['fluent-form-id'] = (string) absint( $hotspot['fluentFormId'] );
655 + } elseif ( isset( $hotspot['fluent-form-id'] ) ) {
656 + $hs['fluent-form-id'] = (string) absint( $hotspot['fluent-form-id'] );
657 + }
658 +
659 + if ( isset( $hotspot['productId'] ) ) {
660 + $hs['hotspot-product-id'] = sanitize_text_field( $hotspot['productId'] );
661 + } elseif ( isset( $hotspot['hotspot-product-id'] ) ) {
662 + $hs['hotspot-product-id'] = sanitize_text_field( $hotspot['hotspot-product-id'] );
663 + }
664 +
633 665 if ( $this->is_pro ) {
634 666 $hs = array_merge( $hs, [
635 667 // Pro styling fields
636 668 'hotspot-customclass-pro' => !empty( $hotspot['iconClass'] ) ? $hotspot['iconClass'] : 'none',
@@ -641,11 +673,10 @@
641 673 'hotspot-border' => $hotspot['border'] ?? 'off',
642 674 'hotspot-border-width' => $hotspot['borderWidth'] ?? '1',
643 675 'hotspot-border-style' => $hotspot['borderStyle'] ?? 'none',
644 676 'hotspot-border-color' => $hotspot['borderColor'] ?? '#00b4ff',
645 - // Pro navigation entry point fields
646 - 'hotspot-scene-pitch' => $hotspot['scenePitch'] !== null ? (string) $hotspot['scenePitch'] : '',
647 - 'hotspot-scene-yaw' => $hotspot['sceneYaw'] !== null ? (string) $hotspot['sceneYaw'] : '',
677 + 'hotspot-scene-pitch' => ( isset( $hotspot['scenePitch'] ) && $hotspot['scenePitch'] !== null ) ? (string) $hotspot['scenePitch'] : '',
678 + 'hotspot-scene-yaw' => ( isset( $hotspot['sceneYaw'] ) && $hotspot['sceneYaw'] !== null ) ? (string) $hotspot['sceneYaw'] : '',
648 679 'hotspot-scene-entry-point-mode' => in_array( $hotspot['sceneEntryPointMode'] ?? '', [ 'inherit', 'custom' ], true )
649 680 ? $hotspot['sceneEntryPointMode']
650 681 : 'inherit',
651 682 ] );