How to Allow Users to Upload Photos to Wordpress
Read Time: xiii mins Languages:
In this tutorial, you'll learn how to create a plugin that allows users to submit images and upload them to the WordPress media library. Yous'll also larn how to correctly delete images from the WordPress media library equally well as do some basic validation on uploaded images.
Previously...
This tutorial is by request from some users who found my quotes plugin tutorial interesting but were especially keen to find out how the same technique could exist used to upload images from the frontend. Then here'south a reiteration of that tutorial that does just that. For detailed info almost plugin setup, shortcodes and nonces, see the previous tutorial.
The plugin will:
- display an image upload form using a shortcode
- accept but images of a certain blazon and maximum size
- add a custom post type for user images
- add images to the WordPress media library with a proper attachment caption
- display unpublished images
- let users to delete their unpublished images
We will use the congenital-in WordPress postal service thumbnail (aka Featured Paradigm) meta field to concur the image for each postal service. This also makes it easier to display and piece of work with our image equally we tin can utilise the post_thumbnail functions.
Here's what nosotros're aiming for:
All lawmaking is available in the plugin source at the acme of this tutorial.
Step 1 Set-Upward the Plugin
Create a plugin file named submit_user_images.php
in the wp-content/plugins/submit-user-images
directory.
Refer to the plugin source for plugin header info.
Step 2 Plugin Initialization Part
We're going to create a custom post type named user_images to agree our user images and a custom taxonomy named user_image_category. This will enable cleaner administration of the images than only assigning them to normal posts and categories.
The Init Hook and Function
We'll utilize the following initialization lawmaking to create our custom post type and custom taxonomy:
add_action('init', 'sui_plugin_init'); part sui_plugin_init(){ $image_type_labels = assortment( 'name' => _x('User images', 'post type general proper name'), 'singular_name' => _x('User Image', 'mail type atypical name'), 'add_new' => _x('Add New User Prototype', 'image'), 'add_new_item' => __('Add together New User Epitome'), 'edit_item' => __('Edit User Image'), 'new_item' => __('Add New User Prototype'), 'all_items' => __('View User Images'), 'view_item' => __('View User Image'), 'search_items' => __('Search User Images'), 'not_found' => __('No User Images found'), 'not_found_in_trash' => __('No User Images found in Trash'), 'parent_item_colon' => '', 'menu_name' => 'User Images' ); $image_type_args = assortment( 'labels' => $image_type_labels, 'public' => true, 'query_var' => true, 'rewrite' => true, 'capability_type' => 'post', 'has_archive' => true, 'hierarchical' => false, 'map_meta_cap' => true, 'menu_position' => zero, 'supports' => array('title', 'editor', 'author', 'thumbnail') ); register_post_type('user_images', $image_type_args); $image_category_labels = array( 'proper name' => _x( 'User Paradigm Categories', 'taxonomy general name' ), 'singular_name' => _x( 'User Image', 'taxonomy singular name' ), 'search_items' => __( 'Search User Prototype Categories' ), 'all_items' => __( 'All User Image Categories' ), 'parent_item' => __( 'Parent User Image Category' ), 'parent_item_colon' => __( 'Parent User Image Category:' ), 'edit_item' => __( 'Edit User Image Category' ), 'update_item' => __( 'Update User Image Category' ), 'add_new_item' => __( 'Add together New User Prototype Category' ), 'new_item_name' => __( 'New User Image Name' ), 'menu_name' => __( 'User Image Categories' ), ); $image_category_args = array( 'hierarchical' => truthful, 'labels' => $image_category_labels, 'show_ui' => truthful, 'query_var' => true, 'rewrite' => assortment( 'slug' => 'user_image_category' ), ); register_taxonomy('sui_image_category', array('user_images'), $image_category_args); $default_image_cats = array('humour', 'landscapes', 'sport', 'people'); foreach($default_image_cats as $cat){ if(!term_exists($cat, 'sui_image_category')) wp_insert_term($cat, 'sui_image_category'); } }
What this code does:
- uses the WordPress init action hook to call a plugin initialization function
- registers a custom post type named user_images
- registers a custom taxonomy named user_image_category and assigns it to the user_images mail service type
- adds some default categories to the user_image_category taxonomy if they don't already exist
We volition now take a User Images menu in our admin dashboard and a fashion to administrate user images and their categories.
Pace 3 Ready Some Defaults
We'll demand to do some basic validation so allow'due south define two constants for later use:
define('MAX_UPLOAD_SIZE', 200000); define('TYPE_WHITELIST', serialize(array( 'epitome/jpeg', 'paradigm/png', 'image/gif' )));
Step 4 Define A Shortcode
We'll define a shortcode that will let us to display (and process) the user images submission class in a postal service or page:
add_shortcode('sui_form', 'sui_form_shortcode');
Security
Because our plugin accepts data from the user, we implement the following security mechanisms:
- only logged-in users have access to the image submission form
- nosotros utilise nonces to verify that the forms were generated by our plugin
- images are submitted using wp_insert_post which sanitizes the information before saving information technology to the database
- users tin only view their own images, and nonces prevent them from deleting any other user's paradigm posts
Pace five The Main Function
This is the office chosen past our shortcode. It displays and processes the image submission class and the paradigm listing/deletion form. We'll take it in bite-sized pieces and in Footstep 6 we'll look at the helper functions.
office sui_form_shortcode(){ if(!is_user_logged_in()){ return '<p>You lot need to be logged in to submit an prototype.</p>'; } global $current_user;
- check to see if the user is logged in
- grab the WordPress $current_user variable which nosotros'll need to get our user ID
if(isset( $_POST['sui_upload_image_form_submitted'] ) && wp_verify_nonce($_POST['sui_upload_image_form_submitted'], 'sui_upload_image_form') ){ $upshot = sui_parse_file_errors($_FILES['sui_image_file'], $_POST['sui_image_caption']); if($event['error']){ repeat '<p>Mistake: ' . $effect['error'] . '</p>'; }else{ $user_image_data = assortment( 'post_title' => $result['caption'], 'post_status' => 'pending', 'post_author' => $current_user->ID, 'post_type' => 'user_images' ); if($post_id = wp_insert_post($user_image_data)){ sui_process_image('sui_image_file', $post_id, $issue['caption']); wp_set_object_terms($post_id, (int)$_POST['sui_image_category'], 'sui_image_category'); } } }
- if the epitome form has been submitted, there'll be a sui_upload_image_form_submitted field which was generated by our wp_nonce_field function. We can then verify the nonce and go along to process the submitted epitome
- do some validation by passing the file input (where the uploaded prototype data is stored) and caption input data to a validation part, sui_parse_file_errors, and display whatsoever returned errors
- construct an array setting the postal service status to pending (the admin will now have to approve it for publication), setting the mail service type to user_images (our custom mail service type), and setting the author of the image post to the currently logged-in user
- if the image mail was successfully inserted, save the image in the WordPress media library (sui_process_image) and finally set the category for the image post and display a success message
if (isset( $_POST['sui_form_delete_submitted'] ) && wp_verify_nonce($_POST['sui_form_delete_submitted'], 'sui_form_delete')){ if(isset($_POST['sui_image_delete_id'])){ if($user_images_deleted = sui_delete_user_images($_POST['sui_image_delete_id'])){ echo '<p>' . $user_images_deleted . ' images(s) deleted!</p>'; } } }
- if the image delete course has been submitted, in that location'll be a sui_form_delete_submitted field which was generated past our wp_nonce_field function. We can then verify the nonce and continue to process the array of images checked for deletion
- we check that nosotros really have some images checked for deletion by testing $_POST['sui_image_delete_id']. If so, we paw them off to the sui_delete_user_images function (run across Step six)
- if images were deleted, nosotros brandish a success message
repeat sui_get_upload_image_form($sui_image_caption = $_POST['sui_image_caption'], $sui_image_category = $_POST['sui_image_category']); if($user_images_table = sui_get_user_images_table($current_user->ID)){ echo $user_images_table; }
- we output the image upload form
- finally, we output the images listing/deletion form by passing the user ID to the sui_get_user_images_table function (see Step 6)
Step half dozen Helper Functions
Here we'll look at the functions that generate the forms, add the images to the media library and the function that deletes the selected images.
part sui_get_upload_image_form($sui_image_caption = '', $sui_image_category = 0){ $out = ''; $out .= '<form id="sui_upload_image_form" method="postal service" action="" enctype="multipart/course-information">'; $out .= wp_nonce_field('sui_upload_image_form', 'sui_upload_image_form_submitted'); $out .= '<label for="sui_image_caption">Image Caption - Letters, Numbers and Spaces</label><br/>'; $out .= '<input type="text" id="sui_image_caption" name="sui_image_caption" value="' . $sui_image_caption . '"/><br/>'; $out .= '<characterization for="sui_image_category">Image Category</characterization><br/>'; $out .= sui_get_image_categories_dropdown('sui_image_category', $sui_image_category) . '<br/>'; $out .= '<label for="sui_image_file">Select Your Image - ' . MAX_UPLOAD_SIZE . ' bytes maximum</characterization><br/>'; $out .= '<input type="file" size="sixty" name="sui_image_file" id="sui_image_file"><br/>'; $out .= '<input type="submit" id="sui_submit" name="sui_submit" value="Upload Image">'; $out .= '</grade>'; return $out; }
- the function accepts 2 optional arguments for repopulating the class fields. This is a convenience for the user.
- a nonce field is output which nosotros check when the grade is submitted
- we output a dropdown for the image categories by calling sui_get_image_categories_dropdown (see next function)
function sui_get_image_categories_dropdown($taxonomy, $selected){ return wp_dropdown_categories(assortment('taxonomy' => $taxonomy, 'name' => 'sui_image_category', 'selected' => $selected, 'hide_empty' => 0, 'echo' => 0)); }
- the function accepts ii arguments including the chemical element ID of the currently selected category
- nosotros utilise the WordPress wp_dropdown_categories function to create a dropdown that lists the user paradigm categories from the user_image_category taxonomy (our custom taxonomy)
part sui_get_user_images_table($user_id){ $args = array( 'author' => $user_id, 'post_type' => 'user_images', 'post_status' => 'pending' ); $user_images = new WP_Query($args); if(!$user_images->post_count) return 0; $out = ''; $out .= '<p>Your unpublished images - Click to see full size</p>'; $out .= '<form method="post" action="">'; $out .= wp_nonce_field('sui_form_delete', 'sui_form_delete_submitted'); $out .= '<table id="user_images">'; $out .= '<thead><thursday>Image</th><th>Explanation</thursday><th>Category</th><thursday>Delete</th></thead>'; foreach($user_images->posts as $user_image){ $user_image_cats = get_the_terms($user_image->ID, 'sui_image_category'); foreach($user_image_cats as $cat){ $user_image_cat = $cat->name; } $post_thumbnail_id = get_post_thumbnail_id($user_image->ID); $out .= wp_nonce_field('sui_image_delete_' . $user_image->ID, 'sui_image_delete_id_' . $user_image->ID, imitation); $out .= '<tr>'; $out .= '<td>' . wp_get_attachment_link($post_thumbnail_id, 'thumbnail') . '</td>'; $out .= '<td>' . $user_image->post_title . '</td>'; $out .= '<td>' . $user_image_cat . '</td>'; $out .= '<td><input type="checkbox" proper noun="sui_image_delete_id[]" value="' . $user_image->ID . '" /></td>'; $out .= '</tr>'; } $out .= '</table>'; $out .= '<input type="submit" name="sui_delete" value="Delete Selected Images" />'; $out .= '</form>'; return $out; }
- accept the user ID because we need to become a listing of user images for the current user just
- create $args to specify our user, the mail service type of user_images and user images that are awaiting (not even so published by the admin)
- execute a custom query using WP_Query
- return false if our query returns no user images
- start a form and generate a nonce for the class
- loop through the images posts making sure we also grab the category of the paradigm post
- generate a nonce for the prototype delete checkbox, assigning a unique proper name for the nonce past concatenating the user paradigm postal service ID
- output a table row containing the prototype post info as well as a delete checkbox
Why add a nonce for each epitome post?
Forms can be manipulated in the browser to post back unexpected data. In our case, each delete checkbox is assigned the value of a post. Merely what if a malicious user contradistinct that value and caused our delete function to remove a postal service that was non actually listed?
Ane way to avoid this, is to employ nonces for each row of postal service information, ensuring that the nonces are uniquely named with the post value to be deleted. We then verify the nonce upon form submission to make sure information technology'southward a genuine render value.
function sui_delete_user_images($images_to_delete){ $images_deleted = 0; foreach($images_to_delete as $user_image){ if (isset($_POST['sui_image_delete_id_' . $user_image]) && wp_verify_nonce($_POST['sui_image_delete_id_' . $user_image], 'sui_image_delete_' . $user_image)){ if($post_thumbnail_id = get_post_thumbnail_id($user_image)){ wp_delete_attachment($post_thumbnail_id); } wp_trash_post($user_image); $images_deleted ++; } } return $images_deleted; }
- the function accepts an array of epitome post IDs to delete
- each prototype postal service ID is checked to come across if a nonce was generated for it
- if the nonce verifies, we delete the image attachment that exists in the media library by passing the id of the prototype post thumbnail to the WordPress function wp_delete_attachment
- we also trash the image mail service using the WordPress function wp_trash_post
But doesn't the thumbnail attachment get deleted when the post is trashed?
No and that's considering WordPress stores attachments every bit regular posts in the posts database table. Take a expect yourself: all attachments are stored in the posts table with a post_type of attachment. Simply deleting a mail of blazon user_images doesn't delete its thumbnail attachment. It remains in the media library for time to come utilise unless we specifically delete it with wp_delete_attachment. For our purposes, I thought it was all-time to remove the attachment when the user's post was deleted.
Footstep seven The Image Handling Functions
Let's remind ourselves of what the output of an html file input looks like when information technology posts an epitome to your script:
Assortment ( [name] => ref_blind.jpg [type] => image/jpeg [tmp_name] => /tmp/php79xI4e [error] => 0 [size] => 106290 )
Nosotros pass that assortment to the sui_process_image function along with the id of the saved user image post and the santized image explanation.
role sui_process_image($file, $post_id, $explanation){ require_once(ABSPATH . "wp-admin" . '/includes/prototype.php'); require_once(ABSPATH . "wp-admin" . '/includes/file.php'); require_once(ABSPATH . "wp-admin" . '/includes/media.php'); $attachment_id = media_handle_upload($file, $post_id); update_post_meta($post_id, '_thumbnail_id', $attachment_id); $attachment_data = array( 'ID' => $attachment_id, 'post_excerpt' => $caption ); wp_update_post($attachment_data); return $attachment_id; }
- we need to include the WordPress admin scripts that handle image uploads behind the scenes
- we phone call the media_handle_upload part (which is role of media.php), passing it the uploaded file array and the postal service id
- now we take an attachment id which we can use with update_post_meta to assign the zipper to the post as its thumbnail. Note: "_thumbnail_id" refers to the internal thumbnail (Featured Image) meta field. Internal Wordpress fields brainstorm with an underscore.
- we next employ the attachment id to update the caption of the zipper using the wp_update_post part
Considering attachments are only regular posts, if we update the post_excerpt field for the attachment, nosotros are actually updating the attachment'south caption field as seen in the media library edit screen.
The validation function
Nosotros also validate the file array and the user-provided paradigm caption with the sui_parse_file_errors function.
function sui_parse_file_errors($file = '', $image_caption){ $result = array(); $event['error'] = 0; if($file['fault']){ $outcome['error'] = "No file uploaded or at that place was an upload mistake!"; return $result; } $image_caption = trim(preg_replace('/[^a-zA-Z0-9\due south]+/', ' ', $image_caption)); if($image_caption == ''){ $consequence['fault'] = "Your caption may simply contain letters, numbers and spaces!"; return $upshot; } $result['caption'] = $image_caption; $image_data = getimagesize($file['tmp_name']); if(!in_array($image_data['mime'], unserialize(TYPE_WHITELIST))){ $result['error'] = 'Your image must be a jpeg, png or gif!'; }elseif(($file['size'] > MAX_UPLOAD_SIZE)){ $result['fault'] = 'Your prototype was ' . $file['size'] . ' bytes! Information technology must not exceed ' . MAX_UPLOAD_SIZE . ' bytes.'; } return $result; }
- cheque the mistake element of the files array for an html upload error, if plant return a result array with error
- run some regex on the epitome caption to remove everything but alphanumeric data and spaces, replacing with spaces for readability
- if we end upwardly with an empty caption later on sanitizing information technology, we render an fault
- bank check the internal image type (don't trust the file extension) using the PHP getimagesize function against the TYPE_WHITELIST constant
- cheque the paradigm size against the MAX_UPLOAD_SIZE constant
Step 8 Some Styling
Merely drop this way info into the mode.css file in your theme folder:
#sui_upload_image_form #sui_image_caption{ width:500px; } #user_images{ font-size:12px; } #user_images th{ text-align:left; } #user_images td{ vertical-align:middle; } #user_images td input{ margin:0px; }
Step ix Attempt It Out
Activate the plugin, pop the shortcode onto a page, log into your site, and test information technology out. When you upload an epitome you'll run across a new post announced under the User Images admin card. It will exist pending publication. Yous'll as well see a new epitome listed in your media library, fastened to your new post and with the caption as provided.
The total plugin code source and a demo site link is listed at the top of this tutorial.
The source folder also contains a Wordpress page template with a custom loop that displays published images for all users.
Final Thoughts
Y'all may wish to place more than stringent validation on your image uploads. Recollect, you're accepting data from users who may accidentally or maliciously upload inappropriate files. Checking the file blazon and size is a skillful offset.
As well, we created the zipper caption by updating the zipper's post_excerpt field. You tin likewise set an attachment description by using the zipper's post_content field.
Did you find this postal service useful?
Source: https://code.tutsplus.com/articles/allow-users-to-submit-images-to-your-wordpress-site--wp-22601
Post a Comment for "How to Allow Users to Upload Photos to Wordpress"