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-ajax.php +88 -24 9.0.39.1.3 View file →
@@ -103,9 +103,9 @@
103 103 }
104 104
105 105 $nonce = isset($_POST['nonce']) ? sanitize_text_field(wp_unslash($_POST['nonce'])) : '';
106 106
107 - if (!wp_verify_nonce($nonce, 'wpvr')) {
107 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
108 108 wp_send_json_error(array('message' => 'Permission denied.'), 403);
109 109 }
110 110
111 111 update_option('high_res_image', 'true');
@@ -464,9 +464,11 @@
464 464 */
465 465 public function wpvr_file_import()
466 466 {
467 467 //===Current user capabilities check===//
468 - if (!current_user_can('edit_posts')) {
468 + $post_type_obj = get_post_type_object( 'wpvr_item' );
469 + $edit_cap = $post_type_obj ? $post_type_obj->cap->edit_posts : 'edit_wpvr_tours';
470 + if ( ! current_user_can( $edit_cap ) || ! current_user_can( 'upload_files' ) ) {
469 471 $response = array(
470 472 'success' => false,
471 473 'data' => 'Permission denied.'
472 474 );
@@ -607,9 +609,9 @@
607 609 update_option('wpvr_webp_conversion', $wpvr_webp_conversion);
608 610 update_option('mobile_media_resize', $mobile_media_resize);
609 611 update_option('high_res_image', $high_res_image);
610 612 update_option('dis_on_hover', $dis_on_hover);
611 - update_option('wpvr_mobile_hotspot_tip', $wpvr_mobile_hotspot_tip ? 'true' : 'false');
613 + update_option('wpvr_mobile_hotspot_tip', 'true' === $wpvr_mobile_hotspot_tip ? 'true' : 'false');
612 614 update_option('wpvr_frontend_notice', $wpvr_frontend_notice);
613 615 update_option('wpvr_frontend_notice_area', $wpvr_frontend_notice_area);
614 616 update_option('wpvr_script_control', $wpvr_script_control);
615 617 update_option('wpvr_script_list', $wpvr_script_list);
@@ -715,9 +717,9 @@
715 717 return;
716 718 }
717 719 $nonce = filter_input(INPUT_POST, 'security', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
718 720 $nonce = !empty( $nonce ) ? $nonce : null;
719 - if ( !wp_verify_nonce( $nonce, 'wpvr' ) ) {
721 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
720 722 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
721 723 return;
722 724 }
723 725
@@ -793,9 +795,9 @@
793 795 return;
794 796 }
795 797
796 798 $nonce = isset($_POST['security']) ? sanitize_text_field(wp_unslash( $_POST['security'] )) : '';
797 - if ( !wp_verify_nonce( $nonce, 'wpvr' ) ) {
799 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
798 800 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
799 801 return;
800 802 }
801 803
@@ -867,9 +869,9 @@
867 869 return;
868 870 }
869 871
870 872 $nonce = isset($_POST['security']) ? sanitize_text_field(wp_unslash( $_POST['security'] )) : '';
871 - if ( !wp_verify_nonce( $nonce, 'wpvr' ) ) {
873 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
872 874 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
873 875 return;
874 876 }
875 877
@@ -947,8 +949,14 @@
947 949 'post_title' => $title,
948 950 'post_status' => 'publish',
949 951 'post_type' => 'wpvr_item',
950 952 'post_author' => get_current_user_id(),
953 + // meta_input is written before wp_insert_post() fires transition_post_status,
954 + // so telemetry listening on that hook sees these flags already set.
955 + 'meta_input' => array(
956 + 'wpvr_created_from_wizard' => true,
957 + 'wpvr_wizard_industry' => $industry,
958 + ),
951 959 );
952 960
953 961 $post_id = wp_insert_post( $post_data );
954 962 if ( is_wp_error( $post_id ) ) {
@@ -965,10 +973,8 @@
965 973 }
966 974 $remote_meta['panodata'] = $panodata;
967 975
968 976 update_post_meta( $post_id, 'panodata', $panodata );
969 - update_post_meta( $post_id, 'wpvr_created_from_wizard', true );
970 - update_post_meta( $post_id, 'wpvr_wizard_industry', $industry );
971 977
972 978 if ( ! empty( $remote_meta ) ) {
973 979 foreach ( $remote_meta as $meta_key => $meta_value ) {
974 980 $sanitized_key = sanitize_key( $meta_key );
@@ -1057,9 +1063,18 @@
1057 1063 }
1058 1064
1059 1065 $attachment_id = attachment_url_to_postid( $source_url );
1060 1066 if ( ! $attachment_id ) {
1061 - $attachment_id = media_sideload_image( $source_url, $post_id, null, 'id' );
1067 + if ( ! current_user_can( 'upload_files' ) ) {
1068 + continue;
1069 + }
1070 +
1071 + $valid_url = wp_http_validate_url( $source_url );
1072 + if ( ! $valid_url ) {
1073 + continue;
1074 + }
1075 +
1076 + $attachment_id = media_sideload_image( $valid_url, $post_id, null, 'id' );
1062 1077 if ( is_wp_error( $attachment_id ) ) {
1063 1078 continue;
1064 1079 }
1065 1080 }
@@ -1114,9 +1129,9 @@
1114 1129 return;
1115 1130 }
1116 1131
1117 1132 $nonce = isset($_POST['security']) ? sanitize_text_field(wp_unslash( $_POST['security'] )) : '';
1118 - if ( !wp_verify_nonce( $nonce, 'wpvr' ) ) {
1133 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
1119 1134 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
1120 1135 return;
1121 1136 }
1122 1137
@@ -1176,15 +1191,17 @@
1176 1191 *
1177 1192 * @since 8.5.48
1178 1193 */
1179 1194 public function wpvr_create_tour_from_wizard() {
1180 - if ( ! current_user_can( 'edit_posts' ) ) {
1195 + $post_type_obj = get_post_type_object( 'wpvr_item' );
1196 + $create_cap = $post_type_obj ? $post_type_obj->cap->edit_posts : 'edit_wpvr_tours';
1197 + if ( ! current_user_can( $create_cap ) ) {
1181 1198 wp_send_json_error( array( 'message' => 'Unauthorized user' ), 403 );
1182 1199 return;
1183 1200 }
1184 1201
1185 1202 $nonce = isset($_POST['security']) ? sanitize_text_field(wp_unslash( $_POST['security'] )) : '';
1186 - if ( !wp_verify_nonce( $nonce, 'wpvr' ) ) {
1203 + if ( ! wp_verify_nonce( $nonce, 'wpvr_setup_wizard' ) && ! wp_verify_nonce( $nonce, 'wpvr' ) ) {
1187 1204 wp_send_json_error( array( 'message' => 'Invalid nonce' ), 400 );
1188 1205 return;
1189 1206 }
1190 1207
@@ -1197,8 +1214,30 @@
1197 1214 wp_send_json_error( array( 'message' => 'Panodata is required' ) );
1198 1215 return;
1199 1216 }
1200 1217
1218 + if ( is_array( $panodata ) ) {
1219 + if ( isset( $panodata['previewtext'] ) ) {
1220 + $panodata['previewtext'] = sanitize_text_field( $panodata['previewtext'] );
1221 + }
1222 + if ( isset( $panodata['defaultscene'] ) && is_string( $panodata['defaultscene'] ) ) {
1223 + $panodata['defaultscene'] = preg_replace( '/[^0-9a-zA-Z_\-]/', '', $panodata['defaultscene'] );
1224 + }
1225 + if ( isset( $panodata['panodata']['firstScene'] ) && is_string( $panodata['panodata']['firstScene'] ) ) {
1226 + $panodata['panodata']['firstScene'] = preg_replace( '/[^0-9a-zA-Z_\-]/', '', $panodata['panodata']['firstScene'] );
1227 + }
1228 + if ( isset( $panodata['panodata']['scene-list'] ) && is_array( $panodata['panodata']['scene-list'] ) ) {
1229 + foreach ( $panodata['panodata']['scene-list'] as $s_idx => $s_val ) {
1230 + if ( isset( $s_val['scene-id'] ) && is_string( $s_val['scene-id'] ) ) {
1231 + $panodata['panodata']['scene-list'][ $s_idx ]['scene-id'] = preg_replace( '/[^0-9a-zA-Z_\-]/', '', $s_val['scene-id'] );
1232 + }
1233 + }
1234 + }
1235 + }
1236 +
1237 + $publish_cap = $post_type_obj ? $post_type_obj->cap->publish_posts : 'publish_wpvr_tours';
1238 + $target_status = current_user_can( $publish_cap ) ? 'publish' : 'draft';
1239 +
1201 1240 if ( $existing_post_id > 0 ) {
1202 1241 $existing_post = get_post( $existing_post_id );
1203 1242 if ( ! $existing_post || 'wpvr_item' !== $existing_post->post_type || ! current_user_can( 'edit_post', $existing_post_id ) ) {
1204 1243 wp_send_json_error( array( 'message' => 'Invalid existing tour ID' ) );
@@ -1209,9 +1248,14 @@
1209 1248 wp_update_post(
1210 1249 array(
1211 1250 'ID' => $post_id,
1212 1251 'post_title' => $title,
1213 - 'post_status' => 'publish',
1252 + 'post_status' => $target_status,
1253 + // See note below: meta_input lands before transition_post_status fires.
1254 + 'meta_input' => array(
1255 + 'wpvr_created_from_wizard' => true,
1256 + 'wpvr_wizard_industry' => $industry,
1257 + ),
1214 1258 )
1215 1259 );
1216 1260 } else {
1217 1261 // Create new post
@@ -1216,11 +1260,17 @@
1216 1260 } else {
1217 1261 // Create new post
1218 1262 $post_data = array(
1219 1263 'post_title' => $title,
1220 - 'post_status' => 'publish',
1264 + 'post_status' => $target_status,
1221 1265 'post_type' => 'wpvr_item',
1222 1266 'post_author' => get_current_user_id(),
1267 + // meta_input is written before wp_insert_post() fires transition_post_status,
1268 + // so telemetry listening on that hook sees these flags already set.
1269 + 'meta_input' => array(
1270 + 'wpvr_created_from_wizard' => true,
1271 + 'wpvr_wizard_industry' => $industry,
1272 + ),
1223 1273 );
1224 1274
1225 1275 $post_id = wp_insert_post( $post_data );
1226 1276
@@ -1243,22 +1293,34 @@
1243 1293
1244 1294 // Save panodata as post meta
1245 1295 update_post_meta( $post_id, 'panodata', $panodata );
1246 1296
1247 - // Mark as created from wizard
1248 - update_post_meta( $post_id, 'wpvr_created_from_wizard', true );
1249 - update_post_meta( $post_id, 'wpvr_wizard_industry', $industry );
1250 -
1251 1297 // Save template meta fields if provided (dynamic meta from API)
1252 1298 $template_meta = isset($_POST['templateMeta']) ? json_decode( wp_unslash( $_POST['templateMeta'] ), true ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
1253 1299 if ( ! empty( $template_meta ) && is_array( $template_meta ) ) {
1300 + $allowed_meta_keys = apply_filters(
1301 + 'wpvr_wizard_allowed_template_meta_keys',
1302 + array(
1303 + 'wpvr_created_from_wizard',
1304 + 'wpvr_wizard_industry',
1305 + 'wpvr_tour_layout',
1306 + 'wpvr_custom_css',
1307 + 'wpvr_streetview_settings',
1308 + 'wpvr_general_settings',
1309 + 'wpvr_controls_settings',
1310 + 'wpvr_floor_plan_settings',
1311 + 'wpvr_checklist',
1312 + )
1313 + );
1314 +
1254 1315 foreach ( $template_meta as $meta_key => $meta_value ) {
1255 1316 // Sanitize meta key to ensure it's a valid meta key
1256 1317 $sanitized_key = sanitize_key( $meta_key );
1257 - if ( ! empty( $sanitized_key ) && 'panodata' !== $sanitized_key ) {
1318 + if ( ! empty( $sanitized_key ) && in_array( $sanitized_key, $allowed_meta_keys, true ) ) {
1258 1319 // Handle different value types
1259 1320 if ( is_array( $meta_value ) ) {
1260 - update_post_meta( $post_id, $sanitized_key, $meta_value );
1321 + $sanitized_value = map_deep( $meta_value, 'sanitize_text_field' );
1322 + update_post_meta( $post_id, $sanitized_key, $sanitized_value );
1261 1323 } else {
1262 1324 update_post_meta( $post_id, $sanitized_key, sanitize_text_field( $meta_value ) );
1263 1325 }
1264 1326 }
@@ -1268,13 +1330,15 @@
1268 1330 // Trigger tour saved action for telemetry
1269 1331 do_action('wpvr_rex_wpvr_tour_saved', $post_id);
1270 1332 do_action( 'wpvr_setup_wizard_completed_event', $industry );
1271 1333
1272 - // Persist industry selection for telemetry (aha event fires later from consent handler).
1273 - update_option( 'wpvr_industry_name', sanitize_text_field( $industry ), false );
1334 + if ( current_user_can( 'manage_options' ) ) {
1335 + // Persist industry selection for telemetry (aha event fires later from consent handler).
1336 + update_option( 'wpvr_industry_name', sanitize_text_field( $industry ), false );
1274 1337
1275 - // Mark wizard as permanently done so the onboarding notice is suppressed.
1276 - update_option( 'wpvr_wizard_onboarding_done', '1', false );
1338 + // Mark wizard as permanently done so the onboarding notice is suppressed.
1339 + update_option( 'wpvr_wizard_onboarding_done', '1', false );
1340 + }
1277 1341
1278 1342 wp_send_json_success( array(
1279 1343 'post_id' => $post_id,
1280 1344 'edit_url' => admin_url( 'post.php?action=edit&post=' . $post_id ),