When WordPress 3.5 was released, one of the most significant changes that was introduced was to that of the Media Uploader. Perhaps a more accurate description of the change would be to refer to at as an addition of a new Media Uploader.
After all, the old version of the Media Uploader still exists and can run side-by-side with the current Media Library, but it’s something that must be done through the proper addition and usage of scripts, style, and all other dependent functionality.
As with anything in software, features and functionality that exist for a significant amount to time are subject to be deprecated in favor of new features or functionality. In our case, the Media Library is no exception. Though it’s no longer being used by WordPress core, there are plenty of plugins and other third-party utilities that are still using the old version of the Media Library.
The challenge that comes with having so many copies of the older functionality’s code is that when it comes time to make use of the Media Library ourselves, we’re likely to end up finding examples to the older functionality.
Since the new Media Library is what’s the new standard in WordPress, and since there’s not a lot of documentation available for how to use it, we’re going to take a look at the functionality over the next few articles to understand how the new Media Library is constructed, how we can implement it in our own work, and how we can take advantage of the various functionality that’s already included in WordPress core.
The WordPress Media Uploader
The new WordPress Media Uploader has a number of advantages over the previous iteration:
- Drag and drop support
- Cleaner interface
- Easer management of galleries
- …and more
It’s important to note, though, that the most recent version of the uploader is built using a set of completely different technologies than those prior. This means that the code that you once wrote to implement custom media management may still work (until the core Thickbox code is deprecated), but that it’s going to look and feel dated in comparison to what users are now experiencing whenever they manage their media within WordPress.
A Word About Underscores and Backbone
Before taking a look at how to begin incorporating this into our own code and creating our own implementation, it’s important to understand the underlying foundation of the new media library.
As mentioned earlier, the previous edition of the media uploader used a library that was known as Thickbox in order to create the things that we’ve seen, but in the latest implementation, WordPress is using both Underscores (not to be confused with the Underscore theme), and Backbone - two JavaScript technologies that work together to drive the user interface and manage the events of the media uploader.
Though we won’t be taking a deep dive into either of these libraries, it’s important to understand the role that each plays in the Media Uploader.
First, Backbone:
Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.
And Underscore:
Underscore is a JavaScript library that provides a whole mess of useful functional programming helpers without extending any built-in objects. It’s the answer to the question: “If I sit down in front of a blank HTML page, and want to start being productive immediately, what do I need?” … and the tie to go along with jQuery’s tux and Backbone’s suspenders.
Obviously, you can read more about each of these on their respective pages, but I wanted to mention them now so that when we get into looking managing the UI and the events for our custom Media Library implementation, then we have a clearer understanding as to what the code is actually doing.
Finally, note that this is not jQuery. If you’re used to working with that library - and many of us are - these two libraries are completely separate. You can - and we will - use jQuery alongside the functionality added by Backbone and Underscore.
Incorporating the Media Uploader
Now, let’s actually get to writing some code.
For the purposes of our example, we’re going to take a look at how we go about integrating a basic version of the Media Library into an existing WordPress theme. For the purposes of our example, we’ll be building this as a plugin; however, the environment that we’re going to use consists of the following:
- A base installation of WordPress 3.9.2
- The Twentytwelve theme
And that’s it. The rest of the code will be contained in our plugin. Of course, this still raises the question as to what our plugin is going to actually do.
In short, we’re going to work on mimicking the ‘Featured Image’ functionality of WordPress, but rather than adding an image to the top of the post (or near the top of the post), we’re going to introduce a ‘Featured Footer Image’ that adds the image to the bottom of the post.
Obviously, the functionality is trivial - the emphasis is on implementing the new Media Library.
All of the source code will be made available for review in a GitHub repository associated with this article, feel free to follow along with the code as the article progresses and then download the code to study more after each article for further review.
1. Setup the Project Directory
In the wp-content/plugins
directory, create a new directory called acme-footer-image
. This is where we’ll be keeping our project files. After that, go ahead and create empty files as follows;
README.txt
LICENSE
acme-footer-image.php
The first three files should be self-explanatory. The acme-footer-image.php
file is where we’ll define the plugin header and actually start execution of the plugin. Note that class-acme-footer-image.php
is the class that will define some of the initial functionality of our plugin.
Next, create a directory within the plugin directory called admin
as this is where all of our administration functionality will be kept. This directory should contain:
admin/class-admin-footer-image.php
admin/js/admin.js
Finally, create a views
directory within the admin
subdirectory as this is where we’re going to place the markup for our meta box. We’ll take a look at this in more depth later in the article.
In an attempt to make sure that we’re creating a well-organized set of files each of which that maintains its own set of responsibilities, we’ll be looking at each of these files in more depth and we work through the tutorial. For now, though, this should include everything we need to get started.
2. Setup the README
Before getting into writing actual code, let’s go ahead and fill out some of the default information starting with the README
.
=== Acme Footer Image === Contributors: tommcfarlin Donate link: http://tommcfarlin.com/ Tags: featured images Requires at least: 3.9.2 Tested up to: 3.9.2 Stable tag: 0.1.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html Append a featured image at the bottom of the content of a post or page. == Description == Append a featured image at the bottom of the content of a post or page. Used as a demo for a Tuts+ Code tutorial. == Installation == This section describes how to install the plugin and get it working. e.g. 1. Upload `plugin-name.php` to the `/wp-content/plugins/` directory 1. Activate the plugin through the 'Plugins' menu in WordPress 1. Place `<?php do_action('plugin_name_hook'); ?>` in your templates == Changelog == = 0.1.0 = * Initial release
Note that this also contains the change log.
3. Setup the Plugin Class
Next, we need to define the code for the core plugin class. This class will be responsible for the following:
- Defining the version number
- Defining the slug that’s used throughout the class
- Registering and enqueuing the necessary JavaScript
- Rendering the meta box
Generally speaking, I don’t find that this is the best way to develop plugins in an object-oriented manner because, as you can see, this class is already doing more than one thing. That’s poor practice; however, because the amount of code is so short, and because the emphasis of this series will be largely focused on the JavaScript that drives the media library, this is a sacrifice I’m willing to make.
So let’s take a look at the class in its entirety and then we’ll take a look at some of the individual components:
<?php /** * The dashboard-specific functionality of the plugin. * * @link http://tommcfarlin.com * @since 0.1.0 * * @package Acme_Footer_Image * @subpackage Acme_Footer_Image/admin */ /** * The dashboard-specific functionality of the plugin. * * Defines the plugin name, version, the meta box functionality * and the JavaScript for loading the Media Uploader. * * @package Acme_Footer_Image * @subpackage Acme_Footer_Image/admin * @author Tom McFarlin <[email protected]> */ class Acme_Footer_Image { /** * The ID of this plugin. * * @since 0.1.0 * @access private * @var string $name The ID of this plugin. */ private $name; /** * The current version of the plugin. * * @since 0.1.0 * @access private * @var string $version The version of the plugin */ private $version; /** * Initializes the plugin by defining the properties. * * @since 0.1.0 */ public function __construct() { $this->name = 'acme-footer-image'; $this->version = '0.1.0'; } /** * Defines the hooks that will register and enqueue the JavaScriot * and the meta box that will render the option. * * @since 0.1.0 */ public function run() { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'add_meta_boxes', array( $this, 'add_meta_box' ) ); } /** * Renders the meta box on the post and pages. * * @since 0.1.0 */ public function add_meta_box() { $screens = array( 'post', 'page' ); foreach ( $screens as $screen ) { add_meta_box( $this->name, 'Footer Featured Image', array( $this, 'display_featured_footer_image' ), $screen, 'side' ); } } /** * Registers the JavaScript for handling the media uploader. * * @since 0.1.0 */ public function enqueue_scripts() { wp_enqueue_media(); wp_enqueue_script( $this->name, plugin_dir_url( __FILE__ ) . 'js/admin.js', array( 'jquery' ), $this->version, 'all' ); } /** * Renders the view that displays the contents for the meta box that for triggering * the meta box. * * @param WP_Post $post The post object * @since 0.1.0 */ public function display_featured_footer_image( $post ) { include_once( dirname( __FILE__ ) . '/views/admin.php' ); } }
Most of the code should be self-explanatory through the comments. If not, don’t hesitate to leave a comment but in the meantime, let’s take a look at the following two areas:
First, the definition of the meta box.
<?php public function add_meta_box() { $screens = array( 'post', 'page' ); foreach ( $screens as $screen ) { add_meta_box( $this->name, 'Footer Featured Image', array( $this, 'display_featured_footer_image' ), $screen, 'side' ); } }
Notice here that we are including support for the meta box on both pages and post types. This function also refers to a callback function display_featured_footer_image
that's responsible for rendering the HTML of the meta box:
public function display_featured_footer_image( $post ) { include_once( dirname( __FILE__ ) . '/views/admin.php' ); }
The markup for this file is very simple. It's an anchor with an ID that we can access via our JavaScript which we'll take a look at momentarily.
<p class="hide-if-no-js"> <a title="Set Footer Image" href="javascript:;" id="set-footer-thumbnail">Set featured image</a> </p>
And we’ll enqueue the JavaScript that’s necessary for loading up the media library.
public function enqueue_scripts() { wp_enqueue_media(); wp_enqueue_script( $this->name, plugin_dir_url( __FILE__ ) . 'js/admin.js', array( 'jquery' ), $this->version, 'all' ); }
Notice here that before registering our own JavaScript, we're making a called to wp_enqueue_media
. According to the Codex, this function:
Enqueues all scripts, styles, settings, and templates necessary to use all media JavaScript APIs.
And this is necessary in order to make sure that we have the dependencies necessary to load up the new Media Uploader.
4. The JavaScript
Next, let's take a look at the JavaScript that we need to write in order to make sure that we're taking advantage of the functionality necessary to setup the Media Library, and to make sure that it displays when the user clicks on the proper link.
The code is heavily commented, so it should be easy to follow. If not, don't hesitate to leave a comment in the feed below the post!
/** * Callback function for the 'click' event of the 'Set Footer Image' * anchor in its meta box. * * Displays the media uploader for selecting an image. * * @since 0.1.0 */ function renderMediaUploader() { 'use strict'; var file_frame, image_data; /** * If an instance of file_frame already exists, then we can open it * rather than creating a new instance. */ if ( undefined !== file_frame ) { file_frame.open(); return; } /** * If we're this far, then an instance does not exist, so we need to * create our own. * * Here, use the wp.media library to define the settings of the Media * Uploader. We're opting to use the 'post' frame which is a template * defined in WordPress core and are initializing the file frame * with the 'insert' state. * * We're also not allowing the user to select more than one image. */ file_frame = wp.media.frames.file_frame = wp.media({ frame: 'post', state: 'insert', multiple: false }); /** * Setup an event handler for what to do when an image has been * selected. * * Since we're using the 'view' state when initializing * the file_frame, we need to make sure that the handler is attached * to the insert event. */ file_frame.on( 'insert', function() { /** * We'll cover this in the next version. */ }); // Now display the actual file_frame file_frame.open(); } (function( $ ) { 'use strict'; $(function() { $( '#set-footer-thumbnail' ).on( 'click', function( evt ) { // Stop the anchor's default behavior evt.preventDefault(); // Display the media uploader renderMediaUploader(); }); }); })( jQuery );
Note that this only displays the Media Library. It doesn't actually do anything after we've uploaded and/or selected an image.
5. Setup Core Plugin File
Finally, the last step is to define our core bootstrap file in order to start the plugin:
<?php /** * Acme Footer Image * * Append a featured image at the bottom of the content of a post or page. Used as a demo * for a Tuts+ Code tutorial. * * @package Acme_Footer_Image * @author Tom McFarlin <[email protected]> * @license GPL-2.0+ * @link http://tommcfarlin.com * @copyright 2014 Tom McFarlin * * @wordpress-plugin * Plugin Name: Acme Footer Image * Plugin URI: TODO * Description: Appends a featured image at the bottom of the content of a post or page. * Version: 0.1.0 * Author: Tom McFarlin * Author URI: http://tommcfarlin.com * License: GPL-2.0+ * License URI: http://www.gnu.org/licenses/gpl-2.0.txt */ // If this file is called directly, abort. if ( ! defined( 'WPINC' ) ) { die; } /** * Includes the core plugin class for executing the plugin. */ require_once( plugin_dir_path( __FILE__ ) . 'admin/class-acme-footer-image.php' ); /** * Begins execution of the plugin. * * Since everything within the plugin is registered via hooks, * then kicking off the plugin from this point in the file does * not affect the page life cycle. * * @since 0.1.0 */ function run_acme_footer_image() { $plugin = new Acme_Footer_Image(); $plugin->run(); } run_acme_footer_image();
Here, everything should be relatively familiar: We're making sure we've permission to load the plugin, we include the dependency for the dashboard, we instantiate the widget, and then we set it into motion.
6. Start It Up
At this point, we’re reading to activate the plugin. Do so from the plugin’s dashboard of your WordPress installation and then navigate to any Post or Page screen. You should notice a “Footer Featured Image.” Then, when you click the anchor, the Media Library should appear.
If not, double-check the paths that you have associated with you JavaScript file and make sure they are properly loading.
From here, you’re free to select images and upload images though nothing else comes from that. In the next article, we’re going to take a look at how to take advantage of the data retrieved from the media uploader.
Conclusion
Here, we took a look at the latest iteration of WordPress’ Media Uploader, how it works, and how we can lay a foundation in order to take advantage of it in our code. In the next article, we’re going to take a look at how to use JavaScript to grab the data added to the Media Uploader so that we, in turn, can do what we want with it.
Additionally, we’re going to take a look at how we can introduce additional fields into the Media Uploader using existing templates that ship with WordPress core. And later, we’re going to see how we can implement additional fields alongside the Media Uploader to save even more information.
For now, play around with the code provided in this article, see if you can get it working within the context of your own projects, and leave and questions and/or feedback that you have in the comment feed below!
Finally, don't forget that you can checkout this code from the associated GitHub repository attached to this post.
Comments