Make Your First WordPress Plugin: A WordCamp Maine 2014 Presentation

This post is a companion to my WordCamp Maine 2014 talk, “Make Your First WordPress Plugin.”

It’s effectively a recap of an earlier post, Making A Simple WordPress Plugin, with elements from Hooking WordPress Taxonomy Changes With The Plugins API.

If you know how to make, or hack, a WordPress theme, you have all the skills you need to write a plugin.

All it takes is a little knowledge of how to write PHP, a basic understanding of how WordPress goes about making Web pages, and a little trial and error. Oh, and the same, basic tools you use to make any website:

A decent text editor is the only “must have.”

For Macintosh, TextWrangler will work fine; I prefer its full-featured sibling, BBEdit. Protip: Download these directly from BareBones; the Apple Store versions don’t support all features and can make upgrading difficult.

For PC, I use Notepad++; others swear by Sublime Text.

A Web development IDE, such as Dreamweaver, WebMatrix or even Visual Studio will work, too; although these tools, in their zeal to make things easier, can significantly complicate writing plugin code.

Regardless of whether you use a Mac or PC, don’t use the built-in text editors (TextEdit and Notepad, respectively); they tend to introduce file encoding that can prove problematic when trying to write plugins.

Optionally, it’s good to have an FTP program. While this isn’t strictly necessary, it makes salvaging a plugin installation that has gone horribly wrong a lot easier. If you’re an OS guru you can, of course, just use your Web browser for FTP, or maybe install an FTP plugin; but I prefer to use FileZilla on PC and Transmit on Mac.

How Do WordPress Plugins Work?

Rideau Hall sentry
Don and Anne Rothfuss stand next to a sentry at Rideau Hall in Ottawa, Ontario, Canada on July 20, 2010. They seem like nice folks, so this sentry isn’t concerned.
A WordPress plugin basically works like a sentry at a military base.

A sentry silently stands by, watching people come and go. In many cases, she doesn’t do anything about what’s passing by; she just stands there.

But when something specific comes by — such as a high-ranking officer, an intruder or some sort of commotion — the sentry leaps into action, deals with the situation, then returns to her post, to again keep watch and act when needed.

Plugins are the sentries of WordPress.

A WordPress plugin basically waits for WordPress, as it goes about its business of making Web pages or handling other requests. to do something specific.

When that something happens, the plugin leaps into action, changing how WordPress goes about that task. Such changes can be quite subtle (maybe just changing some layout based on what category a post is in) or significant, such as a WooCommerce, which turns a WordPress install into a full-featured storefront.

A plugin can:

  • Make WordPress do something it normally wouldn’t do: for example, send an email to your friends, every time you create a new post.
  • Change how WordPress goes about doing something: for example, automatically make every new post sticky, and unsticky the next most recent post.
  • Stop WordPress from doing something it normally would do: for example, turn off all comments for a post if it’s in a given category, regardless of whether the author chose to enable comments.

Since most designers and beginning coders tend to see very complicated plugins which alter WordPress’ behavior in a number of ways, it’s easy to assume plugins are far more complicated than they actually are. And a well-written plugin, fully abstracted into classes and multiple, dependent files, can be neatly indecipherable, even for experienced hands.

But trust me, plugins are very easy to make. Once you get the hang of making a few simple plugins, it won’t be long before you’re happily hacking other people’s plugins to work 100 percent the way you want (rather than the 80 percent effective most plugins prove “out-of-the-box”) and even making your own.

So let’s get started!

Your First WordPress Plugin: Shortcodes

The easiest way to learn how plugins are made is to make one that’s not only child’s play for WordPress to understand, but one that’s also really, really useful. And nothing better fits those bills than a shortcode.

As you probably know, a shortcode is basically a way to apply static HTML, CSS, JavaScript or other text at a given point in a post, or to get WordPress to do something special when processing a post.

For example, some gallery plugins will use a shortcode to specify where, in a post, an image gallery should show up. Or maybe a plugin uses a single shortcode on a page to render its content under a vanity URL, such as “/calendar” for a calendar plugin.

Because we’re new to plugins, we’ll do something a little more pedestrian. We’ll create a plugin that spits out boilerplate text.

Step 1: Prepare The Plugin

And conveniently enough for us, making a plugin begins with adding some boilerplate: namely, a PHP comments section that gives metadata about our plugin.

You know all that cool information that appears when you look at your plugins list in the WordPress dashboard?

The WordPress dashboard, installed plugins panel.
The WordPress dashboard, installed plugins panel.

Well, that data has to come from someplace, and that “someplace” is the very first lines of your plugin’s code, inside a PHP comment.

Here’s what we’ll use. Change the values as appropriate, but make sure each value, such as Plugin Name and Plugin URI, is on its own line. Also, make sure you follow the pattern “Field Title: Field Value,” so WordPress understands what you’re telling it.

/*
* Plugin Name: My Shortcode Plugin
* Plugin URI: http://www.example.com/path-to-some-page-that-this-plugin-calls-home.html
* Description: This is my very first plugin, and it creates a shortcode that spits out a bunch of boilerplate text.
* Version: 1.0
* Author: Your Name Here
* Author URI: http://mywebsite.com
* License: GPL2
*/

If you don’t add this information, the dashboard won’t be able to figure out what your plugin is named. As WordPress’ guide to writing plugins notes, the only line you must have is Plugin Name, and it must be formatted as it is above.

All other lines are optional; but if you plan to offer your plugin on wordpress.org, you’ll need to provide all this information, including a GPL-compatible license term.

Is this commenting system a wise way of attaching metadata to a plugin? Nope, it’s pretty terrible. It’s easy to understand, but it’s also a case where one little mistake can make the whole thing break. So be careful, and remember: “easy” and “efficient” aren’t the same thing.

A Quick Primer On Hooks And Callbacks

OK, now it’s time to get down to brass tacks: Actually making WordPress behave differently by giving it new instructions.

This implies two basic parts to every WordPress plugin:

  • We need to know what WordPress behavior we want to change, extend or stop; and
  • we have to create new instructions that let WordPress change, extend or stop what it’s doing.

Those two parts of a plugin are called the hook and the callback, respectively.

Let’s explain those terms in turn.

The Vaudeville hook, as demonstrated by Donald Duck.
A hook basically means a point at which we can intercept what WordPress is doing, and send it new instructions for performing that task.

Everything WordPress does — save a post, show a webpage, create a user, etc. — is done in steps. If all goes well, it looks to us like WordPress is performing a single task; I clicked on a link for a post, and boom! There it is.

But in actuality, WordPress is going through a number of steps to create that webpage:

A stripped-down version of the WordPress page lifecycle. Several possible events have been removed for simplicity's sake. Source:  WordPress Plugin API Action Reference page.
A stripped-down version of the WordPress page lifecycle. Several possible events have been removed for simplicity’s sake. Source: WordPress Plugin API Action Reference page.

The good news is, WordPress tells us every time it performs any one of these steps.

How it does that is a little complicated, but you can think of a baseball play-by-play announcer.

The announcer doesn’t just sit quietly until a runner crosses home plate; he tells you about the score, the number of strikes and outs, what pitch was just thrown, where players are on the field, who’s batting next, what that person’s batting average is, some tidbit about his career or recent appearances, and so on and so forth.

WordPress isn’t quite that loquacious, but depending on what it’s doing, it tells anyone who’s listening not only what it’s doing as it goes about a task, but in some cases provides very detailed information about what it’s doing.

So all our plugin must do, to know what WordPress is doing and where to change its normal operation, is listen to what WordPress is saying. And the way we do that is through hooks.

That is, our shortcode plugin will tell WordPress something like, “Hey, the next time you display this post, let me know. Because then, I want you to replace this shortcode with something else. That something else, I’m going to define over here, in this callback function.”

Kevin Kline, left, as Cyrano; and Daniel Sunjata, as Christian, woo Jennifer Garner, as Roxane, at her balcony in a 2007 performance of Cyrano de Bergerac (Act 3, Scene 6), at the Richard Rodgers Theatre in New York City. Photo by New York Daily News.
A callback is basically a way to run, from one PHP function, a different function.

Think of callback functions being like Cyrano de Bergerac.

Our plugin’s hook, Christian, gets the attention of WordPress, nee Roxane. But it doesn’t have the words to win her over.

So from the bushes, Cyrano the callback function tells Christian, the hook, what to say to Roxane, aka WordPress.

Like the play, everyone in this melodrama maintains his role, but with a happy outcome: The hook has successfully engaged WordPress; the callback has successfully handled the details; and the plugin has achieved its purpose.

So in building our plugin, we kind of do things backwards. While we need to know what hook to use to capture WordPress’ attention, we first must get Cyrano safely secreted away. That is, we first have to write the code that is going to modify WordPress’ behavior.

Let’s do that now.

Step 2: Write The Code That Does What We Want Done

For our plugin, we’ll create three messages that can be output by our shortcode:

Copyright © 2014. All rights reserved.
Visit our sister site, <a href="http://www.example.com">Example Website</a>.
"Good questions outrank easy answers." &mdash; Paul Samuelson

Now, we’ll create our callback function, which will handle actually outputting the content:

function my_shortcode_plugin_callback($atts, $content = null) {
	switch($atts['id']) {
		case "1":
			$msg = "Copyright &copy; " . date('Y') . " All rights reserved.";
			break;
		case "2":
			$msg = 'Visit our sister site, <a href="http://www.example.com">Example Website</a>.';
			break;
		default:
			$msg = '"Good questions outrank easy answers." &mdash; Paul Samuelson';
			break;
	}
	return $msg;
}

For those new to PHP, let’s go over this line by line:

Line 1 creates the callback function, which is named my_shortcode_plugin_callback. It takes two arguments: $atts will be an associative array of the attributes of the shortcode (more on that momentarily); $content is the text contained within the opening and closing tags.

If we look at a typical WordPress shortcode, it might look something like this:

[myshortcode id=1 color=blue]Lorem ipsum dolor sit amet.[/myshortcode]

In this case, id and color are the values of $atts. More specifically, they become part of an associative array, where id and color are keys in that array, with their respective values.

In other words, this:

[myshortcode id=1 color=blue]

becomes this:

$atts['id'] = "1";
$atts['color'] = "blue";

$content is whatever lies inside the myshortcode tags; or, in this case, “Lorem ipsum dolor sit amet.”

So, when we write our callback function, we provide it with the two arguments that are automatically part of the shortcode: The arguments inside the opening tag, or $atts; and the content inside the opening and closing shortcode tags, or $content.

Notice that in Line 1 of our shortcode’s callback function, we set the default value of $content to be null.

That’s because we don’t always have content inside a shortcode; or, more specifically, not all shortcodes have, or even need, a closing tag.

That’s the case with our shortcode. All we really need is to know which message we want to output. So, when we actually put our shortcode into a post, it would most likely look like this:

[myshortcode id=1]

As you can see, there’s no closing tag for this shortcode. Thus, $content is null; with null meaning “simply does not exist.”

Lines 2-12 of the shortcode are a switch statement. In PHP, a switch basically acts like an if-then statement; but rather than having to write out the same condition several times, I only have to write it once.

The switch in our plugin code is effectively the same as this if-then statement:

if($atts['id'] == "1") {
	$msg = "Copyright &copy; " . date('Y') . " All rights reserved.";
}
elseif($atts['id'] == "2") {
	$msg = 'Visit our sister site, <a href="http://www.example.com">Example Website</a>.';
}
else {
	$msg = '"Good questions outrank easy answers." &mdash; Paul Samuelson';
}

If you prefer, you can write the if-then statement instead of a switch. I prefer a switch because we’re only dealing with one variable.

Because of the way our switch is written, $msg will always have a valid value. If a “1” or “2” is provided as the value of id in our shortcode, then either the copyright or hyperlink message will be shown. But if a “3” — or any other value, for all that’s worth — is chosen, then the default quote is shown.

We’re actually being a little sloppy here, because we’re not making sure that the values contained in $atts is always what we expect. That is, anyone could add anything they wanted as an argument of our shortcode — or provide junk values for id — and our callback function isn’t directly screening them out.

WordPress advises us that we can screen out crazy values in $atts by using the shortcode_atts function. And as a rule, we really should use it.

But because this is a beginner’s lesson, our shortcode is so specifically limited to two possible values for ID and the code itself effectively prevents bad values from harming it because it has a default response, we’re going to skip this step.

Make no mistake, however: You usually can’t get away with this. Always sanitize your inputs.

On Line 13, the callback function sends out its response as a return value.

When writing a shortcode, we don’t use PHP’s echo or print functions; instead, we always return whatever we want printed out.

That’s because of the way WordPress goes about doing its work. In the case of handling shortcodes when it’s processing a post, WordPress first handles all the shortcode processing, then outputs the body text of the post or page.

So if we used echo or print, instead of return, the content of our shortcode would always appear at the top of the post, rather than wherever we put the shortcode. After all, the shortcode was processed first, and we told WordPress to go ahead and print to screen; so WordPress does as it’s told.

Step 3: Hook The Action And Specify The Callback

And that’s it for the callback function. Now, we need to make the hook.

Remember, the hook is what gets WordPress’ attention; the callback is what does the work.

In WordPress, the hook that allows us to register shortcodes — that is, to get WordPress’ attention when a shortcode exists in a post — is add_shortcode.

It takes two arguments: the name of our shortcode (i.e., the text we’ll type inside the square brackets), and the name of the callback function we just wrote.

So, since our shortcode is named “myshortcode” and the name of the callback function is “my_shortcode_plugin_callback,” we create its hook with this code:

add_shortcode('myshortcode', 'my_shortcode_plugin_callback');
A very important note about shortcode and function names: It’s critically important that you do not create shortcode names or function names in your plugins, that have the same names as shortcodes and functions already running on your site.

For example, never name a shortcode “caption,” since that’s a shortcode name used by WordPress itself. And don’t create a function called download_url in your plugin, because there’s already a function by that name in WordPress.

Generally speaking, the safe way to name plugins and functions is to prepend some string to them which is specific to your website, so that you can be sure name collisions don’t take place. For example, I will usually write functions and shortcodes that are prepended with “dv_”. In my install, I can be certain there are no functions or shorcodes that begin with dv_, other than the ones I made.

And with that, we now have a working plugin. We just have to package it for deployment.

You may be wondering, “Hey, how does the my_shortcode_plugin_callback function get the arguments $atts and $content, if I don’t specify them in add_shortcode? Where do they come from?

The short answer is, WordPress automatically provides them, by virtue of the fact that it knows this hook is registering a shortcode. How does it know that and where does it get those values? I won’t get into that here, because it’s complicated, but I do address it in the post Hooking WordPress Taxonomy Changes With The Plugins API.

Final Step: Install Your Plugin

There are two ways to prepare a plugin for use on your website, when it doesn’t come from WordPress.org.

The easiest is to simply put your plugin into a zip file, then upload it through the Dashboard plugin installer.

The screen for uploading a zip file to your site's plugins.
The screen for uploading a zip file to your site’s plugins.

The benefit in doing this is, WordPress handles creating your plugin directory for you and putting that directory in the right place.

When zipping up a single-file plugin, like ours, don’t put it in a folder; just zip the file itself. That’s because WordPress will create a folder when it unzips our file.

If we have our PHP file inside a folder when we make the zip, that would put out PHP file inside a subfolder of the plugin folder on our WordPress site. And that, in turn, could mess up our plugin install. So as a rule, for single-file plugins, just zip the file itself.

Alternatively, we can manually install our plugin:

  • Use your FTP program to connect to your website.
  • Navigate to your plugins folder (usually wp-content/plugins).
  • Create a new folder inside your plugins folder, and name it something file-system friendly (e.g., myshortcode; my-shortcode; my_shortcode).
  • Inside that folder, upload your plugin file. (Note that your plugin file can be named anything; it doesn’t have to be index.php or the like. If you have concerns about directory browsing by hackers, you can always upload a blank index.html file to the same directory; that won’t hurt a thing.)
  • Close your FTP program and log in to the WordPress Dashboard.
  • You should see your plugin listed under Plugins, but deactivated. Just click Activate to fire it up.

Let’s take this thing out for a test run. Open a post, and put the shortcode somewhere within the post’s content:

[myshortcode id=2]

If all went according to plan, you’ll see this message appear in your post, wherever you put that shortcode:

Visit our sister site, <a href="http://www.example.com">Example Website</a>.

And that’s it. Congratulations, you’re officially a WordPress developer!

Disaster Recovery

In theory, if your plugin has major PHP-based problems — as in, it simply won’t parse — WordPress should catch that, and refuse to load the plugin. It should also report the PHP error that is killing the plugin’s execution.

You can use the Dashboard’s plugin editor to quickly fix the problem, but that editor can be dangerous, since it’s easy to accidentally edit the wrong plugin.

So it’s a better choice to remove your plugin altogether, fix it, then reinstall it.

Sometimes your plugin will properly execute (that is, it’s free of PHP errors), but it has wildly unanticipated consequences; for example, it goofs up WordPress completely, or makes some other plugin go haywire.

If you weren’t careful with how you named your plugin’s hooks and callbacks, you’ll definitely run into this.

This is where an FTP program comes in handy. If your plugin has sabotaged your WordPress install:

  • Connect to your website by FTP.
  • Enter the plugin directory (again, usually wp-content/plugins).
  • Locate the directory that contains your plugin file(s).
  • Rename that directory. It’s easiest to just append something to the directory name; for example, if the directory is named myshortcode, rename it to myshortcode-bak.

This will disable the plugin; it will still be in your plugin list, but appear deactivated. You can now uninstall it, fix the code and try reinstalling again.

Dos and Don’ts

So let’s talk finally about best practices when developing plugins.

Build your plugins on a test install of WordPress. While WordPress has been improved over the years to make it harder for an errant plugin to sabotage a site, it’s still well within the realm of possibilities.

Always be pessimistic about function names. The more plugins and customization your WordPress install has, the better the chance you’ll run into a PHP function name that’s already been used.

The easiest way to keep your function names unique is to prepend some identifier to the function name; maybe your blog’s address, maybe your initials, something you can be sure won’t be reused.

function make_thumbnail() { } //BAD!
function dougv_make_thumbnail() { } //GOOD!

Backup WordPress before installing or upgrading a plugin. This is really something you should always do regardless of a plugin’s source, no matter how trusted it is. It only takes one nuked site to make you appreciate having a backup.

I use a plugin called UpdraftPlus, with the premium offsite backup add-on, which I use to send my backup files to Google Drive. VaultPress is another great option, or if you’re running iThemes Security, BackupBuddy.

A backup plugin that copies files just to your Web server, or a manual FTP and MySQL dump to your desktop, is generally OK for recovering from plugin installs gone wrong. But the nice thing about these turnkey backup plugins is the ability to automagically “roll back” to the way things were just before things went wrong.

Links And Code

All links in this post on delicious: https://delicious.com/dougvdotcom/make-first-wordpress-plugin-wordcamp-maine-2014-presentation

The slides from my WordCamp 2014 presentation are here: http://dougv.us/pt

The sample code from my presentation is here: http://dougv.us/ps

I distribute code under the GNU GPL. See Copyright & Attribution for details.

Beach To Beacon 10K finish line by Ben McCanna. All rights reserved, used by permission.
Runners cross the finish line at the Beach To Beacon 10K race on Aug. 2, 2014. Photo by Ben McCanna. All rights reserved, used by permission.

The featured image on this post is © Ben McCanna on Flickr: https://flic.kr/p/ohYovs All rights reserved, used by permission.

1 Comment

Leave a Reply

  • Check out the Commenting Guidelines before commenting, please!
  • Want to share code? Please put it into a GitHub Gist, CodePen or pastebin and link to that in your comment.
  • Just have a line or two of markup? Wrap them in an appropriate SyntaxHighlighter Evolved shortcode for your programming language, please!