Avatar Manager for WordPress is a sweet and simple plugin for storing avatars locally and more. Easily.
Enhance your WordPress website by letting your users choose between using Gravatar or a self-hosted avatar image right from their profile screen. Improved workflow, on-demand image generation and custom user permissions under a native interface. Say hello to the Avatar Manager plugin.
A Quick Recap
In the first part of our tutorial, we reviewed:
- what is a WordPress plugin;
- how to create a basic WordPress plugin, choose an appropriate license and format for the version number;
- what are action and filter hooks and how to use them to create our plugin;
- how to add new settings to existing settings screens;
- how to make a plugin more flexible by using custom options.
Today, we'll take things further and wrap up our plugin: we'll handle avatar uploads and on-demand image generation, internationalize our plugin and much more.
Step 1. Resizing an Avatar Image
Let's start by writing the following function:
/** * Generates a resized copy of the specified avatar image. * * @uses wp_upload_dir() For retrieving path information on the currently * configured uploads directory. * @uses wp_basename() For i18n friendly version of basename(). * @uses wp_get_image_editor() For retrieving a WP_Image_Editor instance and * loading a file into it. * @uses is_wp_error() For checking whether the passed variable is a WordPress * Error. * @uses do_action() For calling the functions added to an action hook. * * @since Avatar Manager 1.0.0 * * @param string $url URL of the avatar image to resize. * @param int $size Size of the new avatar image. * @return array Array with the URL of the new avatar image. */ function avatar_manager_avatar_resize( $url, $size ) { // Retrieves path information on the currently configured uploads directory. $upload_dir = wp_upload_dir(); $filename = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $url ); $pathinfo = pathinfo( $filename ); $dirname = $pathinfo['dirname']; $extension = $pathinfo['extension']; // i18n friendly version of basename(). $basename = wp_basename( $filename, '.' . $extension ); $suffix = $size . 'x' . $size; $dest_path = $dirname . '/' . $basename . '-' . $suffix . '.' . $extension; $avatar = array(); if ( file_exists( $dest_path ) ) { $avatar['url'] = str_replace( $upload_dir['basedir'], $upload_dir['baseurl'], $dest_path ); $avatar['skip'] = true; } else { // Retrieves a WP_Image_Editor instance and loads a file into it. $image = wp_get_image_editor( $filename ); if ( ! is_wp_error( $image ) ) { // Resizes current image. $image->resize( $size, $size, true ); // Saves current image to file. $image->save( $dest_path ); $avatar['url'] = str_replace( $upload_dir['basedir'], $upload_dir['baseurl'], $dest_path ); $avatar['skip'] = false; } } // Calls the functions added to avatar_manager_avatar_resize action hook. do_action( 'avatar_manager_avatar_resize', $url, $size ); return $avatar; }
Summary
- The
avatar_manager_avatar_resize()
function generates a resized copy of the specified avatar image. - The
wp_upload_dir()
call returns an array containing path information on the currently configured uploads directory. - The
str_replace()
function replaces all occurrences of the search string with the replacement string. - The
pathinfo()
function returns information about a file path. - The
wp_basename()
function is the i18n friendly version ofbasename()
which returns the trailing name component of a path. - The
file_exists()
function checks whether a file or directory exists. - The
skip
flag is set totrue
if the destination image file already exists, else a new image is generated. - The
wp_get_image_editor()
function returns aWP_Image_Editor
instance and loads a file into it. With that we can manipulate the image by calling methods on it. - The
is_wp_error()
function checks whether the passed variable is a WordPress error. - Then, we resize and save the image by calling the
resize()
andsave()
methods of the$image
object. - The
do_action()
executes a hook created byadd_action()
; this allows themes and plugins to hook to theavatar_manager_avatar_resize
action which is triggered after resizing an avatar image.
Step 2. Deleting an Avatar Image
Before taking care of profile updates, we need to define one more function:
/** * Deletes an avatar image based on attachment ID. * * @uses get_post_meta() For retrieving attachment meta fields. * @uses wp_upload_dir() For retrieving path information on the currently * configured uploads directory. * @uses delete_post_meta() For deleting attachment meta fields. * @uses get_users() For retrieving an array of users. * @uses delete_user_meta() For deleting user meta fields. * @uses do_action() For calling the functions added to an action hook. * * @since Avatar Manager 1.0.0 * * @param int $attachment_id An attachment ID */ function avatar_manager_delete_avatar( $attachment_id ) { // Retrieves attachment meta field based on attachment ID. $is_custom_avatar = get_post_meta( $attachment_id, '_avatar_manager_is_custom_avatar', true ); if ( ! $is_custom_avatar ) return; // Retrieves path information on the currently configured uploads directory. $upload_dir = wp_upload_dir(); // Retrieves attachment meta field based on attachment ID. $custom_avatar = get_post_meta( $attachment_id, '_avatar_manager_custom_avatar', true ); if ( is_array( $custom_avatar ) ) { foreach ( $custom_avatar as $file ) { if ( ! $file['skip'] ) { $file = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $file['url'] ); @unlink( $file ); } } } // Deletes attachment meta fields based on attachment ID. delete_post_meta( $attachment_id, '_avatar_manager_custom_avatar' ); delete_post_meta( $attachment_id, '_avatar_manager_custom_avatar_rating' ); delete_post_meta( $attachment_id, '_avatar_manager_is_custom_avatar' ); // An associative array with criteria to match. $args = array( 'meta_key' => 'avatar_manager_custom_avatar', 'meta_value' => $attachment_id ); // Retrieves an array of users matching the criteria given in $args. $users = get_users( $args ); foreach ( $users as $user ) { // Deletes user meta fields based on user ID. delete_user_meta( $user->ID, 'avatar_manager_avatar_type' ); delete_user_meta( $user->ID, 'avatar_manager_custom_avatar' ); } // Calls the functions added to avatar_manager_delete_avatar action hook. do_action( 'avatar_manager_delete_avatar', $attachment_id ); } add_action( 'delete_attachment', 'avatar_manager_delete_avatar' );
Summary
- The
delete_attachment
action hook is called when an attachment is deleted bywp_delete_attachment()
. - The
get_post_meta()
returns the values of the custom fields with the specified key from the specified post. First, we test if the attachment with the specified ID is an avatar image. - The
is_array()
call finds whether a variable is an array. - Then, we use the
unlink()
function to delete the avatar image including its resized copies, but skipping those with theskip
flag set totrue
. - The
delete_post_meta()
function deletes all custom fields with the specified key from the specified post. - The
get_users()
function retrieves an array of users matching the criteria given in$args
. - The
delete_user_meta()
function removes metadata matching criteria from a user. - Lastly, we execute the
avatar_manager_delete_avatar
action hook.
Step 3. Updating a User Profile
When updating a user profile, we need not only to save the options changed by the user but to handle avatar uploads and removals too. Let's do it:
/** * Updates user profile based on user ID. * * @uses avatar_manager_get_options() For retrieving plugin options. * @uses sanitize_text_field() For sanitizing a string from user input or from * the database. * @uses update_user_meta() For updating user meta fields. * @uses get_user_meta() For retrieving user meta fields. * @uses update_post_meta() For updating attachment meta fields. * @uses wp_handle_upload() For handling PHP uploads in WordPress. * @uses wp_die() For killing WordPress execution and displaying HTML error * message. * @uses __() For retrieving the translated string from the translate(). * @uses avatar_manager_delete_avatar() For deleting an avatar image. * @uses wp_insert_attachment() For inserting an attachment into the media * library. * @uses wp_generate_attachment_metadata() For generating metadata for an * attachment. * @uses wp_update_attachment_metadata() For updating metadata for an * attachment. * @uses avatar_manager_avatar_resize() For generating a resized copy of the * specified avatar image. * @uses avatar_manager_delete_avatar() For deleting an avatar image based on * attachment ID. * @uses get_edit_user_link() For getting the link to the users edit profile * page in the WordPress admin. * @uses add_query_arg() For retrieving a modified URL (with) query string. * @uses wp_redirect() For redirecting the user to a specified absolute URI. * * @since Avatar Manager 1.0.0 * * @param int $user_id User to update. */ function avatar_manager_edit_user_profile_update( $user_id ) { // Retrieves plugin options. $options = avatar_manager_get_options(); // Sanitizes the string from user input. $avatar_type = isset( $_POST['avatar_manager_avatar_type'] ) ? sanitize_text_field( $_POST['avatar_manager_avatar_type'] ) : 'gravatar'; // Updates user meta field based on user ID. update_user_meta( $user_id, 'avatar_manager_avatar_type', $avatar_type ); // Retrieves user meta field based on user ID. $custom_avatar = get_user_meta( $user_id, 'avatar_manager_custom_avatar', true ); if ( ! empty( $custom_avatar ) ) { // Sanitizes the string from user input. $custom_avatar_rating = isset( $_POST['avatar_manager_custom_avatar_rating'] ) ? sanitize_text_field( $_POST['avatar_manager_custom_avatar_rating'] ) : 'G'; // Updates attachment meta field based on attachment ID. update_post_meta( $custom_avatar, '_avatar_manager_custom_avatar_rating', $custom_avatar_rating ); } ... } add_action( 'edit_user_profile_update', 'avatar_manager_edit_user_profile_update' ); add_action( 'personal_options_update', 'avatar_manager_edit_user_profile_update' );
Summary
- The
edit_user_profile_update
andpersonal_options_update
actions are generally used to save custom fields that have been added to the WordPress profile page. - The
sanitize_text_field()
function sanitizes a string from user input or from the database. - The
update_user_meta()
function updates user meta field based on user ID, whileget_user_meta()
retrieves a single meta field or all fields of user meta data for the given user. - The
update_post_meta()
function updates the value of an existing meta key (custom field) for the specified post.
Handling Avatar Uploads
To handle avatar uploads, write the following code:
if ( isset( $_POST['avatar-manager-upload-avatar'] ) && $_POST['avatar-manager-upload-avatar'] ) { if ( ! function_exists( 'wp_handle_upload' ) ) require_once( ABSPATH . 'wp-admin/includes/file.php' ); // An associative array with allowed MIME types. $mimes = array( 'bmp' => 'image/bmp', 'gif' => 'image/gif', 'jpe' => 'image/jpeg', 'jpeg' => 'image/jpeg', 'jpg' => 'image/jpeg', 'png' => 'image/png', 'tif' => 'image/tiff', 'tiff' => 'image/tiff' ); // An associative array to override default variables. $overrides = array( 'mimes' => $mimes, 'test_form' => false ); // Handles PHP uploads in WordPress. $avatar = wp_handle_upload( $_FILES['avatar_manager_import'], $overrides ); if ( isset( $avatar['error'] ) ) // Kills WordPress execution and displays HTML error message. wp_die( $avatar['error'], __( 'Image Upload Error', 'avatar-manager' ) ); if ( ! empty( $custom_avatar ) ) // Deletes users old avatar image. avatar_manager_delete_avatar( $custom_avatar ); // An associative array about the attachment. $attachment = array( 'guid' => $avatar['url'], 'post_content' => $avatar['url'], 'post_mime_type' => $avatar['type'], 'post_title' => basename( $avatar['file'] ) ); // Inserts the attachment into the media library. $attachment_id = wp_insert_attachment( $attachment, $avatar['file'] ); // Generates metadata for the attachment. $attachment_metadata = wp_generate_attachment_metadata( $attachment_id, $avatar['file'] ); // Updates metadata for the attachment. wp_update_attachment_metadata( $attachment_id, $attachment_metadata ); $custom_avatar = array(); // Generates a resized copy of the avatar image. $custom_avatar[ $options['default_size'] ] = avatar_manager_avatar_resize( $avatar['url'], $options['default_size'] ); // Updates attachment meta fields based on attachment ID. update_post_meta( $attachment_id, '_avatar_manager_custom_avatar', $custom_avatar ); update_post_meta( $attachment_id, '_avatar_manager_custom_avatar_rating', 'G' ); update_post_meta( $attachment_id, '_avatar_manager_is_custom_avatar', true ); // Updates user meta fields based on user ID. update_user_meta( $user_id, 'avatar_manager_avatar_type', 'custom' ); update_user_meta( $user_id, 'avatar_manager_custom_avatar', $attachment_id ); }
Summary
- The
function_exists()
returnstrue
if the given function has been defined, then therequire_once()
statement checks if the specified file has already been included, and if so, doesn't include it again. - The
wp_handle_upload()
function handles PHP uploads in WordPress, sanitizing file names, checking extensions for mime type, and moving the file to the appropriate directory within the uploads directory. - Before adding the new avatar image, we call the
avatar_manager_delete_avatar()
function to delete the old avatar, if any is set. - The
wp_insert_attachment()
function inserts an attachment into the media library. - The
wp_generate_attachment_metadata()
function generates metadata for an image attachment; it also creates a thumbnail and other intermediate sizes of the image attachment based on the sizes defined on theSettings Media Screen
. - The
wp_update_attachment_metadata()
function updates metadata for an attachment. - Next, we call the
avatar_manager_avatar_resize()
function to generate a copy of the avatar image at default size. - Lastly, we update the metadata for the attachment and for the user currently being edited.
Removing an Avatar Image
Now, it's time to make the plugin to actually delete an avatar image when requested:
if ( isset( $_GET['avatar_manager_action'] ) && $_GET['avatar_manager_action'] ) { global $wp_http_referer; $action = $_GET['avatar_manager_action']; switch ( $action ) { case 'remove-avatar': // Deletes avatar image based on attachment ID. avatar_manager_delete_avatar( $_GET['avatar_manager_custom_avatar'] ); break; } // Gets the link to the users edit profile page in the WordPress admin. $edit_user_link = get_edit_user_link( $user_id ); // Retrieves a modified URL (with) query string. $redirect = add_query_arg( 'updated', true, $edit_user_link ); if ( $wp_http_referer ) // Retrieves a modified URL (with) query string. $redirect = add_query_arg( 'wp_http_referer', urlencode( $wp_http_referer ), $redirect ); // Redirects the user to a specified absolute URI. wp_redirect( $redirect ); exit; }
Summary
- If the value of the requested action is
remove-avatar
we call theavatar_manager_delete_avatar()
to delete the specified avatar image. - The
get_edit_user_link()
function gets the link to the users edit profile page in the WordPress admin. - The
urlencode()
function encodes a string to be used in a query part of a URL. - At the end of the function, we call the
wp_redirect()
function to redirect the user back to the updated user profile. - The
exit
call terminates the execution of the script; it's a language construct and it can be called without parentheses if nostatus
is passed.
Step 4. Retrieving a Custom Avatar Image
Next, we're going to write a helper function for retrieving a custom avatar image:
/** * Returns user custom avatar based on user ID. * * @uses get_option() For getting values for a named option. * @uses avatar_manager_get_options() For retrieving plugin options. * @uses get_userdata() For retrieving user data by user ID. * @uses is_ssl() For checking if SSL is being used. * @uses add_query_arg() For retrieving a modified URL (with) query string. * @uses esc_attr() For escaping HTML attributes. * @uses get_user_meta() For retrieving user meta fields. * @uses get_post_meta() For retrieving attachment meta fields. * @uses wp_get_attachment_image_src() For retrieving an array with the image * attributes "url", "width" and "height", of an image attachment file. * @uses avatar_manager_avatar_resize() For generating a resized copy of the * specified avatar image. * @uses update_post_meta() For updating attachment meta fields. * @uses apply_filters() For calling the functions added to a filter hook. * * @since Avatar Manager 1.0.0 * * @param int $user_id User to update. * @param int $size Size of the avatar image * @param string $default URL to a default image to use if no avatar is * available. * @param string $alt Alternative text to use in image tag. Defaults to blank. * @return string <img> tag for the user's avatar. */ function avatar_manager_get_custom_avatar( $user_id, $size = '', $default = '', $alt = false ) { // Returns if showing avatars is not enabled. if ( ! get_option( 'show_avatars' ) ) return false; // Retrieves plugin options. $options = avatar_manager_get_options(); if ( empty( $size ) || ! is_numeric( $size ) ) { $size = $options['avatar-manager-default-size']; } else { $size = absint( $size ); if ( $size < 1 ) $size = 1; elseif ( $size > 512 ) $size = 512; } // Retrieves user data by user ID. $user = get_userdata( $user_id ); // Returns if no user data was retrieved. if ( empty( $user ) ) return false; $email = $user->user_email; if ( empty( $default ) ) { // Retrieves values for the named option. $avatar_default = get_option( 'avatar_default' ); if ( empty( $avatar_default ) ) $default = 'mystery'; else $default = $avatar_default; } $email_hash = md5( strtolower( trim( $email ) ) ); if ( is_ssl() ) $host = 'https://secure.gravatar.com'; else $host = sprintf( 'http://%d.gravatar.com', ( hexdec( $email_hash[0] ) % 2 ) ); if ( $default == 'mystery' ) $default = $host . '/avatar/ad516503a11cd5ca435acc9bb6523536?s=' . $size; elseif ( $default == 'gravatar_default' ) $default = ''; elseif ( strpos( $default, 'http://' ) === 0 ) // Retrieves a modified URL (with) query string. $default = add_query_arg( 's', $size, $default ); if ( $alt === false ) $alt = ''; else // Escapes HTML attributes. $alt = esc_attr( $alt ); // Retrieves values for the named option. $avatar_rating = get_option( 'avatar_rating' ); // Retrieves user meta field based on user ID. $custom_avatar = get_user_meta( $user_id, 'avatar_manager_custom_avatar', true ); // Returns if no attachment ID was retrieved. if ( empty( $custom_avatar ) ) return false; // Retrieves attachment meta field based on attachment ID. $custom_avatar_rating = get_post_meta( $custom_avatar, '_avatar_manager_custom_avatar_rating', true ); $ratings['G'] = 1; $ratings['PG'] = 2; $ratings['R'] = 3; $ratings['X'] = 4; if ( $ratings[ $custom_avatar_rating ] <= $ratings[ $avatar_rating ] ) { // Retrieves attachment meta field based on attachment ID. $avatar = get_post_meta( $custom_avatar, '_avatar_manager_custom_avatar', true ); if ( empty( $avatar[ $size ] ) ) { // Retrieves an array with the image attributes "url", "width" // and "height", of the image attachment file. $url = wp_get_attachment_image_src( $custom_avatar, 'full' ); // Generates a resized copy of the avatar image. $avatar[ $size ] = avatar_manager_avatar_resize( $url[0], $size ); // Updates attachment meta field based on attachment ID. update_post_meta( $custom_avatar, '_avatar_manager_custom_avatar', $avatar ); } $src = $avatar[ $size ]['url']; $avatar = '<img alt="' . $alt . '" class="avatar avatar-' . $size . ' photo avatar-default" height="' . $size . '" src="' . $src . '" width="' . $size . '">'; } else { $src = $host . '/avatar/'; $src .= $email_hash; $src .= '?s=' . $size; $src .= '&d=' . urlencode( $default ); $src .= '&forcedefault=1'; $avatar = '<img alt="' . $alt . '" class="avatar avatar-' . $size . ' photo avatar-default" height="' . $size . '" src="' . $src . '" width="' . $size . '">'; } // Calls the functions added to avatar_manager_get_custom_avatar // filter hook. return apply_filters( 'avatar_manager_get_custom_avatar', $avatar, $user_id, $size, $default, $alt ); }
Summary
- The
avatar_manager_get_custom_avatar
function returns a custom avatar image based on user ID orfalse
if showing avatars is not enabled. The function retrieves plugin options, sanitizes the$size
parameter and escapes HTML attributes from$alt
variable. - Then, it retrieves a default image to use instead of the avatar image if the avatar rating doesn't match. A resized copy of the avatar image is generated on-demand if the requested size doesn't match an existing image file.
- The
get_userdata()
function returns aWP_User
object with the information pertaining to the user whose ID is passed to it. - The
md5()
function returns the MD5 hash for the provided string. - The
strtolower()
function returns the provided string but with all alphabetic characters converted to lowercase. - The
is_ssl()
call checks if SSL is being used. - The
sprintf()
function returns a formatted string. - The
hexdec()
function returns the decimal equivalent of the specified hexadecimal number. - The call
strpos()
finds the numeric position of the first occurrence ofneedle
in thehaystack
string. - The
wp_get_attachment_image_src()
function returns an array with the image attributesurl
,width
andheight
, of an image attachment file. - Lastly, we use the
apply_filters()
function to call the functions added to theavatar_manager_get_custom_avatar
filter hook.
Step 5. Retrieving an Avatar Image
Basically, the next function is the main function of our plugin:
/** * Returns the avatar for a user who provided a user ID or email address. * * @uses get_option() For getting values for a named option. * @uses avatar_manager_get_options() For retrieving plugin options. * @uses get_userdata() For retrieving user data by user ID. * @uses avatar_manager_get_custom_avatar() For retrieving user custom avatar * based on user ID. * @uses apply_filters() For calling the functions added to a filter hook. * * @since Avatar Manager 1.0.0 * * @param int|string|object $id_or_email A user ID, email address, or comment * object. * @param int $size Size of the avatar image * @param string $default URL to a default image to use if no avatar is * available. * @param string $alt Alternative text to use in image tag. Defaults to blank. * @return string <img> tag for the user's avatar. */ function avatar_manager_get_avatar( $avatar = '', $id_or_email, $size = '', $default = '', $alt = false ) { // Returns if showing avatars is not enabled. if ( ! get_option( 'show_avatars' ) ) return false; // Retrieves plugin options. $options = avatar_manager_get_options(); if ( empty( $size ) || ! is_numeric( $size ) ) { $size = $options['avatar-manager-default-size']; } else { $size = absint( $size ); if ( $size < 1 ) $size = 1; elseif ( $size > 512 ) $size = 512; } $email = ''; if ( is_numeric( $id_or_email ) ) { $id = (int) $id_or_email; // Retrieves user data by user ID. $user = get_userdata( $id ); if ( $user ) $email = $user->user_email; } elseif ( is_object( $id_or_email ) ) { if ( ! empty( $id_or_email->user_id ) ) { $id = (int) $id_or_email->user_id; // Retrieves user data by user ID. $user = get_userdata( $id ); if ( $user ) $email = $user->user_email; } elseif ( ! empty( $id_or_email->comment_author_email ) ) { $email = $id_or_email->comment_author_email; } } else { $email = $id_or_email; if ( $id = email_exists( $email ) ) // Retrieves user data by user ID. $user = get_userdata( $id ); } if ( isset( $user ) ) $avatar_type = $user->avatar_manager_avatar_type; else return $avatar; if ( $avatar_type == 'custom' ) // Retrieves user custom avatar based on user ID. $avatar = avatar_manager_get_custom_avatar( $user->ID, $size, $default, $alt ); // Calls the functions added to avatar_manager_get_avatar filter hook. return apply_filters( 'avatar_manager_get_avatar', $avatar, $id_or_email, $size, $default, $alt ); } add_filter( 'get_avatar', 'avatar_manager_get_avatar', 10, 5 );
Summary
- The
avatar_manager_get_avatar()
function returns the avatar for a user who provided a user ID or email address, or false if showing avatars is not enabled. - We use the
get_avatar
filter to change the output of theget_avatar()
function. Our function retrieves plugin options, sanitizes the$size
parameter and finds the ID of the specified user. - Then, it returns the result of the
avatar_manager_get_custom_avatar()
function call, or the unmodified output of theget_avatar()
if the user doesn't use a custom avatar. - The
is_object()
call finds whether a variable is an object. - The
email_exists()
function checks whether or not a given email address has already been registered to a username, and returns that users ID, or false if none exists.
To test the result, go to the Users -> Your Profile Screen.
The Avatar Manager plugin options under the User Your Profile Screen
Browse for an image an upload it. Now, you should be able to choose between using Gravatar or the custom avatar image you just uploaded.
Step 6. Removing Unnecessary Filter Hooks
If you go to the Settings Discussion Screen you'll notice that the avatars from the Default Avatar setting are replaced with your custom avatar. To fix this issue, we'll restore the default avatars by removing our custom function when it isn't needed with the help of the avatar_defaults
filter hook. To do so, add the following code:
/** * Prevents custom avatars from being applied to the Default Avatar setting. * * @uses remove_filter() For removing a function attached to a specified action * hook. * * @since Avatar Manager 1.0.0 * * @param array $avatar_defaults An associative array with default avatars. * @return array An associative array with default avatars. */ function avatar_manager_avatar_defaults( $avatar_defaults ) { // Removes the avatar_manager_get_avatar function attached to get_avatar // action hook. remove_filter( 'get_avatar', 'avatar_manager_get_avatar' ); return $avatar_defaults; } add_filter( 'avatar_defaults', 'avatar_manager_avatar_defaults', 10, 1 );
To prevent custom avatars from being applied to the Default Avatar setting, we call the remove_filter()
function. It removes a function attached to a specified filter hook. This method can be used to remove default functions attached to a specific filter hook and possibly replace them with a substitute.
Step 7. Displaying Custom Media States
The Media Library Screen allows you to edit, view, and delete images, video, recordings, and files previously uploaded to your blog. To identify an attachment being used as an avatar image, we're going to display a custom media state for it:
/** * Displays media states for avatar images. * * @uses get_post_meta() For retrieving attachment meta fields. * @uses __() For retrieving the translated string from the translate(). * @uses apply_filters() For calling the functions added to a filter hook. * * @since Avatar Manager 1.0.0 * * @param array $media_states An associative array with media states. * @return array An associative array with media states. */ function avatar_manager_display_media_states( $media_states ) { global $post; // Retrieves attachment meta field based on attachment ID. $meta_avatar = get_post_meta( $post->ID, '_avatar_manager_is_custom_avatar', true ); if ( ! empty( $meta_avatar ) ) $media_states[] = __( 'Avatar Image', 'avatar-manager' ); // Calls the functions added to avatar_manager_display_media_states filter // hook. return apply_filters( 'avatar_manager_display_media_states', $media_states ); } add_filter( 'display_media_states', 'avatar_manager_display_media_states', 10, 1 );
The display_media_states
filter is used to display custom media states for attachmets that have been added to the Media Library. We use the $post
global variable to grab the ID of the current attachment. If the _avatar_manager_is_custom_avatar
custom field isn't empty, the attachment is an avatar image so we add a custom media state for it.
If you don't have any custom avatar image set up, upload one and go to the Media Library Screen.
The Avatar Manager plugin media states under the Media Library Screen
Notice that each attachment being used as a custom avatar image does have the Avatar Image string appended next to its filename.
Step 8. Adding the Uninstaller
In order to handle the uninstall process, a plugin should create a file named uninstall.php in the base plugin directory rather than using register_uninstall_hook()
. This file will be called, if it exists, during the uninstall process bypassing the uninstall hook. To do so, open avatar-manager/uninstall.php and add the following code:
<?php /** * @package Avatar_Manager * @subpackage Uninstaller */ // Exits if uninstall is not called from WordPress. if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) exit; if ( ! function_exists( 'avatar_manager_delete_avatar' ) ) include_once( 'avatar-manager.php' ); // Deletes plugin options. delete_option( 'avatar_manager' ); // An associative array with criteria to match. $args = array( 'meta_key' => 'avatar_manager_custom_avatar' ); // Retrieves an array of users matching the criteria given in $args. $users = get_users( $args ); foreach ( $users as $user ) { // Deletes avatar image based on attachment ID. avatar_manager_delete_avatar( $user->avatar_manager_custom_avatar ); } ?>
When using uninstall.php the plugin should always check for the WP_UNINSTALL_PLUGIN
constant, before executing. The WP_UNINSTALL_PLUGIN
constant is defined by WordPress at runtime during a plugin uninstall and it will not be present if uninstall.php is requested directly. The defined()
checks whether a given named constant exists. The include_once
statement includes and evaluates the specified file during the execution of the script; if the code from a file has already been included, it will not be included again. The delete_option()
function removes a named option from the options database table.
Step 9. Internationalizing and Translating the Plugin
Once you have the programming for your plugin done, another consideration is internationalization. Internationalization, often abbreviated as i18n, is the process of setting up software so that it can be localized; localization, or l10n, is the process of translating text displayed by the software into different languages. WordPress uses the gettext libraries and tools for i18n.
It is highly recommended that you internationalize your plugin, so that users from different countries can localize it.
Translatable Strings
In order to make a string translatable, you have to just wrap the original string in a __()
function call. If your code should echo the string to the browser, use the _e()
function instead. As you might have noticed, we've already done that in our plugin.
Text Domains
A text domain is a unique identifier, which makes sure WordPress can distinguish between all loaded translations. Using the basename of your plugin is always a good choice. You can load the plugin's translated strings by calling the load_plugin_textdomain()
function, which we've already done in the first part of our tutorial.
PO Files
Now, we need to make a .po file for translators. To do this, we'll use the Poedit translation software. Once you've downloaded it, click File -> New Catalog... to setup a new catalog. A new window should open up. Go to the Project info tab and enter Avatar Manager as the project name.
Poedit's Project info tab under the Settings window
On the Paths tab, let’s leave the base path as . which refers to the directory in which the catalog is.
Poedit's Paths tab under the Settings window
Next, go to the Keywords tab. Remove all the items there, and add in these keywords: __, _e, _n and _x.
Poedit's Keywords tab under the Settings window
Press OK and save the file as avatar-manager/languages/avatar-manager-default.po. Now, the file is ready for translation.
Poedit's main window
Translate all the strings you want and then save the file as avatar-manager/languages/avatar-manager-{locale}.po. The locale is the language code and/or country code you defined in the constant WPLANG
in the file wp-config.php.
MO Files
A .mo file is a binary file which contains all the original strings and their translations in a format suitable for fast translation extraction. The conversion is done automatically if you go to Edit -> Preferences -> Editor and check Automatically compile .mo file on save.
Step 10. Releasing and Promoting a Plugin
This section goes through the steps for taking a plugin that you've created and getting it distributed widely.
Submitting to the WordPress Plugin Directory
The fastest, easiest and best way to get your plugin out there is to upload your plugin to the WordPress Plugin Directory. For more details about submitting your plugin see the about page or skip straight to the plugin submission page
.
Promoting and Documenting Your Plugin
To submit and promote your plugin to the WordPress Community, first create a page for the plugin on your site with complete and well written instructions. Include a link to this explanation page in the plugin's header, so people can easily check for updates and more information and help.
If you choose to submit your plugin to the WordPress Plugin Directory, also make this information as clear as possible so they can categorize and help others understand the usage of your plugin. You also need to create a readme.txt file in a standard format, and include it with your plugin.
Conclusion
This closes our tutorial; now, we have a fully working plugin and learned some practical tips and tricks about WordPress plugin development. The idea behind this plugin started as a feature requested in WordPress core; I would love to hear your thoughts about it. Does it improve the current workflow? Would you find a similar approach useful but on managing Gravatar images right from your profile screen?
As a bonus, the Avatar Manager plugin is also available on WordPress Plugin Directory and GitHub. Check it out to stay up-to-date with the latest releases. Thanks for reading!
References
- WordPress Coding Standards - General information about coding standards for WordPress development.
- Writing a Plugin - Best starting place for learning about how to develop WordPress plugins.
- Plugin API - Description of how to use action and filter hooks in your WordPress plugin, and core functions that plugins can override.
- Function Reference - An article with many of the core WordPress functions useful to plugin and theme developers; lists most of the core functions, excluding Template Tags.
- I18n for WordPress Developers - Internationalization, including a section on how to internationalize your plugin.
- Plugin Submission and Promotion - Once you have written your plugin, here are some hints on distributing it widely.
External Links
- Avatar Manager on WordPress Plugin Directory - Official home for the Avatar Manager plugin.
- Avatar Manager on GitHub - Source code of the Avatar Manager plugin.
Comments