Modify the code to fix the issue: Woocommerce Product Reviews Media Upload Functionality, Customer uploaded files are not getting saved to our servers.

<?php

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

// --- Enqueue Scripts and Styles ---
add_action( 'wp_enqueue_scripts', 'enqueue_review_media_assets' );
function enqueue_review_media_assets() {
    // Only load on single product pages where reviews are typically found
    if (is_product()) {
        
        wp_enqueue_script('reviews-media-js', get_template_directory_uri() . '/js/reviews-media.js', array('jquery'), '1.0', true );
        
        wp_enqueue_style('reviews-media-css', get_template_directory_uri() . '/css/reviews-media.css', array(), false );

        // Localize script for AJAX and settings
        wp_localize_script( 'reviews-media-js', 'rm_vars', array(
            'ajax_url'   => admin_url('admin-ajax.php'),
            'max_imgs'   => 5,
            'max_vids'   => 1,
            'max_img_size' => 5 * 1024 * 1024,   // 5MB
            'max_vid_size' => 20 * 1024 * 1024,  // 20MB
            'nonce'      => wp_create_nonce('reviews_media_nonce'),
        ) );
    }
}

// 2. AJAX handler for upload
add_action( 'wp_ajax_upload_review_media', 'upload_review_media' );
add_action( 'wp_ajax_nopriv_upload_review_media', 'upload_review_media' );
function upload_review_media() {
    check_ajax_referer( 'reviews_media_nonce', 'nonce' );
    if ( empty($_FILES['file']) ) {
        wp_send_json_error('No file found');
    }
    $file = $_FILES['file'];
    $type = sanitize_text_field( $_POST['media_type'] ); // "image" or "video"

    // Validate size & type
    $is_image = strpos($file['type'], 'image/') === 0;
    $is_video = strpos($file['type'], 'video/') === 0;
    if ( $type === 'image' && ! $is_image ) {
        wp_send_json_error('Not an image');
    }
    if ( $type === 'video' && ! $is_video ) {
        wp_send_json_error('Not a video');
    }
    if ( $type==='image' && $file['size'] > rm_vars['max_img_size'] ) {
        wp_send_json_error('Image too large');
    }
    if ( $type==='video' && $file['size'] > rm_vars['max_vid_size'] ) {
        wp_send_json_error('Video too large');
    }

    // Upload location
    $upload_dir = wp_upload_dir();
    $base = trailingslashit( $upload_dir['basedir'] ) . 'reviews-media-storage/';
    if ( ! file_exists( $base ) ) {
        wp_mkdir_p( $base );
    }
    // Unique filename
    $filename = wp_unique_filename( $base, $file['name'] );
    $target   = $base . $filename;

    if ( move_uploaded_file( $file['tmp_name'], $target ) ) {
        $url = trailingslashit( $upload_dir['baseurl'] ) . 'reviews-media-storage/' . $filename;
        wp_send_json_success( array(
            'url'       => esc_url($url),
            'filename'  => esc_attr($filename),
            'media_type'=> $type,
        ) );
    } else {
        wp_send_json_error('Upload failed');
    }
}

// 3. AJAX handler for delete
add_action( 'wp_ajax_delete_review_media', 'delete_review_media' );
add_action( 'wp_ajax_nopriv_delete_review_media', 'delete_review_media' );
function delete_review_media() {
    check_ajax_referer( 'reviews_media_nonce', 'nonce' );
    $filename = sanitize_file_name( $_POST['filename'] );
    $upload_dir = wp_upload_dir();
    $path = trailingslashit( $upload_dir['basedir'] ) . 'reviews-media-storage/' . $filename;
    if ( file_exists( $path ) ) {
        unlink( $path );
        wp_send_json_success();
    }
    wp_send_json_error('File not found');
}

// 4. Save media references when review is submitted
add_action( 'comment_post', 'save_review_media_meta', 10, 2 );
function save_review_media_meta( $comment_id, $approved ) {
    if ( isset($_POST['reviews_media']) ) {
        $files = array_map( 'esc_url_raw', (array) $_POST['reviews_media'] );
        update_comment_meta( $comment_id, 'reviews_media', $files );
    }
}

// 5. Append media after the comment text
add_filter( 'comment_text', 'append_review_media_to_comment', 20, 2 );
function append_review_media_to_comment( $text, $comment ) {
    $media = get_comment_meta( $comment->comment_ID, 'reviews_media', true );
    if ( is_array($media) && !empty($media) ) {
        $out = '<div class="review-media-gallery">';
        foreach ( $media as $url ) {
            if ( preg_match('/\.(mp4|webm|ogg)$/i', $url) ) {
                $out .= '<video controls src="'. esc_url($url) .'" class="review-video"></video>';
            } else {
                $out .= '<img src="'. esc_url($url) .'" class="review-image"/>';
            }
        }
        $out .= '</div>';
        $text .= $out;
    }
    return $text;
}

// 6. Display all customers' media before comment list
add_action( 'display_all_customer_review_media_gallery', 'display_all_reviews_media' );
function display_all_reviews_media() {
    if ( ! is_product() ) return;
    global $product;
    $comments = get_comments( array(
        'post_id' => $product->get_id(),
        'status'  => 'approve',
        'meta_key'=> 'reviews_media',
    ) );
    if ( empty($comments) ) return;

    $all = array();
    foreach ( $comments as $c ) {
        $m = get_comment_meta( $c->comment_ID, 'reviews_media', true );
        if ( is_array($m) ) {
            $all = array_merge( $all, $m );
        }
    }
    if ( empty($all) ) return;

    echo '<div class="all-reviews-media-gallery">';
    foreach ( array_unique($all) as $url ) {
        if ( preg_match('/\.(mp4|webm|ogg)$/i', $url) ) {
            echo '<video controls src="'.esc_url($url).'" class="thumb-video"></video>';
        } else {
            echo '<img src="'.esc_url($url).'" class="thumb-image"/>';
        }
    }
    echo '</div>';
}

// 7. Inject upload controls into the review form
add_action( 'comment_form_after_fields', 'add_reviews_media_fields' );
add_action( 'comment_form_logged_in_after', 'add_reviews_media_fields' );
function add_reviews_media_fields() {
    ?>
    <div id="reviews-media-uploader">
      <p><strong>Upload up to 5 images and 1 video</strong></p>
      <div class="rm-field">
        <label>Images:</label>
        <input type="file" id="rm-image-input" multiple accept="image/*">
      </div>
      <div class="rm-field">
        <label>Video:</label>
        <input type="file" id="rm-video-input" accept="video/*">
      </div>
      <div id="rm-preview"></div>
    </div>
    <?php
}


jQuery(function($){
  let pending = 0;
  const uploadedFiles = [];

  function toggleSubmit() {
    $('#submit').prop('disabled', pending > 0);
  }

  function startUpload(file, type) {
    const data = new FormData();
    data.append('action','upload_review_media');
    data.append('nonce', rm_vars.nonce);
    data.append('media_type', type);
    data.append('file', file);

    const id = Date.now() + Math.random().toString(36).substr(2,5);
    const $item = $(`
      <div class="rm-file" data-id="${id}">
        <span class="rm-name">${file.name}</span>
        <button class="rm-cancel">✖</button>
        <div class="rm-progress"><div class="rm-bar"></div></div>
      </div>
    `).appendTo('#rm-preview');

    const xhr = new XMLHttpRequest();
    xhr.open('POST', rm_vars.ajax_url, true);

    xhr.upload.onprogress = function(e) {
      if (e.lengthComputable) {
        let pct = (e.loaded / e.total * 100).toFixed(0);
        $item.find('.rm-bar').css('width', pct+'%');
      }
    };

    xhr.onload = function(){
      pending--;
      toggleSubmit();
      if (xhr.status === 200) {
        let res = JSON.parse(xhr.responseText);
        if (res.success) {
          $item.find('.rm-progress').remove();
          $item.append('<button class="rm-delete">🗑</button>');
          $item.data('filename', res.data.filename);
          uploadedFiles.push(res.data.url);
          // hidden input
          $('<input>').attr({
            type:'hidden',
            name:'reviews_media[]',
            value: res.data.url,
            'data-id': id
          }).appendTo('#commentform');
        } else {
          $item.addClass('rm-error').find('.rm-name').text(res.data);
        }
      }
    };

    xhr.onerror = function(){
      pending--;
      toggleSubmit();
      $item.addClass('rm-error');
    };

    xhr.send(data);
    pending++;
    toggleSubmit();

    // cancel
    $item.on('click', '.rm-cancel', function(){
      xhr.abort();
      pending--;
      toggleSubmit();
      $item.remove();
    });

    // delete after upload
    $item.on('click', '.rm-delete', function(){
      const fname = $item.data('filename');
      $.post(rm_vars.ajax_url, {
        action: 'delete_review_media',
        nonce:  rm_vars.nonce,
        filename: fname
      }, function(res){
        if (res.success) {
          // remove hidden input
          $('input[name="reviews_media[]"][value="'+$item.find('.rm-name').text()+'"]').remove();
          $item.remove();
        }
      });
    });
  }

  $('#rm-image-input').on('change', function(){
    const files = this.files;
    if (files.length + $('.rm-file').length > rm_vars.max_imgs + rm_vars.max_vids) {
      alert('Image count limit reached.');
      return;
    }
    Array.from(files).forEach(f => {
      if (f.size > rm_vars.max_img_size) {
        alert(f.name + ' is too big.');
      } else {
        startUpload(f, 'image');
      }
    });
    $(this).val('');
  });

  $('#rm-video-input').on('change', function(){
    const files = this.files;
    if ($('.rm-file[data-type="video"]').length >= rm_vars.max_vids) {
      alert('Only one video allowed.');
      return;
    }
    Array.from(files).forEach(f => {
      if (f.size > rm_vars.max_vid_size) {
        alert(f.name + ' is too big.');
      } else {
        startUpload(f, 'video');
      }
    });
    $(this).val('');
  });

});


#reviews-media-uploader { margin: 1em 0; border: 1px solid #ddd; padding: 1em; }
.rm-field { margin-bottom: .5em; }
#rm-preview { display:flex; flex-wrap: wrap; gap: .5em; }
.rm-file {
  position: relative;
  width: 120px; padding: .5em;
  border: 1px solid #ccc;
  background: #f9f9f9;
}
.rm-file .rm-name { display: block; font-size: .8em; margin-bottom: .3em; word-break: break-all; }
.rm-progress { width: 100%; height: 5px; background: #eee; margin-top: .3em; }
.rm-bar { height: 5px; width: 0; background: #4caf50; }
.rm-cancel, .rm-delete {
  position: absolute; top: 2px; right: 2px;
  background: transparent; border: none; cursor: pointer;
}
.rm-delete { top: auto; bottom: 2px; }
.review-media-gallery, .all-reviews-media-gallery {
  display: flex; flex-wrap: wrap; gap: 10px; margin-top: 1em;
}
.review-image, .thumb-image { max-width: 100px; border:1px solid #ddd; }
.review-video, .thumb-video { max-width: 150px; }