A Newbie’s Guide to WordPress Hooks and Functions

When people start wanting to customize WordPress, specifically a theme like Thematic, or a plugin like WooCommerce, I always see questions like:

How do I add “something”, “somewhere”?

or

How do I remove “something” from “somewhere”?

or

How do I change “something”?

At first it is easy to think that adding a div to the #header is different from adding a menu to the #footer, but once you understand how filters and action hooks work, you’ll see these questions really all follow the same pattern. You just need to learn how to speak WordPress! Be patient with yourself, because you literally are learning a new language… especially if you aren’t already familiar with PHP.  I’ll be using examples for working with the [theme-link] but you don’t understanding hooks and functions and eventually filters will be handy in any WordPress project.  Let’s start…

What the heck is an Action Hook

Action hooks look like this:

do_action('this_is_the_action_hook_name');

In a plugin such as WooCommerce, if you investigate in the templates folder you will find all sorts of action hooks. The WooCommerce templates are extremely well-documented and tell you right there which functions are hooked into that action hook and in what order. In the theme, Thematic most of these are buried in the library/extensions folder.  In fact, in the actual templates (like index.php, category.php etc) you will see hooks that look more like:

// action hook for placing content above the index loop
thematic_above_indexloop();

But if you go searching for the definition of that function you will find that it is in content-extensions.php

/**
 * Register action hook: thematic_above_indexloop
 *
 * Located in index.php
 * Just before the loop
 */
function thematic_above_indexloop() {
  do_action('thematic_above_indexloop');
} // end thematic_above_indexloop

Now an action hook is sort of like a parking spot. Some are empty, some have cars on them. you can move the cars around, but the spots themselves stay put. When wordpress gets to an action hook, it will run all the functions that are attached to that particular hook. If it gets to a parking spot and finds a car, it will run that car. If not, then it will continue on to the next hook/space.

How To Add Any Function to any Hook

A completely fictitious example:

function function_you_want_to_add(){
echo "I heart bacon!";
}
add_action('destination_hook','function_you_want_to_add', $priority, $args );

The add_action line is doing the heavy lifting here, and always takes this same “form”…. it sort of reads like this in english:

Add the function called ‘function_you_want_to_add’ to the hook called ‘destination_hook’ in the order of $priority with some optional extra arguments called $args.

You can read all about add_action in the WordPress Codex (hint: there is a TON of info there, but I understand it can be overwhelming at first).

The $priority is always a number. It is like a traffic cop in the parking lot, or maybe just an orange cone. if more than 1 function wants to be on a particular hook the priority decides which goes first. If 2 cars wanted to be in the same spot, the one with the lower number priority would get ground level parking and the one with the higher priority would be stacked on top. Yay 3-d parking! Sorry, prepare yourself we are going to beat this metaphor to death. The default priority is 10, so if you don’t need to change that you don’t even need to define it in your add_action line.

Some hooks pass additional variables to the functions that operate on them, but this is pretty advanced so for an introductory primer we will ignore it.

Now, a practical example:

function function_you_want_to_add(){
echo "I heart bacon!";
}
add_action('thematic_above_indexloop','function_you_want_to_add');

If you add the practice example to your child theme’s functions.php you will see “I heart bacon!” appear on your blog page. Now leave that there and add the following just underneath it in your functions.php.

function kia_another_function(){
echo "Guacamole makes me happy!“;
}
add_action('thematic_above_indexloop','kia_another_function', 5);

Notice the priority number is 5. This means it has a lower priority number than the first function, which is 10 by default since we didn’t specify anything. When you reload your theme you should now see Guacamole makes me happy! on the blog index above the line about loving bacon. Bacon and guacamole together. It must be code heaven.

How to Remove Something From a Hook

removing stuff works a bit differently:

function remove_stuff(){
remove_action('hook_location','function_you_want_to_remove',$priority );
}
add_action('init','remove_stuff');

In english this sort of translates to:

When WordPress runs the init hook, please remove the function called “function_you_want_to_remove” that is located on the hook called “hook_location” with a priority of $priority.

init is just a WordPress hook. in fact, it is the one of the earliest hooks that run when WP starts whirring… it is like priority parking. You can see most all of the hooks that run in the WordPress process again at the Codex: Action Hooks  To remove something that had a specific priority originally, you must remove_action it with the same priority.  A good practical example would be removing the Thematic blog title.

function remove_thematic_header(){
remove_action('thematic_header','thematic_blogtitle', 3);
}
add_action('init','remove_thematic_header');

Paste the above into your functions.php, reload your child theme and poof the blog title is gonzo!

Moving the #access menu is another practical example, that combines adding and removing functions.  I’ll include it here because I see this question asked all the time.

function remove_thematic_header(){
remove_action('thematic_header','thematic_access', 9);
}
add_action('init','remove_thematic_header');
add_action('thematic_aboveheader','thematic_access');

Note that we don’t have to define thematic_access, because it already is defined by thematic. We can simply add_action it to a new parking spot.

Overrides R’ Us

Thematic has a bunch of functions built in that if you define them, they automagically replace the function thematic was going to add to a specific hook, with your custom function.  In WordPress parlance, this is called a pluggable function.  Many thematic functions can be overridden by copying a thematic function to your functions.php and altering the function’s prefix from thematic_ to childtheme_override_.  The overrides completely change the car that is parked on a particular parking spot but they don’t change its location.

For instance to override the thematic_blog_description you could put the following in your functions.php

function childtheme_override_blogdescription(){
echo "Evil laugh! Now your blog is only about bacon!";
}

Refresh your theme and you will see the blog description has been taken over by bacon. , which I think is neat.  Note that with pluggable functions you do not need to also call add_action.  Doing so will add the function twice.  Most functions in thematic have this override capability, but not all.  You can browse through the extensions folder (look but don’t touch the parent theme!)

If you see something like:

if ( function_exists('childtheme_override_blogdescription') )

That’s a sign that you can use the override feature.  The full IF statement reads something like:

If you define a child_theme_override function then Thematic will add your custom function to the appropriate hook instead of its own function.

Overrides are significantly more intuitive than filters, but filters can be more elegant: the scalpel instead of a broadsword if you don’t need to change the entire function.  However, this post is crazy long, so I will leave filters for the next part of series.

Additional Resources

To help you know what hooks are available in Thematic, here are 2 visual aids:

http://www.bluemandala.com/thematic/thematic-structure.html

http://visualizing.thematic4you.com

Additional Help

I’ve tried to make this as beginner-friendly as possible, but I’ve been doing this for a few years now and so it makes total sense to me. Please let me know in the comments if something about this tutorial is not clear so that I can make it better.

Also, I don’t have time to respond to specific support requests in the comments. If you have Thematic questions post them at the Thematic Forums or contact me for some premium support.

KIA Subtitle

now our subtitle input is always in the right place

Recently I was working on a project and needed a subtitle. There are probably two subtitle plugins already in existence. I happened to pick The Subtitle by Luc Princen, which worked pretty much as intended except the actually input box wasn’t always where it was supposed to be and I found that admin notices seemed to make it pretty unreadable and not totally obvious to my clients.

Well instead of seeing if this problem was solved in the other, already-available plugin, I did what I always do when I have more important things I could be working on: I fixed it. I went ahead and tweaked a bunch of other things too: like moving the plugin into a class (I have no idea if this is beneficial, but I feel smart doing it so I do), not saving “Subtitle” as the meta on posts with no subtitle instead of relying on the callbacks to not display it.  Making it translation-ready… with a whopping 1 translatable string.  Oh and just because I am all multi-lingual like that (meaning I can use translate.google.com) I translated it into french and spanish.

USAGE

Usage is covered in the readme.txt but I’ll cover it again here.  Wherever you want to echo the subtitle, you’d use the the_subtitle() template tag.  We’re wrapping it in the function_exists wrapper in case you decide to uninstall the plugin (why?), this way your theme won’t break.

[php]

if(function_exists(‘the_subtitle’)) the_subtitle();

[/php]

As of version 1.2, the_subtitle() accepts three parameters: a string to come before the subtitle, a string to come after the subtitle, and whether or not to echo the subtitle: true by default. Basically we are mimicking the capabilities of WordPress’s default the_title() function.

So for example, you can wrap the subtitle in some HTML tags using the first two parameters:

[php]

if(function_exists(‘the_subtitle’)) the_subtitle( ‘<h2 class="subtitle">’, ‘</h2>’);

[/php]

If you need to return the value, much like the default WordPress functions, you can use get_the_subtitle() which accepts a $post_id parameter if you need to use it outside the loop.  If you do not supply a $post_id, it will automatically grab the ID from the current post.  But if you supplied a number there, you could ostensibly use it to grab the subtitle of another post.

[php]

if(function_exists(‘the_subtitle’)) $subtitle = get_the_subtitle($post_id);

[/php]

Oh, and I left the shortcode in tact, though I can’t figure out why you’d use the shortcode instead of just straight typing into the post editor.  But if you want it, it is still:

with no spaces.

To DO:

I’m wondering if it is worthwhile to add a subtitle column to the edit screen and if I should then add it to the “quick edit”. Let me know your opinion in the comments!

Download

Now available at WordPress: KIA Subtitle at WordPress

or check it out at the KIA Subtitle github repo

Thematic 1.0.1 Upgrade

After a long wait, Thematic 1.0.1 has been live in the WordPress repositories now for a couple of days now! And some issues are starting to crop up in the forum. So far the most recurring issues have to do with the menus. Oh menus, you never cease to cause trouble.

The problem is that thematic 1.0 underwent some major changes to be compliant with WordPress Theme Review Guidelines and the change with the most impact on menus in particular is our switch to properly enqueing stylesheets and scripts using wp_enqueue_stylesheet and wp_enqueue_script. This has led to some changes to existing functions and the removal of a few old filters that didn’t make sense anymore given the new approach. You can see the massive changelog in the readme.txt file that comes with Thematic, but really, its huge, so it would be easy to miss the ones that are effecting you.

I Upgraded and Now My Menu is Broken

We’re going to need to diagnose what went wrong based on what you used to be doing and what has changed.

* Changed: Filter thematic_dropdown_options.

Were you serving your own modified version of the thematic-dropdowns.js script to tweak the widths of the dropdowns, add arrows, or change the delay on the hover? If so, then you might have been filtering thematic_dropdown_options. This filter used to work like so:

[php]
function childtheme_dropdown_options() {
$newscript_uri = "\n" . ‘<script type="text/javascript" src="’ . get_stylesheet_directory_uri() . ‘ /scripts/thematic-dropdowns.js"></script>’ . "\n";
return $newscript_uri;
}
add_filter(‘thematic_dropdown_options’,’childtheme_dropdown_options’);
[/php]

in that you needed to return the whole script tag. That is no longer the case and now you need only to return the URL of the script like so:
[php]
function childtheme_dropdown_options() {
$newscript_uri = get_stylesheet_directory_uri() . ‘/scripts/thematic-dropdowns.js’;
return $newscript_uri;
}
add_filter(‘thematic_dropdown_options’,’childtheme_dropdown_options’);
[/php]

 

* Removed: Variable thematic_use_superfish. * Added: add_theme_support('thematic_superfish')

We’ve switched to using the WordPress function add_theme_support to determine whether to load the superfish scripts. Previously there was a filter called themtatic_use_superfish, that you could target to remove the dropdown scripts if you didn’t need them.
[php]
function childtheme_no_superfish(){
return FALSE; // we don’t want any of your vegetables!
}
add_filter(‘thematic_use_superfish’,’childtheme_no_superfish’);
[/php]

or if you were being super elegant, perhaps you killed the dropdowns with this:

[php]
add_filter(‘thematic_use_superfish’,’__return_FALSE’);
[/php]

But, we’ve ditched this filter in favor of using WordPress’ theme support feature. It is an easy switch. If you don’t want to load any of the superfish, dropdown scripts then you should now do it this way:
[php]
function childtheme_no_superfish(){
remove_theme_support(‘thematic_superfish’);
}
add_action(‘thematic_child_init’,’childtheme_no_superfish’);
[/php]

Note that thematic_child_init is a new action hook, that is specifically placed to remove any theme supports added by thematic.

* Removed: Filter thematic_head_scripts.

To be fair this one isn’t in the readme as far as I can see, but the problem is similar to the issue with thematic-dropdowns.js. Maybe you were using this filter to you maybe wanted to remove all the superfish and supersubs scripts because you don’t use dropdowns. Or perhaps you were adding your own scripts here.
[php]
function childtheme_scripts($scripts){
return FALSE; //we don’t want any of your vegetable scripts!
}
add_filter(‘thematic_head_scripts’,’childtheme_scripts’);
[/php]

or if you were adding a scripts of your own, maybe you did something like this:
[php]
function childtheme_scripts($scripts){
$scripts . = "\n" . ‘<script type="text/javascript" src="’ . get_stylesheet_directory_uri() . ‘ /scripts/thematic-dropdowns.js"></script>’ . "\n";
return $scripts;
}
add_filter(‘thematic_head_scripts’,’childtheme_scripts’);
[/php]

As before, we are now using using wp_enqueue_script, so thematic_head_scripts() is now only a function that is added to the wp_enqueue_scripts hook. You can remove it entirely the same way you remove any action:

[php]
function childtheme_remove_scripts(){
remove_action(‘wp_enqueue_scripts’,’thematic_head_scripts’);
}
add_action(‘init’,’childtheme_remove_scripts’);
[/php]

or possibly you were using the override:

[php]
function childtheme_override_head_scripts(){
// absolutely no bacon here
}
[/php]

However, that is a bit of a nuclear bomb approach and will also wipe out an important script for handling comment replies, which you may or may not need. But thematic is super granular and you can use a scalpel to kill the drop downs scripts quite easily instead of using a viking war hammer with the remove_theme_supportscrap of code from earlier.

If instead, you need to load more scripts, then you should make like Thematic and use wp_enqueue_script.

[php]
function childtheme_scripts(){
wp_enqueue_script(‘bacon-script’, get_stylesheet_directory_uri . ‘/scripts/bacon.js’, array(‘jquery’), ‘1.0’, true);
wp_enqueue_script(‘guacmole-script’, get_stylesheet_directory_uri . ‘/scripts/guac.js’, array(‘jquery’));
}
add_action(‘wp_enqueue_scripts’,’childtheme_scripts’);
[/php]

If you are wondering about why the two lines are different, you can read more about how to use wp_enqueue_script in the WordPress Codex:

* Changed: Function thematic_create_stylesheet to wp_enqueue_style.
* Removed: filter thematic_create_stylesheet.

I saw this come up in the forum already. Someone was using the thematic_create_stylesheet filter to add extra stylesheets to the header. Something along the lines of :

[php]
function childtheme_create_stylesheet($style) {
$style .= ”;
return $style;
}
add_filter(‘thematic_create_stylesheet’, ‘childtheme_create_stylesheet’);
[/php]

Well that filter is gone like a bowl of my famous guacamole, so if you need to add more stylesheets, then we’ll have to add them the updated way… which by the by, will work better with any caching plugins you might be using and prevents the same style from being loaded twice (like if you were loading the supersized script’s css and then you had a plugin that was also trying to load the same stylesheet).
Thematic is now loading the main stylesheet like so:

[php]
function thematic_create_stylesheet() {
wp_enqueue_style( ‘thematic_style’, get_stylesheet_uri() );
}
add_action(‘wp_enqueue_scripts’,’thematic_create_stylesheet’);
[/php]

I can’t think of too many reasons why you’d ever need to change that. Your theme will always need a style.css in order to be a valid theme. But if you need to add more stylesheets, it is going to work just like enqueueing scripts except we use a slightly different function, wp_enqueue_style.

[php]
function childtheme_create_stylesheet() {
wp_enqueue_style( ‘blue_style’, get_stylesheet_directory_uri() . ‘/styles/blue.css’ );
}
add_action(‘wp_enqueue_scripts’,’childtheme_create_stylesheet’);
[/php]

Oh Noes! My menu is still broken!

Well, head to the support forums and start a new thread. Here is a tip for getting better support: do NOT just say “my menu won’t work”. This tells me and the other volunteers absolutely nothing and makes it impossible to help you. Be precise when describing exactly what you are trying to accomplish, what you are seeing/experiencing now, compare that to what you were experiencing before hand, and tell us anything that you might have already tried. Screenshots can be helpful as can links to your live site.

Thematic Support Forums

How to Use Multiple WYSIWYG (TinyMCE) Visual Editors in Your WordPress Metaboxes

Ever since WordPress invented the metabox, people have been trying to put the rich text editor (in WP this is provided by TinyMCE) into their metaboxes. And it makes sense. Sure us uber-geeks know the HTML tags required to make some text bold, but most of the world does not. But they do know how to click on the “B” button.  So if we’re building a theme that requires multiple blocks of content it’s nice to reuse the visual editor.

I’ve been using the WP Alchemy Class by Dimas Begunoff to build my metaboxes for a while now.  It gives a *lot *of power to build really complicated field sets, especially repeating ones.  For a long time using the visual editor in the metaboxes was elusive. Dimas wrote an article on How to Use Multiple WordPress WYSIWYG Visual Editors and it worked, up to a point.  Because TinyMCE is fickle (and despite their tagline being “Easy to Integrate”) this code didn’t work for repeating groups, which in my mind is the strength of Alchemy.

As of WordPress 3.3 you can finally use the built-in wp_editor() function for multiple editors in your metaboxes, but again these must be defined in advance.  You can’t use this function with WPA’s dynamically generated fields. So, repeatable, sortable WYSIWYG (TinyMCE) rich-text editors has been the elusive, ultimate dream of WP Alchemists. The <cough>Holy Grail</cough> of WP Alchemy. But after a lot of head-banging effort, I think I have it!

I have create a Twenty Eleven child theme that shows WP Alchemy-powered metaboxes with repeatable, sortable, WYSIWYG (tinyMCE-enabled) text editors complete with media buttons. And as a bonus, it shows a single field using wp_editor() because that also needed a little twist to work with WPA. Upload and activate the theme, then add a new post to see the boxes in action.  For the curious, and come on you know you are, the real magic is in the kia-metabox.js script. Download the sample theme from for an idea of how it works.

Fork me on github!  Perhaps we can figure out how to use the quicktags editor when the visual editor is disabled. Full tutorial to come…  maybe.

Create an Alphabetical Glossary of Posts in WordPress

Once up a time i did a client project where i had to have archives organized alphabetically.   I ended up accomplishing by adding a query variable and targeting the posts_where filter.  However, in answering a recent question at WordPress Stack Exchange I decided that it might be neater to create a hidden taxonomy instead.  I don’t know if there is any performance benefit, but the code was a little more elegant and you get prettier permalinks: site.com/glossary/a instead of site.com/?glossary=a right off the bat without the need to do any complicated htaccess rewrite rules, since everyone knows that mod-rewrite is straight up voodoo.

Creating a Hidden Taxonomy

Pretty standard function for registering a taxonomy. Just going to accept a lot of the defaults, and not worry about labels since we’re going to hide it from the back-end by setting the ‘show_ui’ parameter to false. For this example we’re going to call the taxonomy “glossary” and we’re going to assign it to posts, but we could well have done it for any custom post type.

Automatically Setting Terms for each Post on Save/Update

It’d be a pain if we had to actively remember to sort each post by its letter each time we wrote a post. I have enough difficulty just writing a post in the first place. But with some code we can automatically pop off the first letter of the post title and assign that letter as the term in our “glossary” taxonomy. The following is the pretty standard function for saving information from a metabox, which works perfectly for our case even though we don’t have a visible metabox.

Auto-Assigning Terms to existing posts

If you’ve had a blog for a while and have a lot of posts the idea of going back and manually saving the posts again sounds worse than pulling our your toenails.  So you can run a little function to do it automatically.  Ideally, if this were a plugin, it’d run on the plugin’s activation hook.  Since it’s not you can just drop it into your functions.php and then reload your site. Thanks to the transient check you can leave it in there and it won’t run again. Basically what it will do it grab all your posts, loop through them all, pop off the first letter of the title and assign it to the “glossary” taxonomy.

Finally, Creating the Alphabet “Menu”

Now that we have assigned a term for each existing post and for every post to come in our custom taxonomy, we should display an alphabet menu…. or some way to access the different Letter archives.  This was the one place were the code was not 10x more elegant than in my first iteration because there was no easy way to test whether a term had a post in it.  Usually, yes, it would… but if you changed a post name and there were no other posts under a certain letter you could come up with an empty section.  So what I did was get all the terms in the taxonomy with get_terms which hides empty terms by default, loop through that data and store it in an array, then check each letter of the alphabet against that array.  To avoid running through that every single page load, I used the transient API to store the resulting array of alphabet terms.  This array refreshes whenever a post is updated (this actually happens in an earlier code block for the kia_save_first_letter() function. For my original project I wanted to have the letters with posts have an active link and the letters without posts in that section just have the letter.  Something like: A B C D** E** …. and onwards, so I have re-created that effect.

Future Improvements

One thing I’d like to improve upon would be ensuring that the first letter I’m popping off with the substr PHP function is actually a letter… or maybe a number, but not a character.  I’d also like to get it to skip words like The, An, and other pointless words that don’t really reflect on the subject.  But then this isn’t a solution for everyone… if you want to make sure that “A Post about Bacon” and “The Bacon Post” show up in the same archive, well you should tag them in the Bacon tag and not hope that they show up alphabetically in the right place.  Still it has its uses.  Let me know of any improvements you make!