Anatomy of a WordPress Plugin

Exclusive offer: get 50% off this eBook here
WordPress 3 Plugin Development Essentials

WordPress 3 Plugin Development Essentials — Save 50%

Create your own powerful, interactive plugins to extend and add features to your WordPress site

€18.99    €9.50
by Brian Bondari Everett Griffiths | March 2011 | Open Source WordPress

WordPress is a popular content management system (CMS), most renowned for its use as a blogging / publishing application. According to usage statistics tracker, BuiltWith (http://builtWith.com), WordPress is considered to be the most popular blogging software on the planet—not bad for something that has only been around officially since 2003.

Before we develop any substantial plugins of our own, let's take a few moments to look at what other people have done, so we get an idea of what the final product might look like. By this point, you should have a fresh version of WordPress installed and running somewhere for you to play with. It is important that your installation of WordPress is one with which you can tinker. In this article by Brian Bondari and Everett Griffiths, authors of WordPress 3 Plugin Development Essentials, we will purposely break a few things to help see how they work, so please don't try anything in this article on a live production site.

 

WordPress 3 Plugin Development Essentials

WordPress 3 Plugin Development Essentials

Create your own powerful, interactive plugins to extend and add features to your WordPress site

        Read more about this book      

(For more resources on Wordpress, see here.)

Deconstructing an existing plugin: "Hello Dolly"

WordPress ships with a simple plugin named "Hello Dolly". Its name is a whimsical take on the programmer's obligatory "Hello, World!", and it is trotted out only for pedantic explanations like the one that follows (unless, of course, you really do want random lyrics by Jerry Herman to grace your administration screens).

Activating the plugin

Let's activate this plugin so we can have a look at what it does:

  1. Browse to your WordPress Dashboard at http://yoursite.com/wp-admin/.
  2. Navigate to the Plugins section.
  3. Under the Hello Dolly title, click on the Activate link.

    Anatomy of a Wordpress Plugin

You should now see a random lyric appear in the top-right portion of the Dashboard. Refresh the page a few times to get the full effect.

Examining the hello.php file

Now that we've tried out the "Hello Dolly" plugin, let's have a closer look. In your favorite text editor, open up the /wp-content/plugins/hello.php file. Can you identify the following integral parts?

  • The Information Header which describes details about the plugin (author and description). This is contained in a large PHP /* comment */.
  • User-defined functions, such as the hello_dolly() function.
  • The add_action() and/or add_filter() functions, which hook a WordPress event to a user-defined function.

It looks pretty simple, right? That's all you need for a plugin:

  • An information header
  • Some user-defined functions
  • add_action() and/or add_filter() functions
    1. In your WordPress Dashboard, ensure that the "Hello Dolly" plugin has been activated.
    2. If applicable, use your preferred (s)FTP program to connect to your WordPress installation.
    3. Using your text editor, temporarily delete the information header from wpcontent/ plugins/hello.php and save the file (you can save the header elsewhere for now). Save the file.
    4. Refresh the Plugins page in your browser.
    5. You should get a warning from WordPress stating that the plugin does not have a valid header:

      Anatomy of a Wordpress Plugin

    1. Ensure that the "Hello Dolly" plugin is active.
    2. Open the /wp-content/plugins/hello.php file in your text editor.
    3. Immediately before the line that contains function hello_dolly_get_lyric, type in some gibberish text, such as "asdfasdf" and save the file.
    4. Reload the plugins page in your browser.
    5. This should generate a parse error, something like: pre width="70">

      Parse error: syntax error, unexpected T_FUNCTION in /path/to/
      wordpress/html/wp-content/plugins/hello.php on line 16

    • Author: Listed below the plugin name
    • Author URI: Together with "Author", this creates a link to the author's site
    • Description: Main block of text describing the plugin
    • Plugin Name: The displayed name of the plugin
    • Plugin URI: Destination of the "Visit plugin site" link
    • Version: Use this to track your changes over time
  • Now that we've identified the critical component parts, let's examine them in more detail.

    Information header

    Don't just skim this section thinking it's a waste of breath on the self-explanatory header fields. Unlike a normal PHP file in which the comments are purely optional, in WordPress plugin and theme files, the Information Header is required! It is this block of text that causes a file to show up on WordPress' radar so that you can activate it or deactivate it. If your plugin is missing a valid information header, you cannot use it!

    Exercise—breaking the header

    To reinforce that the information header is an integral part of a plugin, try the following exercise:

    After you've seen the tragic consequences, put the header information back into the hello.php file.

    This should make it abundantly clear to you that the information header is absolutely vital for every WordPress plugin. If your plugin has multiple files, the header should be inside the primary file—in this article we use index.php as our primary file, but many plugins use a file named after the plugin name as their primary file.

    Location, name, and format

    The header itself is similar in form and function to other content management systems, such as Drupal's module.info files or Joomla's XML module configurations—it offers a way to store additional information about a plugin in a standardized format. The values can be extended, but the most common header values are listed below:

    Anatomy of a Wordpress Plugin

    For more information about header blocks, see the WordPress codex at: http://codex.wordpress.org/File_Header.

    In order for a PHP file to show up in WordPress' Plugins menu:

    • The file must have a .php extension.
    • The file must contain the information header somewhere in it (preferably at the beginning).
    • The file must be either in the /wp-content/plugins directory, or in a subdirectory of the plugins directory. It cannot be more deeply nested.

    Understanding the Includes

    When you activate a plugin, the name of the file containing the information header is stored in the WordPress database. Each time a page is requested, WordPress goes through a laundry list of PHP files it needs to load, so activating a plugin ensures that your own files are on that list. To help illustrate this concept, let's break WordPress again.

    Exercise – parse errors

    Try the following exercise:

    Yikes! Your site is now broken. Why did this happen? We introduced errors into the plugin's main file (hello.php), so including it caused PHP and WordPress to choke.

    Delete the gibberish line from the hello.php file and save to return the plugin back to normal.

    The parse error only occurs if there is an error in an active plugin. Deactivated plugins are not included by WordPress and therefore their code is not parsed. You can try the same exercise after deactivating the plugin and you'll notice that WordPress does not raise any errors.

    Bonus for the curious

    In case you're wondering exactly where and how WordPress stores the information about activated plugins, have a look in the database. Using your MySQL client, you can browse the wp_options table or execute the following query:

    SELECT option_value FROM wp_options WHERE option_name='active_
    plugins';

    The active plugins are stored as a serialized PHP hash, referencing the file containing the header. The following is an example of what the serialized hash might contain if you had activated a plugin named "Bad Example". You can use PHP's unserialize() function to parse the contents of this string into a PHP variable as in the following script:

    <?php
    $active_plugin_str = 'a:1:{i:0;s:27:"bad-example/bad-example.
    php";}';
    print_r( unserialize($active_plugin_str) );
    ?>

    And here's its output:

    Array
    (
    [0] => bad-example/bad-example.php
    )

WordPress 3 Plugin Development Essentials Create your own powerful, interactive plugins to extend and add features to your WordPress site
Published: March 2011
eBook Price: €18.99
Book Price: €30.99
See more
Select your format and quantity:
        Read more about this book      

(For more resources on Wordpress, see here.)

User-defined functions

Each plugin will store the majority of its code inside functions that you define. While it is technically possible to have a plugin that has nothing but a header, or to have a plugin that does not use user-defined functions, it is highly unlikely you would ever write such a plugin outside of a purely academic exercise.

Ready to proceed? Let's make a doomed plugin.

Exercise—an evil functionless plugin

You may not be used to writing your own functions in your code, especially for trivial tasks. However, when you are writing WordPress plugins, it is virtually impossible to get away with having all your code naked in the main code block. Let's take a closer look at how WordPress works and you will see why you need to shepherd your code into functions.

Normal users will use the Add New button in the Dashboard to search the WordPress repository for published plugins, but we as developers will be creating our own plugins from scratch. To do this, all we need is our trusty text editor (and our FTP client to upload it to the web server, if you're running WordPress remotely).

This exercise will illustrate how not to code a plugin:

  1. Create a new PHP file inside the /wp-content/plugins directory. In this example, we've named ours evil-example.php.
  2. Copy the <?php opening tag and the header information from the "Hello Dolly" hello.php file and take a moment to customize the header.
  3. Add a single print statement to your plugin and save it. The following is what our full example looks like:

    <?php
    /*
    Plugin Name: Bad Example
    Plugin URI: http://wordpress.org/#
    Description: Showing what NOT to do.
    Author: Everett's Twin from an Evil Parallel Universe
    Version: 0.666
    Author URI: http://goo.gl/us9i
    */
    // Worst plugin ever
    print " -------- I think I'm getting a clue!";
    /* End of File */

    Downloading the example code
    You can download the example code files for all Packt books you have purchased from your account at http://www.PacktPub.com. If you purchased the book, WordPress 3 Plugin Development Essentials elsewhere, you can visit http://www.PacktPub. com/support and register to have the files e-mailed directly to you.

    In case you didn't notice, we have omitted the closing ?> tag. We'll explain why, later in this article.

  4. Once you've saved your new plugin, head back to your browser and refresh the Plugin admin page. Your new plugin should appear on the list, as follows:

    Anatomy of a Wordpress Plugin

  5. As soon as you activate the plugin, a few horrible things may happen.
  6. You may see a PHP warning, such as Cannot modify header information….
  7. WordPress itself may show you a warning, as follows: The plugin generated 37 characters of unexpected output during activation. If you notice "headers already sent" messages, problems with syndication feeds or other issues, try deactivating or removing this plugin.

    (Move the mouse over the image to enlarge it.)

You will see the text you printed at the top of every page on your site, including your home page! This obnoxious text appears before the opening HTML and DOCTYPE tags.

What just happened

This is a pretty simple script, so why did everything explode? If you already know the answer, keep quiet for the folks who are still figuring this out. The answer will help keep you out of trouble when writing PHP code.

Now, to answer the question of all those header errors—what's going on? The whole point of using a hook is to have your function executed at a certain time. When you include a file, its code is parsed and any code not inside classes or function-blocks gets executed (whereas the classes and functions are merely loaded). The problem here revolves around PHP's header() function, which WordPress is using to declare the content type of its output—for example, the scripts generating the main pages use the text/HTML content type, whereas the scripts generating the RSS feeds use an RSS/XML content type.

All you really need to understand here is that the header() function must be called before any output is sent. From PHP's documentation:

"Remember that header() must be called before any actual output is sent, either by normal HTML tags, blank lines in a file, or from PHP."

It also warns that header errors are common when using include() or require() functions. A brief analogy is seen when you mail a letter—you must address the envelope before you drop it into the mailbox.

Consider the following two scripts:

Example 1

<?php
header('Content-type: text/plain');
print "Headers come first.";
/* End of File */

Example 2

<?php
print "This will raise a warning.";
header('Content-type: text/plain');
/* End of File */

The first example works normally—if you uploaded this to the root of your website and named it test.php, then loaded it in your browser (for example, http://yoursite. com/test.php), you would see the printed text. However, the second example generates the now familiar PHP warning: Cannot modify header information. It's as if you are trying to change the address on your letter after you posted it.

Back in our "Bad Example" plugin, this is exactly what was happening. The print statement was executed when the file was included, and this jumped the gun on the header() function, even though the code was otherwise syntactically correct. Our "Bad Example" is, in fact, a good example of what not to do. This should help drive home the point that you must define your own functions in order to write WordPress functions—you cannot simply put naked code into your plugin file.

Omitting the closing "?>" PHP tag

So why do we omit the closing tag in our plugins? PHP will automatically terminate a file with a closing ?> tag if needed, but we're not just being lazy here. The reason is predicated on our discussion about headers—if your plugins have any trailing whitespace after the closing ?>, it gets interpreted in the same way as if you had printed something, and that can cause the same header warnings. Look closely at the following example. Notice the extra lines after the closing PHP tag?

Anatomy of a Wordpress Plugin

It is exceedingly difficult to spot extra newlines or spaces when debugging a script, so we omit the closing PHP tags whenever possible simply because they may trigger header errors. It is helpful to include a comment at the end of the file, such as /*End of File*/ or simply /*EOF*/ just as a reminder that yes, the omission is intentional and not the result of a corrupted file.

A better example: Adding functions

Now that we know what we can't simply print data directly from our plugin's main block, let's fix our example to make it a bit more like the "Hello Dolly" plugin:

<?php
/*
Plugin Name: Better Example
Plugin URI: http://wordpress.org/#
Description: Undoing the Madness
Author: Everett's sometimes obnoxious Twin
Version: 0.7
Author URI: http://theonion.com/
*/
function safe_print() {
print " -------- I think I'm getting a clue!";
}
/* End of File */

What's different about this example? This version of our plugin isolates the print statement inside a function block so that it does not execute immediately once the file is loaded. If you change the code in your sample plugin and save it, the warnings caused by the previous version of this plugin should disappear once you refresh the page. This gets us out of trouble, but it doesn't get our statement printing and visible just yet. To do that, we must add a hook to trigger execution of our function.

Referencing hooks via add_action() and add_filter()

The final vital component in a WordPress plugin is the hook, which defines when the plugin is executed. This is arguably the most confusing component of a plugin, so we will be thorough in our explanations. Just as in pop-music, the term "hook" is sometimes ambiguous—different people use the term to refer to different things. Technically, the term "hook" should refer to a WordPress event, such as get_header or the_content, but sometimes it is used generally to refer to the add_action() or add_filter() functions which reference the hook. Pay attention to the context, and it should be clear which meaning was intended. The most important thing to understand here is that you determine when your functions execute by attaching them to a WordPress event by using the add_action() or add_filter() functions. Remember: hooks are events.

The syntax for both functions is exactly the same. We'll discuss the reasoning for this shortly, but for now, just compare the two:

add_filter( string $hook, mixed $your_function_name [, int
$priority = 10 [, int $accepted_args = 1]])

versus

add_action( string $hook, mixed $your_function_name [, int
$priority = 10 [, int $accepted_args = 1]])

In practice, the most common usage includes only the name of the WordPress event and the name of your function, such as:

add_action('admin_footer', 'hello_dolly');

In "Hello Dolly", admin_footer is the action or event, and hello_dolly is the name of the function which we want WordPress to run when the admin_footer event occurs. Note that we have intentionally digressed from WordPress' official terminology for the sake of clarity.

Actions versus Filters

This is another confusing area in the land of WordPress plugins. What exactly is the difference between an action and a filter? Well, even if you've read through the forums and official documentation, the answers there likely left you more confused, so let's get this clarified once and for all.

Actions and filters are simply two different types of events. Remember that WordPress refers to events as "hooks". The difference between them is predicated on how WordPress handles the hook in question. Some hooks are designated as action hooks, others as filter hooks. When you link one of your functions to a filter hook, your function must accept an input and return an output because it is intended to modify or "filter" output. When you link a function to an action hook, your function is not passed input parameters, and any value returned is simply ignored. It is all a matter of how WordPress handles a given hook. On his site, Adam Brown maintains lists of all available WordPress hooks, and you can verify whether a given hook is a filter or an action hook (http://adambrown.info/p/wp_hooks/).

The truth of the matter is that the architecture here is showing its age, and there are some caveats that can be confusing. Actions and filters are simply types of events, and the add_action() and add_filter() functions are actually one and the same— one function merely references the other. If you are curious, have a look for yourself inside the /wp-includes/plugin.php file. In other words, you can replace any instance of add_action() with add_filter() and vice versa, and it will have no effect on the functionality of your plugin. They both simply tie a WordPress event to a function you have defined. Even though the add_action() and add_filter() functions are fundamentally the same, we do not recommend that you swap them! There is a recommended usage here that should be followed for mnemonic purposes.

Just once, however, let's demonstrate that the add_action() and add_filter() functions are equivalent by modifying the "Hello Dolly" plugin once again. This will help us understand that both functions tie to an event, and the behavior of the event is determined by the event in question, not by the function used to reference it.

Exercise—actions and filters

Using your favorite text editor, let's modify the "Hello Dolly" plugin once more.

Try replacing both instances of add_action() with add_filter() and save the file. The following is what the important lines now look like:

add_filter('admin_footer', 'hello_dolly');
// ...
add_filter('admin_head', 'dolly_css');

Remember: We haven't changed anything else about this plugin, only these two lines.

Try refreshing the WordPress Dashboard—the plugin still functions in exactly the same way. The takeaways from this exercise should be that actions and filters are simply classifications of events, and the behavior of a particular event is inherent in the event itself, not in the function we use to reference it. In other words, admin_ footer and admin_head are action-events, not filter-events, and they remain actionevents no matter how we hook into them.

Return the functions to their original state once you're done:

add_action('admin_footer', 'hello_dolly');
// ...
add_action('admin_head', 'dolly_css');

Now that we've demonstrated that the event is the important thing here, not the function, let's try using a different event so we can see how it behaves differently.

Exercise—filters

Let's suppose we want to repurpose the "Hello Dolly" plugin so it prints random lyrics into posts on the frontend of our site instead of just inside the WordPress manager. We will call this new plugin "Hello Knock Off". The change in behavior will revolve around the event that we hook into. Instead of tying into the admin_ footer event, we are going to hook into the the_content event. the_content is a filter event, so we have to use it slightly differently than we did the admin_footer action event. Comparing the "Hello Knock Off" plugin to the original "Hello Dolly" will be a simple example that demonstrates the differences between an action and a filter. Let's get started.

First, let's make a copy of the "Hello Dolly" plugin—just copy the hello.php file and name the copy knockoff.php. You should save it in the same directory: /wp-content/plugins. Be sure you deactivate the original "Hello Dolly" plugin to avoid confusion.

Next, modify the information header so we can spot this plugin inside the WordPress manager. The following is what our example looks like:

<?php
/*
Plugin Name: Hello Knock Off
Plugin URI: http://wordpress.org/#
Description: Our first filter event
Author: Some Puerto Rican Guy
Version: 0.1
Author URI: http://goo.gl/kMEc
*/
/*EOF*/

Activate the plugin from inside the WordPress manager—it should show up in the Plugin administration area under the name "Hello Knock Off". Before we change the functionality, verify that the copy of the plugin works just like the original. You should see the same random messages at the top of each page in your WordPress Dashboard just like you did with the original plugin.

Next, let's change the event that is referenced here. Instead of using the admin_ footer hook, let's use the the_content hook. Change the following line:

add_action('admin_footer', 'hello_dolly');

So it reads:

add_filter('the_content', 'hello_dolly');

Even though we have demonstrated that both functions are effectively the same, do not confuse yourself or others by mixing these up! the_content is a filter event, so we should always reference it using the add_filter() function.

Save your work, then try visiting your home page. You'll notice that all of your posts have been replaced with random Hello Dolly lyrics, all simply because we are hooking the code into a different event.

Anatomy of a Wordpress Plugin

Let's make some adjustments here so that instead of replacing the post content, we append the quote to it. That is what a filter normally does: it modifies some text, not replaces it entirely.

Edit the hello_dolly() function in your knockoff.php so that it accepts an input, and instead of echoing a string, it returns it:

function hello_dolly($input) {
$chosen = hello_dolly_get_lyric();
return $input . "<p id='dolly'>$chosen</p>";
}

The $input here represents the content for each post—it is passed into the filter function, acted on, and then returned. Do you see how we have appended the chosen lyric to the $input? The result is that now we are appending a random lyric to each blog post instead of overwriting it.

Anatomy of a Wordpress Plugin

To reiterate what just happened, the bulk of changes were caused by simply changing the event that was referenced from admin_footer to the_content. We also had to change some of the syntax in the user-defined function to correctly use a filter event instead of an action event. This should help reinforce the fact that some events are filters, and some events are actions, and now you have seen the differences in syntax between these two types of events. A function called by an action event does not accept or return input, whereas a function called by a filter does.

You may have noticed that some parts of this knock-off plugin are not being used. So let's simplify our knock-off plugin by deleting the following two functions: dolly_css() and the function that hooks into it: add_action('admin_head', 'dolly_css');

Deleting those functions simply helps clean up superfluous code. The original "Hello Dolly" plugin required those extra functions in order to correctly style and position the output, but in our "Hello Knock Off" plugin, we don't need the extra styling because we are simply appending the quotes to post content.

Reading more

Hopefully these exercises have clarified how WordPress handles actions and hooks. It is worth your time and effort to skim through the online documentation that lists the most common actions and filters, just so you have some awareness of what actions and filters are available. WordPress has thousands of hooks, but there are still some key places that you cannot easily hook into. We recommend bookmarking the following two pages for reference:

http://codex.wordpress.org/Plugin_API/Action_Reference
http://codex.wordpress.org/Plugin_API/Filter_Reference

The hooks referenced on those pages are only a fraction of those available, but we recommend that you stick to the short list as much as possible. For a full list of all WordPress hooks, see:

http://adambrown.info/p/wp_hooks/

Summary

After completing this article, you should know how to create a simplistic WordPress plugin and you should know where you have to put the file in order for it to show up in the WordPress Dashboard. You should have learned a couple debugging techniques that will apply to your work as a plugin developer. We've learned the differences between filters and actions and seen how WordPress sends data to your functions in each case. You should now have a working understanding of the most common plugin patterns and you should now be ready to write a couple of your own.


Further resources on this subject:


WordPress 3 Plugin Development Essentials Create your own powerful, interactive plugins to extend and add features to your WordPress site
Published: March 2011
eBook Price: €18.99
Book Price: €30.99
See more
Select your format and quantity:

About the Author :


Brian Bondari

Brian Bondari is a musician, composer, and teacher with equal loves for both music and technology. His hobbies include reading, hiking, composing music, and playing with his pet rabbit. He also spends an exorbitant amount of time lying on the floor grading papers.

Brian earned his doctorate from the University of Kansas in 2009 and is currently an Assistant Professor of Music Theory and Composition at the University of Texas at Tyler. When he is not writing music or grading papers, he serves as Senior Editor for the multi-author technology blog, http://www.TipsFor.us.

You can also visit him at http://www.bondari.com.

Everett Griffiths

Everett Griffiths is a freelance PHP/Perl developer and database architect specializing in Content Management Systems and plugin development. His hobbies include playing guitar and running. He currently resides in Los Angeles with frequent trips abroad.

Books From Packt

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

WordPress Top Plugins
WordPress Top Plugins

WordPress 3 Complete
WordPress 3 Complete

WordPress 3 Site Blueprints
WordPress 3 Site Blueprints

WordPress 3.0 jQuery
WordPress 3.0 jQuery

WordPress 3 Ultimate Security
WordPress 3 Ultimate Security

WordPress and Flash 10x Cookbook
WordPress and Flash 10x Cookbook

WordPress 3.0 Search Engine Optimization
WordPress 3.0 Search Engine Optimization

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software