WordPress and AJAX – Upload image as featured

I’m using wordpress with ajax in a frontend form and I’d need support for handling and uploading the featured image. My problem is specifically about the featured image. My html is something like:

<form id="msform" action="#" method="post" enctype="multipart/form-data">
//inputs of various nature
<input type="file" name="main_image" id="main_image"  multiple="false" value="" accept=".png, .jpg, .jpeg, .gif"/>
<input type="submit" class="submit" value="Publish"/>
</form>

I send data to a php function (following WordPress methods) through this jquery:

Read More
function apfaddpost() {
    var formData = $('#msform').serialize();
    formData.append('main_image', $('#main_image')[0].files[0]); //here should be the problem
    jQuery.ajax({
        type: 'POST',
        url: apfajax.ajaxurl,
        data: formData + '&action=apf_addpost', //here I send data to the php function calling the specific action
        processData: false,
        contentType: false

        success: function(data, textStatus, XMLHttpRequest) {
            var id = '#apf-response';
            jQuery(id).html('');
            jQuery(id).append(data);
            resetvalues();
        },

        error: function(MLHttpRequest, textStatus, errorThrown) {
            alert(errorThrown);
        }

    });
}

My function php is something like

function apf_addpost() {
    require_once(ABSPATH . "wp-admin" . '/includes/image.php');
    require_once(ABSPATH . "wp-admin" . '/includes/file.php');
    require_once(ABSPATH . "wp-admin" . '/includes/media.php');
    $file_handler = 'main_image';
    $attach_id = media_handle_upload($file_handler,$pid );
    update_post_meta($pid,'_thumbnail_id',$attach_id);
}

Important to say: all the other data like title, description, tags are correctly serialized and sent. The problem is for the image. I’ve tried also to use the $_FILES[] handler without success and I suppose that my ajax code is not so great then. Can you help me? If you have any other workaround for this issue please share! Thanks in advance.

[SOLVED] EDIT

Thanks to the answers below I’ve just changed my ajax into

function apfaddpost() {
    var fd = new FormData($('#msform')[0]);
    fd.append( "main_image", $('#main_image')[0].files[0]);
    fd.append( "action", 'apf_addpost');      
   //Append here your necessary data
    jQuery.ajax({
        type: 'POST',
        url: apfajax.ajaxurl,
        data: fd, 
        processData: false,
        contentType: false,

        success: function(data, textStatus, XMLHttpRequest) {
            var id = '#apf-response';
            jQuery(id).html('');
            jQuery(id).append(data);
            resetvalues();
        },

        error: function(MLHttpRequest, textStatus, errorThrown) {
            alert(errorThrown);
        }

    });
}

I’ve discovered that FormData() allows to serialize files, thing that .serialize() method doesn’t. Known that, it has been simple to move on.
Thanks.

Related posts

2 comments

  1. Please Try :

    I have modify your code.

    Jquery (added FormData() and append)

    function apfaddpost() {
        var fd = new FormData();
        fd.append( "main_image", $('#main_image')[0].files[0]);
        fd.append( "action", 'apf_addpost');      
       //Append here your necessary data
        jQuery.ajax({
            type: 'POST',
            url: apfajax.ajaxurl,
            data: fd, 
            processData: false,
            contentType: false
    
            success: function(data, textStatus, XMLHttpRequest) {
                var id = '#apf-response';
                jQuery(id).html('');
                jQuery(id).append(data);
                resetvalues();
            },
    
            error: function(MLHttpRequest, textStatus, errorThrown) {
                alert(errorThrown);
            }
    
        });
    }
    

    in function.php

    I have added file upload code

    /******FILE UPLOAD*****************/
    function upload_user_file( $file = array() ) {    
        require_once( ABSPATH . 'wp-admin/includes/admin.php' );
        $file_return = wp_handle_upload( $file, array('test_form' => false ) );
        if( isset( $file_return['error'] ) || isset( $file_return['upload_error_handler'] ) ) {
            return false;
        } else {
            $filename = $file_return['file'];
            $attachment = array(
                'post_mime_type' => $file_return['type'],
                'post_title' => preg_replace( '/.[^.]+$/', '', basename( $filename ) ),
                'post_content' => '',
                'post_status' => 'inherit',
                'guid' => $file_return['url']
            );
            $attachment_id = wp_insert_attachment( $attachment, $file_return['url'] );
            require_once(ABSPATH . 'wp-admin/includes/image.php');
            $attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
            wp_update_attachment_metadata( $attachment_id, $attachment_data );
            if( 0 < intval( $attachment_id ) ) {
              return $attachment_id;
            }
        }
        return false;
    }
    

    now modify your function apf_addpost() in function.php

    function apf_addpost() {
         foreach( $_FILES as $file ) 
         {  
              if( is_array( $file ) ) {
                    $attach_id =upload_user_file();  //Call function 
                    update_post_meta($pid,'_thumbnail_id',$attach_id);
              }
         }
    
    }
    
  2. For ajax upload in WordPress these are a few things to note;

    HTML

    For sending images a form with enctype="multipart/form-data" is necessary. enctype attribute specifies how the form-data is encoded during form submission. By default its application/x-www-form-urlencoded as we are doing a file upload we change the value to multipart/form-data.

      <form action="" method="post" enctype="multipart/form-data">
          <input type="file" id="image_upload">
          <button type="button" id="image_upload_btn">Update</button>
      </form>
    

    AJAX

    $("#image_upload_btn").click(function (e) {
      e.preventDefault();
      var fd = new FormData();
      var files = $("#image_upload")[0].files;
      fd.append("file", files[0]);
      fd.append("action", "upload_image"); // your ajax function
    
      if (files.length > 0) {
        jQuery.ajax({
          type: "POST",
          url: ajax_url, //  var ajax_url = " <?= admin_url('admin-ajax.php'); ?>"; pass it in the php file
          processData: false,
          contentType: false,
          data: fd,
          beforeSend: function () {
    // Any code you like
          },
          success: function (response) {
    // Success code
          },
          error: function (request, status, error) {
            console.log(error);
            alert(request.responseText);
          },
        });
      }
    });
    

    We need to use a FormData() interface to construct a set of key/value pairs that represent our form fields and values(here it’s our image file). This helps to easily transfer the file using ajax.

    As we are using WordPress, in addition to the image file we also add in the action parameter as well in the FormData().

    Another important thing to note here is the processData and contentType without which you are likely to face Uncaught TypeError: Illegal invocation.

    1. Why processData ?

    The data passed in the data option as the object is processed and transformed into a query string for ajax by default, as we are doing a file upload we want that to be false.

    1. Why contentType ?

    By default it’s application/x-www-form-urlencoded; charset=UTF-8 for file uploads we have to explicitly change it to false to unset any content-type header.

    PHP

    function upload_image()
    
    {
        if (isset($_FILES['file']['name'])) {
            $filename = $_FILES['file']['name'];
    
            $location = ;// Your desired location
            $imageFileType = pathinfo($location, PATHINFO_EXTENSION);
            $imageFileType = strtolower($imageFileType);
    
            $valid_extionsions = array("jpg", "jpeg", "png");
    
            $response = 0;
    
            if (in_array($imageFileType, $valid_extionsions)) {
                if (move_uploaded_file($_FILES['file']['tmp_name'], $location)) {
                    $response = $location; // this is to return the file path after upload
                }
            }
            echo $response;
            exit;
        }
    }
    add_action("wp_ajax_upload_image", "upload_image");
    add_action("wp_ajax_nopriv_upload_image", "upload_image");
    

    Please note to add wp_ajax and wp_ajax_nopriv instead or wp_admin

Comments are closed.