0

When submitting form data via jQuery and using admin-ajax, including a file attachment was easy:

var data = new FormData($(this)[0]);

How do you include a file attachment when submitting form data to a Rest Controller?

This submits all the form fields, except the file attachment.

var data = $this.serializeArray();

The jQuery:

   $('#create-book-form').submit(function (e) {
    
        var $this = $(this);
        e.preventDefault();
    
        //var data = new FormData($(this)[0]); 
    
        var data = $this.serializeArray(); 
        data.push({name: "rtype", value: "create"});
    
        $.ajax({
    
            url: BOOK_SUBMITTER.root + 'rfp-books/v1/books',
            data: $.param(data),
            beforeSend: function ( xhr ) {
                xhr.setRequestHeader( 'X-WP-Nonce', BOOK_SUBMITTER.nonce );
            },
            //etc

It all works, except the file is not part of the form data that arrives at the rest controller. Yes, I have an input called 'file' so the user can include a jpg.

I need to send all the form data in a single call. The post attachment is created right after the post is created in the controller. So, how do I get the file into the data included in $.param(data)

In the route callback in the REST Controller:

$params = $request->get_params();
write_log( $params );

The log shows all the form data - except the file. ( If I submit the jQuery data as FormData, none of the data is recognized in the controller. )

2 Answers 2

1

You can really use FormData just like you could use it with the old admin-ajax.php route, but:

  1. Set processData and contentType to false.

  2. Set the method to POST and make sure your REST API route supports the POST method.

    $('#create-book-form').submit(function (e) {
    
    //  var $this = $(this); // what's this?
        e.preventDefault();
    
        var data = new FormData( this ); 
    
        data.append( 'rtype', 'create' ); // add extra param
    
        $.ajax({
    
            url: BOOK_SUBMITTER.root + 'rfp-books/v1/books',
            data: data, //$.param(data),
            processData: false,
            contentType: false,
            method: 'POST',
            beforeSend: function ( xhr ) {
                xhr.setRequestHeader( 'X-WP-Nonce', BOOK_SUBMITTER.nonce );
            },
            success: function ( data ) {
                console.log( data ); // I added just for testing purposes.
            },
        });
    });
    

Then in your REST API endpoint callback, just use the $_FILES to get the uploaded file, e.g. $_FILES['file']. For other parameters, you can use $request->get_param(), e.g. $request->get_param( 'rtype' ).

Additionally or to other readers, you should have a file upload input in your form, e.g. <input type="file" name="file" />, but the name can be anything unless if you're creating an attachment using the default wp/v2/media route.

4
  • PS: You can try my sample plugin. Just follow the guide there. Let me know.
    – Sally CJ
    Jul 19, 2020 at 14:19
  • 1
    Bingo! Setting method: 'POST' was the key. In the register route, I have methods set to ALLMETHODS. Seems it has to be explicit in the ajax for files. Anyhow, I really appreciate your effort and patience.
    – shanebp
    Jul 19, 2020 at 14:23
  • 1
    And thanks for sharing the plugin. I'm sure it will be useful to others.
    – shanebp
    Jul 19, 2020 at 14:24
  • Yep, the request method has to be POST, because binary file data can't be put in the URL as query string which is how the form data would be submitted when using the GET request method which is the default in jQuery.ajax().
    – Sally CJ
    Jul 19, 2020 at 14:54
0

i have used this code which uploads file in an ajax request

<style>
    .wbc_form {
        width: 500px;
        max-width: 100%;
        margin: 0 auto;
        text-align: center;
    }

    .image_preview {
        width: 500px;
        max-width: 100%;
        height: 250px;
        border: 3px dashed #eee;
        display: flex;
        align-items: center;
        justify-content: center;
    }

    .image_preview img {
        width: 100%;
        height: auto;
        max-height: 100%;
        display: none;
    }
</style>
<form class="wbc_form" action="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ) ?>" method="POST"
      enctype="multipart/form-data">
    <h1>
        <?php esc_html_e( 'Upload payment confirmation image', 'wbc' ); ?>
    </h1>
    <input type="hidden" name="action" value="wbc_bacs_confirm">
    <?php wp_nonce_field() ?>
    <input type="hidden" name="order_id" id="wbc_order_id" value="<?php echo esc_attr( $order_id ); ?>">
    <input type="file" class="wbc_image" name="wbc_image" value="" accept="image/*">
    <div class="image_preview">
        <img src="" class="img_preview__image" alt="Preview">
        <span class="img_preview__default_text"><?php esc_html_e( 'Image Preview', 'wbc' ); ?></span>
    </div>
    <br>
    <button class="go_now button alt" type="submit"><?php esc_html_e( 'Send', 'wbc' ); ?></button>
</form>

<script>
    (function ($) {
        let input_file = $('.wbc_image'),
            preview_image = $('.img_preview__image'),
            preview_text = $('.img_preview__default_text');

        input_file.on('change', function (e) {
            let f = this.files[0];

            //here I CHECK if the FILE SIZE is bigger than 2 MB (numbers below are in bytes)
            if (f.size > 2097152 || f.fileSize > 2097152) {
                //show an alert to the user
                alert(wbc_object.max_file_size_msg);
                //reset file upload control
                this.value = null;
            }

            let file = e.target.files[0];
            if (file) {
                let reader = new FileReader();
                preview_text.hide();
                preview_image.show();
                reader.onload = function (event) {
                    preview_image.attr("src", event.target.result)
                };
                reader.readAsDataURL(file);
            } else {
                preview_image.attr('src', '');
                preview_image.hide();
                preview_text.show();
            }
        });


        $('.wbc_form').on('submit', function (e) {
            e.preventDefault();
            var formData = new FormData(this);
            $.ajax({
                url: wbc_object.ajax_url,
                type: "POST",
                data: formData,
                contentType: false,
                processData: false,
                success: function (response) {
                    // console.log(response);
                    if (response.success) {
                        $('.wbc_form').html(wbc_object.request_received_msg);
                    } else {
                        //show the toastr js message
                        // toastr.error(response.data.msg);
                    }
                }
            });
        });

    })(jQuery);
</script>

then you will receive the file in the request parameters

1
  • Thanks, but I am using the wp rest api - not admin-ajax. So a different approach is required.
    – shanebp
    Jul 19, 2020 at 11:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.