Ten Things Every WordPress Plugin Developer Should Know

Advertisement

Plugins are a major part of why WordPress powers millions of blogs and websites around the world. The ability to extend WordPress to meet just about any need is a powerful motivator for choosing WordPress over other alternatives. Having written several plugins myself, I’ve come to learn many (but certainly not all) of the ins-and-outs of WordPress plugin development, and this article is a culmination of the things I think every WordPress plugin developer should know. Oh, and keep in mind everything you see here is compatible with WordPress 3.0+.

Don’t Develop Without Debugging

The first thing you should do when developing a WordPress plugin is to enable debugging, and I suggest leaving it on the entire time you’re writing plugin code. When things go wrong, WordPress raises warnings and error messages, but if you can’t see them then they might as well have not been raised at all.

Screenshot1

Enabling debugging also turns on WordPress notices, which is important because that’s how you’ll know if you’re using any deprecated functions. Deprecated functions may be removed from future versions of WordPress, and just about every WordPress release contains functions slated to die at a later date. If you see that you are using a deprecated function, it’s best to find its replacement and use that instead.

How to Enable Debugging

By default, WordPress debugging is turned off, so to enable it, open wp-config.php (tip: make a backup copy of this file that you can revert to later if needed) in the root of your WordPress installation and look for this line:

define('WP_DEBUG', false);

Replace that line with the following:

// Turns WordPress debugging on
define('WP_DEBUG', true);

// Tells WordPress to log everything to the /wp-content/debug.log file
define('WP_DEBUG_LOG', true);

// Doesn't force the PHP 'display_errors' variable to be on
define('WP_DEBUG_DISPLAY', false);

// Hides errors from being displayed on-screen
@ini_set('display_errors', 0);

With those lines added to your wp-config.php file, debugging is fully enabled. Here’s an example of a notice that got logged to /wp-content/debug.log for using a deprecated function:

[15-Feb-2011 20:09:14] PHP Notice: get_usermeta is deprecated since version 3.0! Use get_user_meta() instead. in C:CodePluginswordpresswp-includesfunctions.php on line 3237

With debugging enabled, keep a close eye on /wp-content/debug.log as you develop your plugin. Doing so will save you, your users, and other plugin developers a lot of headaches.

How to Log Your Own Debug Statements

So what about logging your own debug statements? Well, the simplest way is to use echo and see the message on the page. It’s the quick-and-dirty-hack way to debug, but everyone has done it one time or another. A better way would be to create a function that does this for you, and then you can see all of your own debug statements in the debug.log file with everything else.

Here’s a function you can use; notice that it only logs the message if WP_DEBUG is enabled:

function log_me($message) {
    if (WP_DEBUG === true) {
        if (is_array($message) || is_object($message)) {
            error_log(print_r($message, true));
        } else {
            error_log($message);
        }
    }
}

And then you can call the log_me function like this:

log_me(array('This is a message' => 'for debugging purposes'));
log_me('This is a message for debugging purposes');

Use the BlackBox Debug Bar Plugin

I only recently discovered this plugin, but it’s already been a huge help as I work on my own plugins. The BlackBox2 plugin adds a thin black bar to the top of any WordPress post or page, and provides quick access to errors, global variables, profile data, and SQL queries.

Clicking on the Globals tab in the bar shows all of the global variables and their values that were part of the request, essentially everything in the $_GET, $_POST, $_COOKIE, $_SESSION, and $_SERVER variables:

The next tab is the Profiler, which displays the time that passed since the profiler was started and the total memory WordPress was using when the checkpoint was reached:

You can add your own checkpoints to the Profiler by putting this line of code anywhere in your plugin where you want to capture a measurement:

apply_filters('debug', 'This is a checkpoint');

Perhaps the most valuable tab in the BlackBox plugin is the SQL tab, which shows you all of the database queries that executed as part of the request. Very useful for determining long-running database calls:

And finally we have the Errors tab, which lists all of the notices, warnings, and errors that occurred during the request:

By providing quick access to essential debug information, the BlackBox plugin is a big-timer when it comes to debugging your WordPress plugin.

Prefix Your Functions

One of the first things that bit me when I started developing WordPress plugins was finding out that other plugin developers sometimes use the same names for functions that I use. For example, function names like copy_file(), save_data(), and database_table_exists() have a decent chance of being used by other plugins in addition to yours.

The reason for this is because when WordPress activates a plugin, PHP loads the functions from the plugin into the WordPress execution space, where all functions from all plugins live together. There is no separation or isolation of functions for each plugin, which means that each function must be uniquely named.

Fortunately, there is an easy way around this, and it’s to name all of your plugin functions with a prefix. For example, the common functions I mentioned previously might now look like this:

function myplugin_copy_file() {
}

function myplugin_save_data() {
}

function myplugin_database_table_exists() {
}

Another common naming convention is to use a prefix that is an abbreviation of your plugin’s name, such as “My Awesome WordPress Plugin”, in which case the function names would be:

function mawp_copy_file() {
}

function mawp_save_data() {
}

function mawp_database_table_exists() {
}

There is one caveat to this, however. If you use PHP classes that contain your functions (which in many cases is a good idea), you don’t really have to worry about clashing with functions defined elsewhere. For example, let’s say you have a class in your plugin named “CommonFunctions” with a copy_file() function, and another plugin has the same copy_file() function defined, but not in a class. Invoking the two functions would look similar to this:

// Calls the copy_file() function from your class
$common = new CommonFunctions();
$common->copy_file();

// Calls the copy_file() function from the other plugin
copy_file();

By using classes, the need to explicitly prefix your functions goes away. Just keep in mind that WordPress will raise an error if you use a function name that’s already taken, so keep an eye on the debug.log file to know if you’re in the clear or not.

Global Paths Are Handy

Writing the PHP code to make your plugin work is one thing, but if you want to make it look and feel good at the same time, you’ll need to include some images, CSS, and perhaps a little JavaScript as well (maybe in the form of a jQuery plugin). And in typical fashion, you’ll most likely organize these files into their own folders, such as “images”, “css”, and “js”.

That’s all well and good, but how should you code your plugin so that it can always find those files, no matter what domain the plugin is running under? The best way that I’ve found is to create your own global paths that can be used anywhere in your plugin code.

For example, I always create four global variables for my plugins, one each for the following:

  • The path to the theme directory
  • The name of the plugin
  • The path to the plugin directory
  • The url of the plugin

For which the code looks like this:

if (!defined('MYPLUGIN_THEME_DIR'))
    define('MYPLUGIN_THEME_DIR', ABSPATH . 'wp-content/themes/' . get_template());

if (!defined('MYPLUGIN_PLUGIN_NAME'))
    define('MYPLUGIN_PLUGIN_NAME', trim(dirname(plugin_basename(__FILE__)), '/'));

if (!defined('MYPLUGIN_PLUGIN_DIR'))
    define('MYPLUGIN_PLUGIN_DIR', WP_PLUGIN_DIR . '/' . MYPLUGIN_PLUGIN_NAME);

if (!defined('MYPLUGIN_PLUGIN_URL'))
    define('MYPLUGIN_PLUGIN_URL', WP_PLUGIN_URL . '/' . MYPLUGIN_PLUGIN_NAME);

Having these global paths defined lets me write the code below in my plugin anywhere I need to, and I know it will resolve correctly for any website that uses the plugin:

$image = MYPLUGIN_PLUGIN_URL . '/images/my-image.jpg';
$style = MYPLUGIN_PLUGIN_URL . '/css/my-style.css';
$script = MYPLUGIN_PLUGIN_URL . '/js/my-script.js';

Store the Plugin Version for Upgrades

When it comes to WordPress plugins, one of the things you’ll have to deal with sooner or later is upgrades. For instance, let’s say the first version of your plugin required one database table, but the next version requires another table. How do you know if you should run the code that creates the second database table?

I suggest storing the plugin version in the WordPress database so that you can read it later to decide certain upgrade actions your plugin should take. To do this, you’ll need to create a couple more global variables and invoke the add_option() function:

if (!defined('MYPLUGIN_VERSION_KEY'))
    define('MYPLUGIN_VERSION_KEY', 'myplugin_version');

if (!defined('MYPLUGIN_VERSION_NUM'))
    define('MYPLUGIN_VERSION_NUM', '1.0.0');

add_option(MYPLUGIN_VERSION_KEY, MYPLUGIN_VERSION_NUM);

I certainly could have simply called add_option('myplugin_version', '1.0.0'); without the need for the global variables, but like the global path variables, I’ve found these just as handy for using in other parts of a plugin, such as a Dashboard or About page.

Also note that update_option() could have been used instead of add_option(). The difference is that add_option() does nothing if the option already exists, whereas update_option() checks to see if the option already exists, and if it doesn’t, it will add the option to the database using add_option(); otherwise, it updates the option with the value provided.

Then, when it comes time to check whether or not to perform upgrade actions, your plugin will end up with code that looks similar to this:

$new_version = '2.0.0';

if (get_option(MYPLUGIN_VERSION_KEY) != $new_version) {
    // Execute your upgrade logic here

    // Then update the version value
    update_option(MYPLUGIN_VERSION_KEY, $new_version);
}

Use dbDelta() to Create/Update Database Tables

If your plugin requires its own database tables, you will inevitably need to modify those tables in future versions of your plugin. This can get a bit tricky to manage if you’re not careful, but WordPress helps alleviate this problem by providing the dbDelta() function.

A useful feature of the dbDelta() function is that it can be used for both creating and updating tables, but according to the WordPress codex page “Creating Tables with Plugins”3, it’s a little picky:

  • You have to put each field on its own line in your SQL statement.
  • You have to have two spaces between the words PRIMARY KEY and the definition of your primary key.
  • You must use the keyword KEY rather than its synonym INDEX and you must include at least one KEY.

Knowing these rules, we can use the function below to create a table that contains an ID, a name, and an email:

function myplugin_create_database_table() {
    global $wpdb;
    $table = $wpdb->prefix . 'myplugin_table_name';

    $sql = "CREATE TABLE " . $table . " (
              id INT NOT NULL AUTO_INCREMENT,
              name VARCHAR(100) NOT NULL DEFAULT '',
              email VARCHAR(100) NOT NULL DEFAULT '',
              UNIQUE KEY id (id)
              );";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

Important: The dbDelta() function is found in wp-admin/includes/upgrade.php, but it has to be included manually because it’s not loaded by default.

So now we have a table, but in the next version we need to expand the size of the name column from 100 to 250. Fortunately dbDelta() makes this straightforward, and using our upgrade logic previously, the next version of the plugin will have code similar to this:

$new_version = '2.0.0';

if (get_option(MYPLUGIN_VERSION_KEY) != $new_version) {
    myplugin_update_database_table();
    update_option(MYPLUGIN_VERSION_KEY, $new_version);
}

function myplugin_update_database_table() {
    global $wpdb;
    $table = $wpdb->prefix . 'myplugin_table_name';

    $sql = "CREATE TABLE " . $table . " (
              id INT NOT NULL AUTO_INCREMENT,
              name VARCHAR(250) NOT NULL DEFAULT '', // Bigger name column
              email VARCHAR(100) NOT NULL DEFAULT '',
              UNIQUE KEY id (id)
              );";

    require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
    dbDelta($sql);
}

While there are other ways to create and update database tables for your WordPress plugin, it’s hard to ignore the flexibility of the dbDelta() function.

Know the Difference Between include, include_once, require, and require_once

There will come a time during the development of your plugin where you will want to put code into other files so that maintaining your plugin is a bit easier. For instance, a common practice is to create a functions.php file that contains all of the shared functions that all of the files in your plugin can use.

Let’s say your main plugin file is named myplugin.php and you want to include the functions.php file. You can use any of these lines of code to do it:

include 'functions.php';
include_once 'functions.php';

require 'functions.php';
require_once 'functions.php';

But which should you use? It mostly depends on your expected outcome of the file not being there.

  • include: Includes and evaluates the specified file, throwing a warning if the file can’t be found.
  • include_once: Same as include, but if the file has already been included it will not be included again.
  • require: Includes and evaluates the specified file (same as include), but instead of a warning, throws a fatal error if the file can’t be found.
  • require_once: Same as require, but if the file has already been included it will not be included again.

My experience has been to always use include_once because a) how I structure and use my files usually requires them to be included once and only once, and b) if a required file can’t be found I don’t expect parts of the plugin to work, but it doesn’t need to break anything else either.

Your expectations may vary from mine, but it’s important to know the subtle differences between the four ways of including files.

Use bloginfo(‘wpurl’) Instead of bloginfo(‘url’)

By and large, WordPress is installed in the root folder of a website; it’s standard operating procedure. However, every now and then you’ll come across websites that install WordPress into a separate subdirectory under the root. Seems innocent enough, but the location of WordPress is critically important.

To demonstrate, in the “General Settings” section of the WordPress admin panel, you’ll find the “WordPress address (URL)” and “Site address (URL)” settings, and for sites where WordPress is installed into the root directory, they will have the exact same values:

But for sites where WordPress is installed into a subdirectory under the root (in this case a “wordpress” subdirectory), their values will be different:

At this stage it’s important to know the following:

  • bloginfo(‘wpurl’) equals the “WordPress address (URL)” setting
  • bloginfo(‘url’) equals the “Site address (URL)” setting

Where this matters is when you need to build URLs to certain resources or pages. For example, if you want to provide a link to the WordPress login screen, you could do this:

// URL will be http://mydomain.com/wp-login.php
<a href="<?php bloginfo('url') ?>/wp-login.php">Login</a>

But that won’t resolve to the correct URL in the scenario such as the one above where WordPress is installed to the “wordpress” subdirectory. To do this correctly, you must use bloginfo('wpurl') instead:

// URL will be http://mydomain.com/wordpress/wp-login.php
<a href="<?php bloginfo('wpurl') ?>/wp-login.php">Login</a>

Using bloginfo('wpurl') instead of bloginfo('url') is the safest way to go when building links and URLs inside your plugin because it works in both scenarios: when WordPress is installed in the root of a website and also when it’s installed in a subdirectory. Using bloginfo('url') only gets you the first one.

How and When to Use Actions and Filters

WordPress allows developers to add their own code during the execution of a request by providing various hooks. These hooks come in the form of actions and filters:

  • Actions: WordPress invokes actions at certain points during the execution request and when certain events occur.
  • Filters: WordPress uses filters to modify text before adding it to the database and before displaying it on-screen.

The number of actions and filters is quite large, so we can’t get into them all here, but let’s at least take a look at how they are used.

Here’s an example of how to use the admin_print_styles action, which allows you to add your own stylesheets to the WordPress admin pages:

add_action('admin_print_styles', 'myplugin_admin_print_styles');

function myplugin_admin_print_styles() {
    $handle = 'myplugin-css';
    $src = MYPLUGIN_PLUGIN_URL . '/styles.css';

    wp_register_style($handle, $src);
    wp_enqueue_style($handle);
}

And here’s how you would use the the_content filter to add a “Follow me on Twitter!” link to the bottom of every post:

add_filter('the_content', 'myplugin_the_content');

function myplugin_the_content($content) {
    $output = $content;
    $output .= '<p>';
    $output .= '<a href="http://twitter.com/username">Follow me on Twitter!</a>';
    $output .= '</p>';
    return $output;
}

It’s impossible to write a WordPress plugin without actions and filters, and knowing what’s available to use and when to use them can make a big difference. See the WordPress codex page “Plugin API/Action Reference”4 for the complete list of actions and the page “Plugin API/Filter Reference”5 for the complete list of filters.

Tip: Pay close attention to the order in which the actions are listed on its codex page. While not an exact specification, my experimentation and trial-and-error has shown it to be pretty close to the order in which actions are invoked during the WordPress request pipeline.

Add Your Own Settings Page or Admin Menu

Many WordPress plugins require users to enter settings or options for the plugin to operate properly, and the way plugin authors accomplish this is by either adding their own settings page to an existing menu or by adding their own new top-level admin menu to WordPress.

How to Add a Settings Page

A common practice for adding your own admin settings page is to use the add_menu() hook to call the add_options_page() function:

add_action('admin_menu', 'myplugin_admin_menu');

function myplugin_admin_menu() {
    $page_title = 'My Plugin Settings';
    $menu_title = 'My Plugin';
    $capability = 'manage_options';
    $menu_slug = 'myplugin-settings';
    $function = 'myplugin_settings';
    add_options_page($page_title, $menu_title, $capability, $menu_slug, $function);
}

function myplugin_settings() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Here is where you could start displaying the HTML needed for the settings
    // page, or you could include a file that handles the HTML output for you.
}

By invoking the add_options_page() function, we see that the “My Plugin” option has been added to the built-in Settings menu in the WordPress admin panel:

The add_options_page() function is really just a wrapper function on top of the add_submenu_page() function, and there are other wrapper functions that do similar work for the other sections of the WordPress admin panel:

  • add_dashboard_page()
  • add_posts_page()
  • add_media_page()
  • add_links_page()
  • add_pages_page()
  • add_comments_page()
  • add_theme_page()
  • add_plugins_page()
  • add_users_page()
  • add_management_page()

How to Add a Custom Admin Menu

Those wrapper functions work great, but what if you wanted to create your own admin menu section for your plugin? For example, what if you wanted to create a “My Plugin” admin section with more than just the Settings page, such as a Help page? This is how you would do that:

add_action('admin_menu', 'myplugin_menu_pages');

function myplugin_menu_pages() {
    // Add the top-level admin menu
    $page_title = 'My Plugin Settings';
    $menu_title = 'My Plugin';
    $capability = 'manage_options';
    $menu_slug = 'myplugin-settings';
    $function = 'myplugin_settings';
    add_menu_page($page_title, $menu_title, $capability, $menu_slug, $function);

    // Add submenu page with same slug as parent to ensure no duplicates
    $sub_menu_title = 'Settings';
    add_submenu_page($menu_slug, $page_title, $sub_menu_title, $capability, $menu_slug, $function);

    // Now add the submenu page for Help
    $submenu_page_title = 'My Plugin Help';
    $submenu_title = 'Help';
    $submenu_slug = 'myplugin-help';
    $submenu_function = 'myplugin_help';
    add_submenu_page($menu_slug, $submenu_page_title, $submenu_title, $capability, $submenu_slug, $submenu_function);
}

function myplugin_settings() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Render the HTML for the Settings page or include a file that does
}

function myplugin_help() {
    if (!current_user_can('manage_options')) {
        wp_die('You do not have sufficient permissions to access this page.');
    }

    // Render the HTML for the Help page or include a file that does
}

Notice that this code doesn’t use any of the wrapper functions. Instead, it calls add_menu_page() (for the parent menu page) and add_submenu_page() (for the child pages) to create a separate “My Plugin” admin menu that contains the Settings and Help pages:

One advantage of adding your own custom menu is that it’s easier for users to find the settings for your plugin because they aren’t buried within one of the built-in WordPress admin menus. Keeping that in mind, if your plugin is simple enough to only require a single admin page, then using one of the wrapper functions might make the most sense. But if you need more than that, creating a custom admin menu is the way to go.

Provide a Shortcut to Your Settings Page with Plugin Action Links

In much the same way that adding your own custom admin menu helps give the sense of a well-rounded plugin, plugin action links work in the same fashion. So what are plugin action links? It’s best to start with a picture:

See the “Deactivate” and “Edit” links underneath the name of the plugin? Those are plugin action links, and WordPress provides a filter named plugin_action_links for you to add more. Basically, plugin action links are a great way to add a quick shortcut to your most commonly used admin menu page.

Keeping with our Settings admin page, here’s how we would add a plugin action link for it:

add_filter('plugin_action_links', 'myplugin_plugin_action_links', 10, 2);

function myplugin_plugin_action_links($links, $file) {
    static $this_plugin;

    if (!$this_plugin) {
        $this_plugin = plugin_basename(__FILE__);
    }

    if ($file == $this_plugin) {
        // The "page" query string value must be equal to the slug
        // of the Settings admin page we defined earlier, which in
        // this case equals "myplugin-settings".
        $settings_link = '<a href="' . get_bloginfo('wpurl') . '/wp-admin/admin.php?page=myplugin-settings">Settings</a>';
        array_unshift($links, $settings_link);
    }

    return $links;
}

With this code in place, now when you view your plugins list you’ll see this:

Here we provided a plugin action link to the Settings admin page, which is the same thing as clicking on Settings from our custom admin menu. The benefit of the plugin action link is that users see it immediately after they activate the plugin, thus adding to the overall experience.

Additional Resources

I’ve covered a lot in this article, but there’s plenty more out there to keep you busy awhile. The most comprehensive documentation for WordPress plugin development can be found on the WordPress Codex6, a huge collection of pages documenting everything that is WordPress. Below are some of the more pertinent links from the codex you’ll need:

I also suggest reading Joost de Valk’s article “Lessons Learned From Maintaining a WordPress Plug-In12“, which provides more good tips on WordPress plugin development.

(vf) (ik)

↑ Back to topShare on Twitter

Dave lives in Columbus, OH and is one of the founders of Max Foundry, a company that makes WordPress plugins for landing pages, squeeze pages, sales pages, and A/B testing. You can follow Dave on Twitter and on his blog, where he writes about living the bootstrapped startup life.

  1. 1

    Great insights Dave. I loved the way you have pointed out the things that any developer that needs to keep track of. Thanks for sharing.

    2
  2. 2

    Intersting stuff about adding a custom menu and a settings page :D great post Dave.

    0
  3. 3

    Great article Dave! This will really help out my future endeavors with WordPress plugin development. Thanks for sharing!

    3
  4. 4

    This is brilliant, thanks for the write up. Bookmarked! I see that you recommend the Blackbox debug plugin. Having just started creating my own plugins, why this and not the DebugBar plugin (http://wordpress.org/extend/plugins/debug-bar/)? What’s the primary difference?

    0
    • 5

      @David – I didn’t include the DebugBar plugin because it requires WordPress 3.1, which was only in Release Candidate mode at the time of writing. Both plugins provide similar debug info, so I suggest trying both and going with the one you like best.

      1
  5. 6

    Great advices! I wish it would have been released much earlier – could have saved me a lot of time and trouble :)

    Regarding bloginfo(wpurl): The codex says to use site_url() instead, for it also supports https, eg. if is_ssl() is true.

    0
    • 7

      @Chris – I can’t find the codex article that says to use site_url() instead of bloginfo(‘wpurl’), but yes, I suppose you could do that. There seems to be some confusion about whether or not site_url() includes the install directory of WordPress (if installed in a subdirectory), but looking at the core WordPress code it looks like it does.

      0
  6. 9

    Nice article, thanks for sharing. I especially like the notes on debugging & function prefixes. Hopefully this will change the coding habits of some Developers when writing a WP plugin.

    1
  7. 10

    Another awesome and well described tutorial Dave! I especially love how concise the part about creating admin settings panel and menu.

    Cheers,

    0
  8. 11

    Thomas Bachmann

    March 8, 2011 6:55 am

    thanks!
    … if you are a trained professional developer and familiar with PHP only half of it should be new (wordpress specifics)

    0
  9. 12

    Great stuff! Very useful thought.

    0
  10. 13

    Precise and short; good, clear checkpoints!

    0
  11. 14

    Samundra Shrestha

    March 8, 2011 7:33 am

    Really loved the way you have mentioned the tricks for wordpress developer. I liked the way you described the usuage of require, require_once, include and include_once. All most of us use them but never seem to care since we all use include_once most of the time :).

    I have already been using some of the tricks you have mentioned.

    Great Article.

    best regards,
    Samundra Shrestha
    Realtime Solutions, Nepal

    -3
  12. 15

    Great post. It makes me want to write a plugin! :)

    0
  13. 16

    Joseph Carrington

    March 8, 2011 7:37 am

    Good stuff. I’d point out that using a class as a fill-in for a namespace is not exactly the intention of OOP however.

    0
    • 17

      @Joseph Carrington – You’re right, using classes as a namespace fill-in is not the intention of OOP, but it is a common practice for avoiding function name collisions in PHP and WordPress.

      0
  14. 18

    Great info! I wasn’t aware of the bloginfo(‘wpurl’) vs. bloginfo(‘url’) difference.

    0
  15. 19

    Really enjoyed this. It was encouraging that I found I was already doing most of these things. Some good tips, though, and I’ve updated my plugin with some of these suggestions.

    I tried blackbar, but got tons of deprecated errors, which kind of made me laugh…

    0
  16. 21

    Thanks for so much, getitng started with plugin development and wordpress theme development, and this article help me a lot in knowing many things that i do not know

    1
  17. 22

    Great article, very informative without straying too far down rabbit trails. Thanks.

    0
  18. 23

    Hi,
    Using blackbox-debug-bar with wp_debug on true display a bunch of notices, not very good for developping :/

    0
    • 24

      @Raherian – But that’s kind of the point of enabling debugging in the first place, to see all of the notices you wouldn’t have otherwise known were there.

      0
      • 25

        Yes but this plugin is usefull for developping, and i develop with wp_debug true, so having a bunch of notices while developping isn’t good.
        It were a good idea to make a plugin available on repository only if he doesn’t have any notices, like themes ^^

        1
  19. 26

    So far I developed only two themes, both of them using different methods (or no method apart from “hope it will work”)

    it seems that these 10 plugins will make the process much easier to manage and hopefully to be able to understand by things work – that way things could stick in the head when developing the next theme

    thanks

    0
  20. 27

    Nice article, Dave. I don’t know if there is a codex article on using site_url() but this article has some good tips on guarding for ssl: http://blogs.sitepoint.com/2011/02/22/crimes-against-wordpress/

    0
  21. 28

    Great article. One of my biggest hurdles is debugging my plugins properly and these tips are outstanding. I usually use firephp to see what’s going on with the variables being passed back and fourth. Such an invaluable tool.

    0
  22. 29

    Great post. I’ll have to try blackbar in my future projects.

    I was also _just_ looking for a tutorial on adding menu items when I found this gem.

    Thanks again,
    Conrad

    0
  23. 30

    Great article, but I am a little sad that i18n wasn’t contemplated from the beginning for all those strings, i.e.

    $page_title = __('My Plugin Settings', 'myplugin_textdomain');
    instead of
    $page_title = 'My Plugin Settings';

    It’s great for all other languages to have plugins that are translatable from the get go.
    http://codex.wordpress.org/I18n_for_WordPress_Developers

    1
    • 31

      @Ze – I mentioned on another comment that I thought about including internationalization but decided against it for this article. The topic is probably big enough for another article on its own, so maybe I’ll write that one next.

      1
  24. 32

    Thanks for the lead on Blackbox!. I installed it mid-read on your post and played with it for 30 minutes on three of my sites. Then I remember I was reading your post so I came back to finish. Great roundup!

    0
  25. 33

    one very common problem from US writers missing – forgotting internationalization so __(), _x(), _e() functions etc.

    0
    • 34

      @Tomas – I thought about including a section on internationalization, but decided against it for this article. Maybe I’ll write another article just for that.

      0
  26. 35

    This is great :)

    Thank you so much.

    0
  27. 36

    Thanks for this great. This is awesome !

    0
  28. 37

    Patent Litigation

    March 8, 2011 10:03 pm

    Here is a similar story

    Until recently, migrating all your blogs to a single multisite blog was a massive task because of the need to resolve conflicting IDs across different tables. Fortunately, newer WordPress versions have built-in functions to make life a bit easier for all of us.

    0
  29. 38

    As a customer of WordPress plugins, my biggest gripe is the lack of screenshots displaying what the plugin does. Is it really that hard to grab screens? Great you’ve made this fantastic plugin, and also great that you’ve put it up for free, just telling me what it does, isn’t going to completely sell me on it.
    Screenshots, do it.

    1
  30. 39

    I wish every single plugin developer followed these simple rules!
    It would make life a little bit easier

    0
  31. 40

    This is a great article. Thanks for consolidating all of this information instead of making me search everywhere for it!

    0
  32. 41

    Dave, Awesome post. Pretty helpful for green-hands like me for wordpress.
    Usually we use netbeans and X-debug for debugging. This time we could try blackbox for help :)

    One question: How do you do unit test for new built WP plugin? Use PHPUnit or something else? I am quite new to the test procedure of PHP, any help will be much appreciated.

    0
  33. 42

    Thanks a lot for this great article Dave !

    0
  34. 43

    One thing that you have understand about include vs include_once, require vs require_once is performance penalty.

    If you develop your code, and you are 100% for sure, that after you included your file in following code it wont be included again, never use *_once functions. They are more resource eating that simple include or require.

    Read this article to understand difference in C level:
    http://www.techyouruniverse.com/software/php-performance-tip-require-versus-require_once

    0
  35. 44

    Fernando Agüero

    March 9, 2011 1:42 am

    One of the best post written in Smashing Magazine. Now I have no doubts.

    Thank you!

    0
  36. 45

    Great you’ve made this fantastic plugin, and also great that you’ve put it up for free.It seems that these 10 plugins will make the process much easier to manage and hopefully to be able to understand by things. Thanks for give us this information.

    0
  37. 46

    Great you’ve made this fantastic plugin, and also great that you’ve put it up for free.It seems that these 10 plugins will make the process much easier to manage and hopefully to be able to understand by things. Thanks for this useful knowledge..

    0
  38. 47

    A very important topic that is missing here is Data Validation.
    http://codex.wordpress.org/Data_Validation

    0
  39. 48

    One bad thing was described above.
    When webmaster changes wp-content directory name, following code will break the site:
    define('MYPLUGIN_THEME_DIR', ABSPATH . 'wp-content/themes/' . get_template());
    You should use following code instead wrong one:
    define('MYPLUGIN_THEME_DIR', WP_CONTENT_DIR . 'themes/' . get_template());

    2
    • 49

      @Max – Good point, thanks for catching that. Using WP_CONTENT_DIR instead of a hardcoded ‘wp-content’ string would be better.

      0
    • 50

      Thanks for pointing this out, I 100% concur – every WP install I do, I move the wp-content to site root, so i wind up with a nice structure like:
      /themes
      /plugins
      /wordpress
      /index.php

      Developers should definitely utilize WP_PLUGIN_DIR and WP_CONTENT_DIR. Google either of those terms for more info on how to leverage them.

      0
  40. 51

    And please: do NOT fill the front-end HTML with plugin-specific CSS/jQuery/meta crap without a way to properly erase them if it is not required. I code my own front-end markup and i’m tired to see jQuery/Prototype/Mootools included everytime I use a plugin…

    PLEASE!

    0
  41. 52

    catalin cimpanu

    March 9, 2011 4:49 am

    Hell of a job on this article.

    0
  42. 53

    Although my current WordPress blogs have some of the SeO plugins installed I have found a good tips on your list that I must to follow

    0
  43. 54

    Good WordPress summary to develop a WordPress plugin.
    Great work and good explanations!

    0
  44. 55

    Douglas Bonneville

    March 9, 2011 11:47 am

    Dave: Great article – I’m going to give making a plugin a shot pretty soon and I’ll start here. I’ve edited a few, but this outline really lowers the threshold to new development. This is one of the best WordPress articles I’ve seen in a while, and certainly on my list of top articles at Smashing!

    0
  45. 56

    Thanks for your post, it’s very helpful for my daily work and thoughts.

    0
  46. 57

    Seriously why is everybody still using wordpress its the biggest crap of code i ever seen, its like IE6 under the browsers…

    -1
  47. 58

    Christian K. Nordtømme

    March 10, 2011 2:29 am

    Thanks for this. I’m just now learning how to develop my own plugins, and have bookmarked this post.

    I also wish more plugin developers made the plugin’s documentation and help easier accessible, though.

    I don’t think digging up readme files from the plugin folder, rummaging through every page on the author’s website or trying to decipher the code in search of basic answers should be neccessary. Instead, a “Quick Start” action link (either to 100% self-explanatory settings or to a readme file) should be standard.

    0
  48. 59

    This is superuseful article! In-depth yet still accessible for occassional developers. Much better than “25 nice inspirational designs in pink” or “100 beautiful photos of furry pets” type stuff…

    0
  49. 60

    excellent post… stumbled.. :)

    0
  50. 61

    these articles are getting lamer and lamer

    0
  51. 62

    Thanks for sharing this post.I like this post.It contains good examples of wordpress plugin developer should know.

    0
  52. 63

    I really appreciate your posting. Thanks.

    There is one issue I’ld like to add: localization.
    I have to translate all kinds of plugins and that can be a really annoying waste of time, if a plugin is not meant to be localized.

    0
  53. 64

    Great post. Really helps a lot. But need to ask something. I saw this effect on a recently launched blog with wp posts coming in like a js gallery slider.

    http://sputznik.com/

    How have they achieved this transition and post thing? Is there a plugin that I could use? Thanks for the help.

    0
    • 65

      @Rahul – It looks like that transition is done with jQuery and the easing plugin for jQuery. Just give it a quick Google and you’ll find what you need.

      0
  54. 67

    Manny Fleurmond

    March 13, 2011 9:26 pm

    I also recommend using the plugins_url() function to find your plugins base directory:
    http://codex.wordpress.org/Function_Reference/plugins_url

    0
  55. 68

    This is a great post. Thanks for bringing it all together in one place.

    0
  56. 69

    Great article! Particularly the part about using wp_debug is a must-read for every plugin developer.
    By the way, just wanted to point out that there is a function wp_login_url() for login url. People should use this, because some plugins may modify it with filter that is inside it and bloginfo(‘wpurl’) . “/wp-login.php” is not necessary the right login URL.

    0
    • 70

      @Valentinas – Good catch about the wp_login_url() function, thanks for pointing that out.

      0
  57. 71

    Awesome post. 9 of 10 i’ve found extremely interesting and enlightening…

    I’d just like to query the tip: “Use bloginfo(‘wpurl’) Instead of bloginfo(‘url’)”. I believe this is bad advice.

    When developing a WordPress website, developers may be forced to work in a live environment with a holding page in place. If you use ‘wpurl’ in your themes/plugins, this will fail, as you will need to rename index.php and point ‘siteurl’ to the index page to have the website up for development.

    If all of your internal links are output with the ‘wpurl’ parameter, these will link to your holding page and you will have to type permalinks into your browser manually instead of clicking on links within the website.

    0
  58. 72

    This is a great article for anyone wanting to develop a WordPress plugin. Hopefully it will lead to some brilliant plug-ins which will enrich the WordPress community even more.

    Thanks Dave!

    1
  59. 73

    This is a great list, but one thing that every WordPress developer should know about (more important than knowing about require_once() etc) is nonces. Nonces are a very important part of WordPress that help to combat security problems and should definitely be on this list.
    http://codex.wordpress.org/WordPress_Nonces

    0
  60. 74

    One thing every WordPress plugin developer should do is NOT include default styles for their generated HTML. Doing so means reverse engineering for other WordPress developers. If you do add default styles, add in the option to deactivate the CSS.

    0
  61. 75

    Nothing about wp_enqueue_script()?

    1
  62. 76

    Permana Jayanta

    March 15, 2011 6:40 pm

    Really helpful post as I’m writing WordPress plugin now. Maybe should added list of functions that can help plugin development, instead of writing a functions again.

    0
  63. 77

    Thank you.. superb.. !!! its really helpful…

    1
  64. 78

    Sterling Hamilton

    April 9, 2011 11:15 am

    Hey there!

    A few things…

    In regards to dbDelta:
    “require_once(ABSPATH . ‘wp-admin/includes/upgrade.php’);”

    That means you are now including a core WP file into your plugin…not really recommended. Further more, by doing that – it will start throwing aggressive cache busting headers. This will get in the way of caching plugins and proxies.

    Also – rather than prefixing every function, it’s better to just do an Object in PHP and give that a unique name. That way prefixing is not needed – just a unique object name.

    And the BlackBox plugin has been known to drastically slow down servers, so it should not be used in any sort of production environment.

    Also – you want to load your plugins meta data rather than creating your own. So version number/plugin path/etc are able to be loaded like this: https://gist.github.com/911684

    Another really good tip…do NOT rely on environment variables like HTTP_HOST, REQUEST_URI and such.

    These tend to be unreliable – its best to use the wordpress variables for determining locations and what not.

    0
  65. 79

    Because of the topic the “Objective Best Practices for Plugin Development?” on http://wordpress.stackexchange.com/questions/715/objective-best-practices-for-plugin-development is also a good addition.

    Maybe to add to the debugging part: I also found using Zend Server community edition together with PHP PDT increase my debugging abilities (I dumped xampp for it).

    For making names unique well… I use php 5.3 with namespaces -end of problem- the language solves it for me. So I just state “this plugin is only for php 5.3 onwards” (although some discussion exist on “only 5.3″ http://groups.google.com/group/wp-hackers/browse_thread/thread/19dc7c7197f66754/9a60ad0b37ccaf1b?show_docid=9a60ad0b37ccaf1b&pli=1)

    0
  66. 80

    rule #1 wordpress is coded badly you will not learn anything about design patterns or best practices from looking at the wordpress source code, use your initiative ;)

    0
  67. 81

    Thanks for these really awesome tips! They will be really helpful.

    -2
  68. 82

    Nice tips. I’m currently writing my first plugin and it helped me a lot especially for the upgrade system.

    2
  69. 83

    Really nice things to keep in mind and great for beginners exploring the deep depths of wordpress plugin development!
    Thanks!

    0
  70. 84

    Hi thanks for the tip, I just notice in Settings link, I think there is the better way to declare setting link.

    something like this
    $settings_link = ‘Settings‘;

    Ryan S

    0
  71. 86

    thanks dude!

    0
  72. 87

    Good stuff!

    0
  73. 88

    Great article. Being new to WP development, this is really helpful. Even for those of us struggling to tweak plugins we use.

    0
  74. 89

    Thanks Dave,

    These are fantastic tips to start quality plugin development. Please keep up the good work!
    Much appreciated.

    Cheers,
    Manuel

    0
  75. 90

    Clear and well-written – you’ve allowed me to understand php even in the middle of the night….
    thanks

    0
  76. 91

    Hello,
    a really really good tutorial.
    Thanks

    0
  77. 92

    Thanks for the article. The menu stuff in particular was very helpful.

    I’d add 11): Understand how/when WordPress loads things. This flow chart of what happens during a WP request cycle is pretty illuminating: http://www.rarst.net/script/wordpress-core-load/

    Couple of other handy flow charts linked from that page as well in particular this chart that explains WP Query Functions http://www.rarst.net/script/wordpress-query-functions/

    0
  78. 93

    i have developed a plugin for paggination along with a shortcode but the output is showing in dashboad and when adding shortcode in any pages then it displays output in pages.
    Kindly suggest how to hide the output from dashbord.

    Thank You in advance

    0
  79. 94

    Good post. I learn something totally new and challenging on blogs I stumbleupon on a daily basis. It will always be helpful to read through content from other authors and use something from their sites.

    0

↑ Back to top