Function Documentation

WordPress Function Documentation Progress

Writing WordPress Widget Best Practices

Don’t Nest Functions

It appears to be a neat trick, but that is all it is. A hack that you should avoid and just because you can do it and it works does not give reason to do so. There are many programming practices that you can use in PHP, but must not. The only exception was, if you were the only one that is going to see it and it was an exercise of academics. Aside from that, the common widget practice of nesting functions inside of functions should be halted.

Example of Wrong Widget Form

function myplugin_widget_init()
{

    function myplugin_widget_display($args)
    {
        
    }

    function myplugin_widget_control()
    {
        
    }

    // Register myplugin_widget_display() and myplugin_widget_control()
}

The problems with this code are listed below.

  1. Class structure would be the most logical alternative.

    The simple containment of the functions is easily accomplished using a class container. I’m unsure what the appeal of this form, but if the need to contain the three functions, than a class should have been used instead.

    I have an theory, that the first one to use this pattern knew what he/she was doing and thought it would be cool and didn’t realize that everyone else would use it as an example. Everyone else that came after noticed that it worked (mysteriously) and decided that it was easier than learning OOP. However, this theory is unproven, so whatever the reason, a class would have been a better and wiser choice.

  2. Prevents Opcode Caching optimization.

    PHP will not compile the two functions contained in myplugin_widget_init() until that function is called. By halting the compile process, some one using an Opcode Cache will not receive the boost. Furthermore, PHP will not know in most cases whether it will need to continue to cache the two functions, so at the best case the functions will be cached after the function is called and at the worst case, it will have to compile the two functions with each process.

  3. Causes fatal duplicated function definitions.

    In the event that myplugin_widget_init() is called twice, it will cause PHP to try to compile the contained functions twice. This will fail, because PHP already compiled the functions when the function was called the first time. The reason you won’t have a third call is that the second call will bring PHP and WordPress crashing down.

Widget Best Practice: Using the Object Pattern

class myplugin_widget
{
    function init()
    {
        // Register myplugin_widget::display() and myplugin_widget::control()
    }

    function display()
    {
        // Echo content
    }

    function control()
    {
        // Echo administration control
    }
}

I like keeping functionality contained together. Some plugins choose to dump all functionality into the same object, I would advise against this, but if it is easier for you, then just use functions instead until you learn OOP better.

Widget Best Practice: Using Functions

function myplugin_widget_init()
{
    // Register myplugin_widget::display() and myplugin_widget::control()
}

function myplugin_widget_display()
{
    // Echo content
}

function myplugin_widget_control()
{
    // Echo administration control
}

This code is far nicer looking and contained and has none of the disadvantages listed above.

February 4, 2008 Posted by | Writing Plugins Series | , , | 1 Comment

Shortcodes API

WordPress 2.5 adds the ability to register bbcode style formats in plugins for post content only. I have a plugin that converts language specific bbcodes to genshi style. It however parses the content manually. Using the new API, it only needs to register each language or a single name and use an attribute for each language.

The functions for plugins are add_shortcode() and remove_shortcode(). The functions exist in wp-includes/shortcodes.php and offer a basic functionality. Overall, the addition will decrease the hassles of plugin authors and unify the standard of replacing short tags that a lot of plugins use in their plugins. This will be a great boon for plugin authors.

How to Add a Shortcode

Lets say that we want to support the bbcode code ‘b’ and add support for it in post content. We would first register the ‘b’ short code with the function which which will replace the ‘[b]’ and ‘[/b’] with ‘<‘ and ‘>’ respectively.

function bbcodeplugin_b($attr, $content='')
{
    if( empty( $content ) )
    {
        return '';
    }

    return '<strong>'. $content .'</strong>';
}

add_shortcode('b', 'bbcodeplugin_b');

The first parameter catches any attributes that the user might have added between the “[b …]content[/b]” that will be caught and given to your plugin function.

In the example of using geshi, lets create a plugin short code which, in theory, will allow any number of languages to be converted to geshi styles.

function genshiplugin_genshi($attr, $content='')
{
    if( empty( $content ) )
    {
        return '';
    }

    return genshi_conversion_function_or_method($attr['lang'], $content);
}

remove_shortcode('genshi');

add_shortcode('genshi', 'genshiplugin_genshi');

In this example, we remove any plugin that might have registered their own and replace it with our function instead. If you are going to create something that is generally generic, then it is a good idea to choose something that either has your plugin name or in the case of the above example used a generic ‘code’, so that the user doesn’t have to go through all post content to replace the bbcode style to switch over to your plugin. However, if the user wants to use multiple methods, then let the user decide with an option.

Most Common Replacement

Many plugins replace a “tag” in the content with their own content or run a special filter and add forms or pictures or any number of special content. Many plugins build their own regular expressions to process the content to look for the content. With the short code API, this is no longer necessary.

If I wanted to replace every instance of “[myplugin]” with “My Plugin is Awesome”. I can use the above examples and just return the “My Plugin is Awesome”.

function myplugin_is_awesome($attr)
{
    return 'My Plugin is Awesome';
}

add_shortcode('myplugin', 'myplugin_is_awesome');

Adding Shortcode to more filters

The default filter (as of this writing, it might be added to more when 2.5 is released), is ‘the_content’, but you might want to apply the code to comments and excerpts or any other filter. As a warning, some plugins might register codes which might make it unsafe to be used in comments, so be careful with what is exactly registered and confirmed with comments.

add_filter('the_excerpt', 'do_shortcode');

Or if you don’t want to use short codes, add the following to a plugin.

remove_filter('the_content', 'do_shortcode');

How Fast is Shortcode?

The API is extremely optimized and fast for what it does. It is doubtful that it can be optimized any further and barring any defects, it probably will stay quick. It also appears that it doesn’t use the built-in plugin API, so that means that one function can exist for each shortcode. You won’t be able to run a ‘code’ shortcode tag through two or more filters, only one can exist for the short code. This decreases the time spent, but removes one of the best features in the Plugin API.

February 3, 2008 Posted by | Writing Plugins Series | , , , | 9 Comments

Replacing WordPress Object Caching

The WordPress Object Cache changed in WordPress 2.5 and removed a lot of file support from the code. This means that the Object Cache in WordPress 2.5 is completely dependent on memory and will not be saved to disk for retrieval later. The constant WP_CACHE also changed its meaning.

WP_CACHE Constant

In WordPress versions prior to 2.5 release, there were two constants that were used. One always enabled the cache and the other always disabled the cache. However, confusion was caused by both the constant values being booleans. In WordPress 2.5, those old constants were removed and a new one is used instead.

Normally, the WP_CACHE constant does not exist in wp-config.php. If it does exist, then it means that there is a file in wp-content folder named advanced-cache.php. This file, if it exists will be included (not to be confused with required, meaning that if it isn’t there and you remove it, it won’t halt the WordPress execution) and a function called wp_cache_postload(), if it exists.

The way to disable the WordPress cache is to define another cache, also in the wp-content folder, called object-cache.php. However, the functions that are used by WordPress still need to be defined in the file. Mostly, if you return false, then WordPress will just retrieve from the database, which will decrease performance.

When you write a plugin which uses advanced-cache.php, make sure you include code which writes the WP_CACHE constant to the wp-config.php file for the user, in case they don’t have enough experience manipulating files themselves.

Note: the value inside of WP_CACHE is not important, what is important is that the constant is defined. So in theory, you can use:

define('WP_CACHE', '');

But in practice, it is better to set the value to true instead:

define('WP_CACHE', true);

advanced-cache.php File

In theory, the advanced-cache.php file is useful if you wish to save the output of the WordPress pages through the use of wp_cache_postload() function. There are other purposes that can be handled through the wp_cache_postload() function, but that is up to you the plugin developer to decide.

This file is optional, only the next file is required to replace the internal WordPress Object Cache.

object-cache.php File

You are replacing a file that has definitions used by WordPress, so you must also define those functions in your file and handle the cache using whatever method that you will be using the same way that the internal WordPress cache does.

This means that when wp_cache_get() is called, if the cached object does not exist, then you return false. If it does exist, then you return the object. The same way with other replaced functions.

What you would put in this file is Memcache implementation, or file based caching, or some other custom solution. The full implementation should go in this file and there can only be one caching implementation used at a time.

January 30, 2008 Posted by | Writing Plugins Series | , , , | 1 Comment

Writing Plugins: Including an Uninstaller

I think the central issue is that, plugin developers think writing an uninstaller is difficult, but it is not. I’ve been doing it for quite a while in my private WordPress plugins. It was quite easy. I think that the few plugins which do implement it, do so in a way that over complicates it for other novice users.

  1. Activation Step

    The core simple concept is to have an option that tells your plugin whether the plugin should be uninstalled or not. If you add options anyway, then this isn’t to difficult.

  2. Deactivation Step

    The second concept is to check that option during the deactivation and then if it is set to true, then you remove everything that you added in the activation step.

  3. Plugin Option Administration

    I think this is where novice plugin authors get tripped up and most other people. If you already have an options page, then it should be simple to add a checkbox that states whether the user wants to uninstall the plugin when it is deactivated.

    If you don’t have an options page, then let me walk you through that.

Activation Step

The code is pretty much uniform for all of my plugins and most plugins that I see.


function myplugin_activation()
{
    $option = get_option('myplugin_option');

    if( false === $option )
    {
        // Install tables and setup options

        $option = array();
        $option['uninstall'] = false;
        // Other options
        
        add_option('myplugin_option', $option);
    }
}

register_activation_hook(__FILE__, 'myplugin_activation');

And that implements the entire step for adding the uninstall option. Not to difficult, I don’t think. If you have any questions, then feel free to ask.

Deactivation Step

The deactivation step is as easy as the activation step (and I think the only difficult part is creating the administration page).

What you do is get the options and test to see if the options exist (should always exist, but you never know if the user deleted your options for you). Then you test to see if the uninstall option is true and remove everything.


function myplugin_deactivation()
{
    $options = get_option('myplugin_option');

    if( is_array($options) &amp;&amp; $options['uninstall'] === true)
    {
        delete_option('myplugin_option');
        // Remove other tables and installed items.
    }
}

register_deactivation_hook(__FILE__, 'myplugin_deactivation');

That is it! Quite easy, I believe. The hard part is creating the administration page, until you get used to doing them.

Administration Page Alternative

You do have an alternative, if you don’t want to create an administration page. What I’ve done, was test to see if an constant is defined and if it is, I run the uninstall in the deactivation hook. This will require manual work on the user’s part, and instructions on your part. Quite frankly this is only useful for testing of your uninstaller, and for personal projects where you don’t really need an administration page. However, if you plan on placing your plugin in the open, it will be a good idea to use the other method.


function myplugin_deactivation()
{
    if( defined('UNINSTALL_MYPLUGIN') )
    {
        delete_option('myplugin_option');
        // Remove other tables and installed items.
    }
}

register_deactivation_hook(__FILE__, 'myplugin_deactivation');

Administration Step

The administration creation is not difficult, just time consuming. When you have it set up, it is fairly straight forward. I would also suggest that if you are just going to include the uninstaller option that you have your plugin page in the plugin page.

I’ll post the administration creation step in a later step. If you need more information then the WordPress codex has all that you need for creating administration pages.

January 24, 2008 Posted by | Writing Plugins Series | , , , | Leave a comment

Writing Plugins: Writing Maintainable Procedural Plugins

  1. Don’t use Globals.

    Okay, so WordPress uses globals and that is okay, so why can’t you use globals? If you know what you are doing then by all means, ignore this suggestion, because this does not apply to you. For all of the others, the suggestion to put logic in functions applies.

    If you place variables in main(), then they automatically become global to the execution process. If you don’t use naming convention practice, then your global variable could clash with another plugin.

    It is not that you shouldn’t use globals, with procedural programming, there is no way around using globals. However, declare and set the globals up in functions, instead of setting them at the top of the plugin execution path.

  2. Use naming conventions

    And whatever you do, don’t start your functions with “wp_”. Choose a function prefix that no one (that you know of) uses yet, which could be your company or your name (although, it just doesn’t seem right to start functions using human names, since author information is better located elsewhere), the plugin name, or something you just make up.

    As long as you use it throughout the plugin, call it whatever. Consistency is key, and with naming conventions and coding standards, no one can tell you that you are wrong, as long as you are consistent. Most developers do conform to the WordPress coding standards, but use whatever naming convention pleases you.

  3. Split duplicated logic into functions.

    Are you writing the same lines of code, over and over again? How about you split that chunk of code into its own function and call that function in different places. The goal is to only write code once and reuse it in many different locations.

    This also allows you to fix a bug in one location and not have to track where similar lines of code is located. It saves time, reduces the chances of defects, and increases the maintainability of the code. Also, since most of the time, when code is split it usually increases the ability of others to grasp the full purpose of one of your functions.

    For completeness, it will be pointed out, that by splitting logic into functions does increase the overhead (where opcode caching is not used), so it will decrease the performance of your plugin. Not by much, however, it is something to look at when optimizing and is a counter suggestion to this suggestion for optimization.

    However, the optimization arguments, that I’ve seen have not convinced me that the sacrifice of maintainability and clarity is worth a few milliseconds (if even that). If your plugin is hurting, it is most likely not, because you one or two large functions into four or five smaller ones.

  4. Keep the branches and functions to a minimum

    I’ve seen plugins where there were foreach loops within if statements within foreach loops within if statements. Besides optimization complaints, I would probably say that the function needs to be simplified somewhere, so that someone like me would even want to read it to understand what it was trying to do.

    There are metrics that will inform you of how difficult a function or method is, but any function more than 25 lines is pushing the barrier of complexity. The other index for branches, is a little bit more difficult to recommend. However, try not to have more than 5 branches or like the above example. Most of the time, something like that can be split into its own function and called, if only for the sake of sanity when reading through the function.

    By keeping the complexity of functions to a minimum you increase the chances of a user coming and finding an issue and making a modification that won’t break anything. You also increase the odds that you won’t create something so complex that even you don’t understand what is happening, “Yeah, it works, just don’t breath on it!” Statements like that, should be avoided, because something will break, and you won’t be able to fix it.

  5. Keep the base plugin file length short.

    Again, this recommendation is arguable, so you can choose to have all of your functions in one file or split them into multiple logically named files. It is up to you. The argument for why you should keep functions in a single file is for optimization and there is enough optimization evidence for having PHP functionality in one file. However, I believe in maintainability, and I don’t like scrolling up and down in one massive file.

    My recommendation is that when your plugin becomes large enough, that you split it into logical portions. Usually, what I will see for classes, is a block that checks for whether the class exists and if not then it will define the class. I think just having the class in its own file and using require_once() makes more sense. You gain nothing in optimization over require_once(), because opcode caching won’t cache the class until it knows it needs it and the if statement will prevent it from doing so.

    My base plugin usually only have the activation, deactivation, and init hooks and everything else is in other files. I also split my administration files into their own files separate from other plugin functionality.

  6. Have HTML, place them in their own template file.

    I admit I do place HTML into functions myself, as it is quick and easy method. I think placing HTML in functions is not hackish or dirty at all, since it is practically the same as placing them in its own file.

    Where I don’t do this, is for administration HTML, because it is much bigger than a snippet of HTML and requires other actions. You must protect your administration files, so test for ABSPATH before outputting HTML.

January 22, 2008 Posted by | Writing Plugins Series | , , , , , | Leave a comment

Writing Plugins: Directory Structure

If you plugin is fairly simple and small, you can contain your plugin in one file and have translations in the same directory. However, if you ever plan to extend your plugin and create more complex and feature complete, then you’ll want to rethink the single file method.

The only reason you would not use this method, is if you have optimization in mind and include all the library code in one file to prevent file access overhead. However, in most instances, if your library is massive, it is probably better to have the files separated for maintainability.

Separate Translated Files (.mo) Directory

It would serve your plugin better, if translated files were in their own directory, that way, when you setup the plugin textdomain, you can reference that one directory for WordPress to look into. Also, it would allow for easy management and cleaner plugin root structure.

Third Party or External Library Directory

For third party libraries that are used, it is better to place them all in another folder and could call it third-party/. This will create a separate from your plugin’s code and code that is external from your code. When people go to file bug reports you don’t want them to file bug reports with you that they should be filing with the respective library maintainer.

Using that name will give a hint that the files are not maintained by you and should have the defects filed elsewhere. It may not stop everyone from reporting the defects to you, but if you keep notes, it should be more informative to most WordPress power users.

Library Directory

The idea is to have at most two files in the root, a readme and your base plugin file. The readme to inform users on how to use your plugin, how to uninstall your plugin, and other information about your plugin. Your base plugin file has the WordPress required comment with your plugin data, so that WordPress knows about your plugin and can activate it. The base file will set up all of the plugin variables and include the required files.

The rest of your library will be contained in a folder in your plugin’s directory. You can use one file for optimization or for maintainability, separate the functionality out into logically named files.

Public CSS/JavaScript Directory(-ies)

If you plugin also has public CSS and JavaScript files, it is better to have them in their own directory. It allows for quick access to all of the individual files for CSS and JavaScript. It creates a separation, so that users know where to look for your CSS and JavaScript. Another advantage is for permissions, but those might need to be set by the user.

Others?

The idea is to create a separation of content, so that your plugin is more maintainable for both yourself and others. It is a suggestion and developers have their own style. I have no complaints other than you should be consistent. That is not to say that if you have one plugin with directories like the above that all of your plugins should be that way. No, it is to say that if you use directories for one thing, then you should split all of your content into directories.

January 20, 2008 Posted by | Writing Plugins Series | Leave a comment

Writing Plugins: Don’t Place All Methods in One Object

Objects should only contain a single purpose, but most plugins I’ve seen pack every method in a single object. This opposed to splitting the methods out into better logical objects which contain that purpose and allow reuse across multiple projects. I would like to instead propose a better way to write objects, which don’t violate the advantages and purpose of objects. Packing everything in the same object did cause problems prior to WordPress 2.3.

I believe the reason that plugin authors have for placing all of the methods in the same object is:

  1. To keep the plugin contained for the user.
  2. That it is easier to access all of the methods and properties.
  3. Place all data and methods in a single namespace.

Objects are supposed to solve the question of reuse. It should seem reasonable that if plugins were decoupled objects, then it would be possible to easily create that same plugin for another PHP application. That is probably not the intention of the plugin author, but it could be another user’s or mine.

A solution for plugins which do this, is to inherit the object and override the methods and data you need to change. I did this with a recent plugin, which allows me to upgrade the plugin’s code without having to make the same changes over and over again.

The general rule I keep is when I’m building a class is either to plan out what methods each one it going to have and what properties and finally how each will interact with the other. If you must jump in and code without planning then once you reached a point where you are adding methods and properties that fall outside the scope of the original functionality then stop and ask, “How can I refactor this?”

For me, it is a constant question I ask about my code, because unless you’ve been coding objects for most of your life, there can always be improvements made. Decoupling your code also has the advantage of allowing you to reuse, which is key with objects and functions, in another plugin or project.

Most plugins that I’ve seen are coupled and can not easily be refactored without an almost complete rewrite of the core systems. If this is the case, then good luck and I wish you the best for your plugin.

Better Standard

I personally don’t use classes for my plugins. However, if I were to use objects, I would do it in this matter.

I would have a single class for the activation, deactivation, and init hooks.

class MyPlugin_Core
{
    function activation_hook()
    {
        // Do activation stuff
    }

    function deactivation_hook() {  }

    function init_hook() {
        $objMyPlugin = new MyPlugin_DoesSomething();

        // Do stuff with MyPlugin_DoesSomething
    }
}

register_activation_hook( __FILE__, array('MyPlugin_Core', 'activation_hook') );
register_deactivation_hook( __FILE__, array('MyPlugin_Core', 'deactivation_hook') );

add_action( __FILE__, array('MyPlugin_Core', 'init_hook') );

More of how you should structure your plugins in a later post.

Updated: An object is an object and a singleton is an object which only returns one reference to itself. With objects, you can create any number, but the Singleton pattern restricts creation to only one. Thanks to Jamie Talbot for the correction!

January 16, 2008 Posted by | Writing Plugins Series | , , | 5 Comments

Writing Plugins: What is the Class Callback Format?

Prior to WordPress 2.3.0, there was a bug that prevented object referenced method callbacks from being removed. In WordPress 2.3.x and upcoming WordPress 2.5, in order to remove the original method in the class, you have to use the original object reference. In PHP4, where objects are passed by value, this can be a problem, but PHP5 users shouldn’t have much to worry about as long as the variable they are using holds the original class reference.

Explanation of Problem Prior to WordPress 2.3

To demonstrate the problem, take a look at this code. If you were to run this prior to WordPress 2.3, the hook would not be removed because you changed the class property $test.

class MyPlugin
{
    var $test;

    function MyPlugin() {
        $this->test = false;
        add_action('init', array(&$this, '_init'));
        $this->test = true;
    }

    function init() {
        remove_action('init', array(&$this, '_init));
    }
}

This is a poor example, in that the ‘init’ hook will never run again. Other hooks will demonstrate the problem better in real world practice. That said, the method of adding callbacks to the hook array wouldn’t have allowed you to remove the hook until the state of the class was back in its original form prior to the addition of adding the MyPlugin::_init() to the init hook.

It is a little complicated to explain, but basically, once you changed the properties of the class, you wouldn’t be able to remove any hook you added prior to the change. For most plugins this was a huge deal since they had everything in one Singleton class (big mistake, will detail in later post).

How Method Callbacks are handled in WordPress 2.3+

A new private function was introduced to manage object referenced method callbacks. The form of which is below.

$myplugin = new MyPlugin();

add_action( 'init', array(&$myplugin, '_init') );

As you can see, the callback references the $myplugin variable along with the method in the second element. The reason this can cause a problem, is if you unset the variable afterwards.

$myplugin = new MyPlugin();

add_action( 'init', array(&$myplugin, '_init') );

unset($myplugin);

If you think this will magically remove the reference in the hook array, you are mistaken. PHP will retain the reference to the object and will call the method. This will hinder, but not prevent the removal of the object’s callbacks later.

For a workaround, you can recreate the object reference and it should (purely conjecture) recreate the needed hook string to reference to previously added object reference callback. This will not work if two or more object references of the same class were created, so it is assumed that in most cases only one object reference will be created. If only one were created and destroyed, it might be possible to remove the callbacks from the action or filter using the Plugin API.

New format

The new format for the above object referenced method callbacks are always: class name, followed immediately by the method name, followed by the amount of previously added (classname+methodname). For classes, this allows you to add as many object referenced classes and add methods which don’t override each other.

For static method callbacks, the format is always: class name followed immediately by method name. There is no need to protect against overrides because no two classes can have the same class name (yes, I do know there is an exception to this rule).

For functions, nothing changes, it is just the function name.

January 13, 2008 Posted by | Writing Plugins Series | , , , | 5 Comments

Writing Plugins: Does the filter or action exist?

This WordPress Plugin API feature is new to WordPress 2.5 and is quite interesting. Its application in plugins will be interesting to see when WordPress 2.5 is released.

The has_action() and has_filter() checks for the existent of hooks and whether a specific callback exists within the filter. This is useful, since it allows you to check whether anyone has added a callback to a specific hook. It also can prevent you from removing a callback that had already been removed.

Testing the Existence of a Hook

Hooks are only created when callbacks are added and in WordPress 2.5, when there remains at least one callback in the hook. If no callbacks are added to a hook or all callbacks are removed then both has_action($hook_name); and has_filter($hook_name); will return false.

This can be useful for creating your own filters for your plugin to see if anyone had hooked into your actions and filters. You can halt running the action or filter if there is nothing attached to the hook.

Removing Callbacks from Hooks

It used to be quite the process to test whether a callback existed and get the priority of the callback in order to remove it. These processes have been simplified in WordPress 2.5 and will make both finding and removing a known callback easier.

The key is that the callback has to be known. With classes, in 2.3.0 and the upcoming 2.5 release, there is a format for how classes are added as a callback. Fortunately, at least in 2.5 you don’t need to worry about the format. I’ll detail the format in a later post for those wanting to know in 2.3.x.

In WordPress 2.5 however, you only need to pass the same reference to the class and the method name. The way to get the reference, if you are removing the callback from another plugin’s class is to get the known global and use that reference.

If the plugin is known to cause problems with yours, then you should be able to get that information easily. It is easier if the offending plugin uses functions or static method calls as the original class reference variable is not needed.

Most of the hooks plugin authors will be removing will be WordPress internal ones, which don’t use classes. If this is the case, then the format is easier.

function myplugin_remove_offending_hook_after_test() {
    if( false !== ($priority = has_filter( 'pre_term_name', 'wp_filter_kses')) ) {
        remove_filter( 'pre_term_name', 'wp_filter_kses', $priority );
        // Hook another filter in its place.
    }
}

myplugin_remove_offending_hook_after_test();

When the second parameter is used, if the callback is found then the priority is returned. You can use this in the method above to remove the hook. As before, you must know the callback before hand.

The has_action() is used in the same way and as with add_filter() and add_action() it is always better to use the correct function for the hook you are referencing, even through they both use the same function.

January 12, 2008 Posted by | Writing Plugins Series | 2 Comments

Writing Plugins: Getting the Current Hook

WordPress 2.5 adds the ability to get the current hook name. This is useful for when you have a function for a filter which needs to return different output by the hook name.

A little bit of History

I didn’t agree with the idea, but the patch put forward was clean and neat. The implementation really moves the progress of the WordPress 2.5 Plugin API forward. The reasoning behind the implementation is that there are several times where a single function needs to be used for different hooks but still do somewhat different things depending on each hook.

My suggestion was to create two functions for each hook, but after some time debating I eventually supported the idea. While I didn’t supply the patch, or at least not the patch that was committed to core, I do think debating the idea made for a better feature.

How to get the Current Hook

The current hook can be retrieved using the current_filter() function. It will return a string that has the name of the hook within the context of the function that is called within the hook.

To further explain, lets say that Hook_A has three functions and the second function calls Hook_B, which has one function. When the one function in Hook_B calls current_filter(), it will return ‘Hook_B’. When the three functions in Hook_A call current_filter(), it will return ‘Hook_A’.

It will always be this way since, PHP does not do multithreading to allow for current_filter() to process two hooks at the same time. So it can always be assumed that the value in current_filter() will always return the current filter that the function was hooked into.

Example Plugin

The example plugin strips tags in the ‘wp_title’ hook and in the ‘wp_content’ hook, but also calls wpautop for ‘wp_content’ hook.

add_filter('wp_title', 'myplugin_sanitize');
add_filter('wp_content', 'myplugin_sanitize');

function myplugin_sanitize($content) {
    $content = strip_tags($content);

    if( 'wp_content' == current_filter() )
        $content = wpautop($content);

    return $content;
}

So we reduced what would be two functions into one and reduced the footprint of the total plugin code.

For filtering it is useful to sanitize something for everything except for a few areas or allow for different hooks to have different allowable items, but not for others. While it is possible to write several functions for each one, it is better (arguably) to have everything in one function for maintainability.

January 11, 2008 Posted by | Writing Plugins Series | , , | Leave a comment