Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ajax file upload in Wordpress - can't pass FormData

I've made a script which uses $.ajax and FormData to pass two form objects to PHP. One form object is a text and the other is a file. It worked well as a stand-alone script. However, after I added it to Wordpress, as a plugin, it keeps giving me "Uncaught TypeError: Illegal invocation".

I can't afford to serialize the formdata, simply because then I won't be able to pass the file to the callback function in PHP.

JS involving FormData before ajax call:

var fd = new FormData();
var file = jQuery(this).find('input[type="file"]');
var caption = jQuery(this).find('input[name=img_caption]');
var individual_file = file[0].files[0];
fd.append("file", individual_file);
var individual_capt = caption.val();
fd.append("caption", individual_capt);

This part above is 100% correct.

Ajax call:

jQuery.ajax({
    type: 'POST',
    url: fiuajax.ajaxurl,
    data: {
        action: 'fiu_upload_file',
        security: fiuajax.security,
        data: fd,
        contentType: false,
        processData: false,
    },
    success: function(response){
        var dataObj = jQuery.parseJSON(response);
        if(dataObj.message == 'error') {
            jQuery('.fiu_validation').html('The following error occured: '+dataObj.desc);
        }
        else if(dataObj.message == 'success') {
            jQuery('.fiu_file').val('');
        }
        console.log(response);
    }
});

This is incredibly frustrating since it worked perfectly fine outside of Wordpress. I've tried de-registering Wordpress' jQuery and enqueueing the latest jQuery version, but it made no difference.

To recap:
1) Ajax/jQuery is refusing to pass a form object to PHP
2) Can't serialize the object because I need to preserve the file object
3) Script works outside of Wordpress
4) Tried updating to the newest jQuery version, no change

like image 579
Stefan Avatar asked Jan 24 '15 12:01

Stefan


2 Answers

try this :

jQuery(document).on('click', '#submit', function(e){
    e.preventDefault();

    var fd = new FormData();
    var file = jQuery(document).find('input[type="file"]');
    var caption = jQuery(this).find('input[name=img_caption]');
    var individual_file = file[0].files[0];
    fd.append("file", individual_file);
    var individual_capt = caption.val();
    fd.append("caption", individual_capt);  
    fd.append('action', 'fiu_upload_file');  

    jQuery.ajax({
        type: 'POST',
        url: fiuajax.ajaxurl,
        data: fd,
        contentType: false,
        processData: false,
        success: function(response){

            console.log(response);
        }
    });
});

php

function fiu_upload_file(){

    var_dump($_FILES);
    exit();
}

add_action('wp_ajax_fiu_upload_file', 'fiu_upload_file');
add_action('wp_ajax_nopriv_fiu_upload_file', 'fiu_upload_file');
like image 196
David Avatar answered Oct 18 '22 16:10

David


I managed to do it. The code works on the latest version of Wordpress (4.9.4)

First of all, I'm using XMLHttpRequest to send the data and not the jQuery ajax. This means that you can adapt it to just pure JS. Notice the xhttp.setRequestHeader("enctype","multipart/form-data"); which was essential to pass the FormData using this method.

JS:

var user_id = $('#user_id').val();
var picture = $('#userPic')[0].files[0];

console.log(picture);

if( picture && typeof picture !== undefined ) {

  if ( picture['size'] > 1000000 ) {
    alert('The Profile Pic can\'t be larger than 1Mb.');
    return;
  }

  if ( picture['type'].indexOf('image') == -1 ) {
    alert('The uploaded file needs to be an image.');
    return;
  }

  var data = new FormData();
  data.append('user_id', user_id);
  data.append('userPic', picture);

  // console.log(data);

  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      console.log('Receive:' + this.responseText);
    }
  };
  xhttp.open("POST", location.origin + "/wp-content/themes/search-and-go-child/ajax/upload_user_profile_pic_ajax.php", true);
    xhttp.setRequestHeader("enctype","multipart/form-data");
  xhttp.send(data);

}

The PHP part is also extremely useful since it requires the files needed to manipulate the received data with the WP core functions. Here you will also find the code to upload an attachment using the WP core functions.

PHP:

    // error_reporting(-1);
    // ini_set('display_errors', 'On');
    $path = $_SERVER['DOCUMENT_ROOT'];
    require_once($path.'/wp-load.php');
    require_once( '/home/s24t06b21lk5/public_html/wp-includes/template-loader.php' );
    // require_once("/home/s24t06b21lk5/public_html/wp-admin" . '/includes/image.php');
    require_once("/home/s24t06b21lk5/public_html/wp-admin" . '/includes/file.php');
    // require_once("/home/s24t06b21lk5/public_html/wp-admin" . '/includes/media.php');


    $user_id = $_POST['user_id'];
    $picture = $_FILES['userPic'];


    var_dump($user_id);
    var_dump($picture);

    $response = array();

    if( isset($picture['name']) && $picture['name'] ) {

        // Get the path to the upload directory.
        $wp_upload_dir = wp_upload_dir();           

        $picture['name'] = preg_replace( '/[^0-9a-zA-Z.]/', '', basename( $picture['name'] ) );

        // Upload the file
        $upload_overrides = array( 'test_form' => false );
        $upload_result = wp_handle_upload($picture, $upload_overrides);
        // echo '<pre>'; print_r($upload_result); echo '</pre>' ;

        if( $upload_result['url'] ) {

            // Prepare an array of post data for the attachment.
            $attachment = array(
                'guid'           => $upload_result['url'], 
                'post_mime_type' => $picture['type'],
                'post_title'     => $picture['name'],
                'post_content'   => '',
                'post_status'    => 'inherit'
            );


            $attach_id = wp_insert_attachment( $attachment, $upload_result['file'] );

            if( $attach_id ) {

                // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
                require_once( ABSPATH . 'wp-admin/includes/image.php' );

                // Generate the metadata for the attachment, and update the database record.
                $attach_data = wp_generate_attachment_metadata( $attach_id, $upload_result['file'] );
                wp_update_attachment_metadata( $attach_id, $attach_data );

                // Update the usermeta table with the uploaded avatar
                if( !update_user_meta($user_id, 'wp_user_avatar', $attach_id ) || !update_user_meta($user_id, 'wp_zfgrf5v7rw_user_avatar', $attach_id) ) {
                    $response['result'] = FALSE;
                    $response['message'] = "The uploaded image could not be associated with the User ID in the database.";              
                }
                else {
                    $response['result'] = TRUE;             
                }


            }
            else {
                $response['result'] = FALSE;
                $response['message'] = "Wordpress attachment post for the user's image could not created.";
            }

        }
        else {
            $response['result'] = FALSE;
            $response['message'] = "The file couldn't be uploaded. Check the permissions.";
        }

    }

    die( json_encode($response) );

Thank you.

like image 34
TheoPlatica Avatar answered Oct 18 '22 16:10

TheoPlatica