AJAX Multi File Upload in WordPress Front-End

Date Posted: October 23, 2015, 9:42 am


Step 1: Create a custom page in WordPress

  • Go to your Dashboard > Pages > Add New
  • Name the page anything you want, ex: Ajax Uploader
  • In your Dashboard > Settings > Permalinks, make sure Common Settings is set to Post Name
  • In the new page, copy the page slag: if you used “Ajax Uploader” as your page name, the slag would be ajax-uploader
  • In your WordPress theme create a file called page-ajax-uploader.php  Notice how we attached the slag to the “page-“, this will allow us to add custom scripts that will only apply to this specific page.
  • Go to your browser and navigate to your new page. ex. http://example.com/ajax-uploader It should show you a blank white page, if not then you did something incorrectly.

Step 2: Working on our page

  • Building the HTML Form
1
2
3
4
5
6
7
8
9
10
<div class = "col-md-6 upload-form">
    <div class= "upload-response"></div>
    <div class = "form-group">
        <label><?php __('Select Files:', 'cvf-upload'); ?></label>
        <input type = "file" name = "files[]" accept = "image/*" class = "files-data form-control" multiple />
    </div>
    <div class = "form-group">
        <input type = "submit" value = "Upload" class = "btn btn-primary btn-upload" />
    </div>
</div>

Javascript

  • Setup our form data to be sent via AJAX:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
$(document).ready(function() {
    // When the Upload button is clicked...
    $('body').on('click', '.upload-form .btn-upload', function(e){
        e.preventDefault;

        var fd = new FormData();
        var files_data = $('.upload-form .files-data'); // The <input type="file" /> field
       
        // Loop through each data and create an array file[] containing our files data.
        $.each($(files_data), function(i, obj) {
            $.each(obj.files,function(j,file){
                fd.append('files[' + j + ']', file);
            })
        });
       
        // our AJAX identifier
        fd.append('action', 'cvf_upload_files');  
       
        // Remove this code if you do not want to associate your uploads to the current page.
        fd.append('post_id', <?php echo $post->ID; ?>);

        $.ajax({
            type: 'POST',
            url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
            data: fd,
            contentType: false,
            processData: false,
            success: function(response){
                $('.upload-response').html(response); // Append Server Response
            }
        });
    });
});
  • This is how your page-ajax-uploader.php template should look like:
  • Make sure you have the latest jQuery in your header.php
    1
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php get_header(); ?>

    <section class = "inner-page-wrapper">
        <section class = "container">
            <section class = "row content">
                <?php if ( have_posts() ) while ( have_posts() ) : the_post(); ?>
                    <article id="post-<?php the_ID(); ?>" <?php post_class(); ?>>
                        <h1><?php the_title(); ?></h1>
                        <article class="entry-content">
                            <?php the_content(); ?>
                           
                            <div class = "col-md-6 upload-form">
                                <div class= "upload-response"></div>
                                <div class = "form-group">
                                    <label><?php __('Select Files:', 'cvf-upload'); ?></label>
                                    <input type = "file" name = "files[]" accept = "image/*" class = "files-data form-control" multiple />
                                </div>
                                <div class = "form-group">
                                    <input type = "submit" value = "Upload" class = "btn btn-primary btn-upload" />
                                </div>
                            </div>
                                                                                   
                            <script type = "text/javascript">
                            $(document).ready(function() {
                                // When the Upload button is clicked...
                                $('body').on('click', '.upload-form .btn-upload', function(e){
                                    e.preventDefault;

                                    var fd = new FormData();
                                    var files_data = $('.upload-form .files-data'); // The <input type="file" /> field
                                   
                                    // Loop through each data and create an array file[] containing our files data.
                                    $.each($(files_data), function(i, obj) {
                                        $.each(obj.files,function(j,file){
                                            fd.append('files[' + j + ']', file);
                                        })
                                    });
                                   
                                    // our AJAX identifier
                                    fd.append('action', 'cvf_upload_files');  
                                   
                                    // uncomment this code if you do not want to associate your uploads to the current page.
                                    fd.append('post_id', <?php echo $post->ID; ?>);

                                    $.ajax({
                                        type: 'POST',
                                        url: '<?php echo admin_url( 'admin-ajax.php' ); ?>',
                                        data: fd,
                                        contentType: false,
                                        processData: false,
                                        success: function(response){
                                            $('.upload-response').html(response); // Append Server Response
                                        }
                                    });
                                });
                            });                    
                            </script>
                           
                           
                        </article>
                    </article>
                <?php endwhile; ?>
            </section>
        </section>
    </section>
   
<?php get_footer(); ?>

Server Side Processing

  • Add the code bellow to your functions.php
  • Don’t forget to read thru the comments found within the codes.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
add_action('wp_ajax_cvf_upload_files', 'cvf_upload_files');
add_action('wp_ajax_nopriv_cvf_upload_files', 'cvf_upload_files'); // Allow front-end submission

function cvf_upload_files(){
   
    $parent_post_id = isset( $_POST['post_id'] ) ? $_POST['post_id'] : 0;  // The parent ID of our attachments
    $valid_formats = array("jpg", "png", "gif", "bmp", "jpeg"); // Supported file types
    $max_file_size = 1024 * 500; // in kb
    $max_image_upload = 10; // Define how many images can be uploaded to the current post
    $wp_upload_dir = wp_upload_dir();
    $path = $wp_upload_dir['path'] . '/';
    $count = 0;

    $attachments = get_posts( array(
        'post_type'         => 'attachment',
        'posts_per_page'    => -1,
        'post_parent'       => $parent_post_id,
        'exclude'           => get_post_thumbnail_id() // Exclude post thumbnail to the attachment count
    ) );

    // Image upload handler
    if( $_SERVER['REQUEST_METHOD'] == "POST" ){
       
        // Check if user is trying to upload more than the allowed number of images for the current post
        if( ( count( $attachments ) + count( $_FILES['files']['name'] ) ) > $max_image_upload ) {
            $upload_message[] = "Sorry you can only upload " . $max_image_upload . " images for each Ad";
        } else {
           
            foreach ( $_FILES['files']['name'] as $f => $name ) {
                $extension = pathinfo( $name, PATHINFO_EXTENSION );
                // Generate a randon code for each file name
                $new_filename = cvf_td_generate_random_code( 20 )  . '.' . $extension;
               
                if ( $_FILES['files']['error'][$f] == 4 ) {
                    continue;
                }
               
                if ( $_FILES['files']['error'][$f] == 0 ) {
                    // Check if image size is larger than the allowed file size
                    if ( $_FILES['files']['size'][$f] > $max_file_size ) {
                        $upload_message[] = "$name is too large!.";
                        continue;
                   
                    // Check if the file being uploaded is in the allowed file types
                    } elseif( ! in_array( strtolower( $extension ), $valid_formats ) ){
                        $upload_message[] = "$name is not a valid format";
                        continue;
                   
                    } else{
                        // If no errors, upload the file...
                        if( move_uploaded_file( $_FILES["files"]["tmp_name"][$f], $path.$new_filename ) ) {
                           
                            $count++;

                            $filename = $path.$new_filename;
                            $filetype = wp_check_filetype( basename( $filename ), null );
                            $wp_upload_dir = wp_upload_dir();
                            $attachment = array(
                                'guid'           => $wp_upload_dir['url'] . '/' . basename( $filename ),
                                'post_mime_type' => $filetype['type'],
                                'post_title'     => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
                                'post_content'   => '',
                                'post_status'    => 'inherit'
                            );
                            // Insert attachment to the database
                            $attach_id = wp_insert_attachment( $attachment, $filename, $parent_post_id );

                            require_once( ABSPATH . 'wp-admin/includes/image.php' );
                           
                            // Generate meta data
                            $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
                            wp_update_attachment_metadata( $attach_id, $attach_data );
                           
                        }
                    }
                }
            }
        }
    }
    // Loop through each error then output it to the screen
    if ( isset( $upload_message ) ) :
        foreach ( $upload_message as $msg ){       
            printf( __('<p class="bg-danger">%s</p>', 'wp-trade'), $msg );
        }
    endif;
   
    // If no error, show success message
    if( $count != 0 ){
        printf( __('<p class = "bg-success">%d files added successfully!</p>', 'wp-trade'), $count );  
    }
   
    exit();
}

// Random code generator used for file names.
function cvf_td_generate_random_code($length=10) {
 
   $string = '';
   $characters = "23456789ABCDEFHJKLMNPRTVWXYZabcdefghijklmnopqrstuvwxyz";
 
   for ($p = 0; $p < $length; $p++) {
       $string .= $characters[mt_rand(0, strlen($characters)-1)];
   }
 
   return $string;
 
}

About author


Carl Victor Fontanos

A fine gentleman specializing in front-end and back-end development with extensive experience building high performance web applications that keeps users engaged and help businesses grow.

 
Hire Me