In the previous article in this series I explained how Genesis is a framework that is not dissimilar from working with Legos. I listed out all the built in hooks and used the analogy that those are like the bumps that let you attach bricks to each other.
If the hooks are those bumps, the actions are the directions on where a brick should go. The brick itself is a bit of code called a function. There are two basic kinds of actions, add_action() and remove_action(). Fortunately these are not intended to be confusing in their nomenclature. In other words, they do exactly what the name says they do. An add_action() is an instruction on where to add a brick (function) while a remove_action() is an instruction to remove the bit of code. There are 5 parts to the instruction.
- Instruction Type: add or remove
- The hook to be used: where the code goes
- The call back function: the code that will be added
- The Priority: what order the code is loaded relative to other actions
- Accepted Args: the number of variables that can be sent to the function
Simple enough right? Ok, so lets see how this is built in code.
Add Action
Here is a generic add action
add_action( 'hook', 'callback_function', 10, 1);
The first part tells us it is adding an action, not removing one.
The second part tells us the hook’s name is “hook.” If this hooks doesn’t exist then the code doesn’t do anything else. This is helpful since you don’t need to deal with conditional codes to make sure the hook exists, it also means you don’t need to worry about your function loading if the hooks hasn’t loaded. This is used in Genesis for the loop and comment template. If the loop isn’t loaded, then the remaining loop hooks don’t load, likewise, if the comment template isn’t loaded, then none of the other comment hooks load.
The third part tells us the name of the callback function is “callback_function.” This must exist or you will get an error to the effect of “The second argument is expected to be a valid callback function.” This means you need to either use an existing function (which is really cool and I’ll talk about that more in the next article) or you need to create a function. All you need to do is write this in a php file that will be loaded when this action is executed (typically just before or after the action code)
function callback_function() { //do something really cool }
The first part says “hey this is a function for you to remember.” The next part is the function name. Inside the () would be any arguments that can be passed (more on that later) and the { is the start of the function. Everything after that is code that runs inside the function. the } is the end of the function. Simple really, but also very easy to mess up. Misspell any of that, use the wrong symbol, or put something out of order and you will get an error. Learn to read those errors and you will know how to fix it, but that’s another tutorial. The short version is, type it out like this and you won’t break anything.
The fourth part is the priority. In this case it is 10, which is the default. If this number is not set then WordPress will see it as a 10. Any actions with the same priority will get loaded in the order the code occurs, WordPress core functions, most plugins, framework files, theme function files, theme template file. I’ll go into this in more detail on the next article. The lower the number, the higher the priority, in other words it loads first. The higher the number the lower the priority, so it loads later. This means you can put several items on the same hook and use priority to force them into the exact order you want.
add_action('hook', 'function_1'); //loads second add_action('hook', 'function_2', 15); //loads last add_action('hook', 'function_3', 5); //loads first
Notice none of these have the arguments(which we will talk about next) and only the second two use the priority. the first defaults to “10” so it comes between the second and third.
The fifth part is the accepted args, this defaults to 1, but you don’t have to actually pass any args along. Normally this is left at 1, since the actions aren’t actually passing along anything that can be used; however, there are times when this can be very useful. In my plugin “Genesis Featured Widget Amplified” I get my $instance value for the widget settings and send that outside the class via the hook function. This means I can write code in my functions.php file and have it check the widget settings before it does anything.
add_action( 'gfwa_post_content', 'gfwa_do_post_content', 10, 1 ); /** * Outputs the selected content option if any * * @author Nick Croft * @since 0.1 * @version 0.2 * @param array $instance Values set in widget isntance */ function gfwa_do_post_content( $instance ) { if ( !empty( $instance['show_content'] ) ) { if ( $instance['show_content'] == 'excerpt' ) the_excerpt(); elseif ( $instance['show_content'] == 'content-limit' ) the_content_limit( ( int ) $instance['content_limit'], esc_html( $instance['more_text'] ) ); else the_content( esc_html( $instance['more_text'] ) ); } }
As you can see, this checks the $instance value to see if this should show the_excerpt(), the_content_limit(), or the_content() or do nothing at all. If you didn’t see that, the important part is that I added the $instance value as an argument. Since we don’t work with this very often in actions I’ll move on for now, and deal with this in depth when I explain filters.
The last thing you need to know is duplicate add_actions are ignored. If an action exactly matches, it will do nothing. If any part is different, including the priority or accepted arguments, then it will load onto the site again.
add_action('hook', 'function_1'); add_action('hook', 'function_1'); //this is ignored since that instruction already exists add_action('hook', 'function_1' ,5); //this will load before the first instance of function_1() on "hook" add_action('hook_2', 'function_1'); //this will load the code in function_1() onto "hook_2"
OK, so now you can add an action (lego blog) but writing a simple instruction that says where to put it, what to put there, and what order to put it in and any special parts the code might need. The next step is learning how to remove the action.
Remove Action
A remove action has all the same parts, the biggest difference is the remove action depends on an add action and hook, not just the hook. Remember that the add_action() is ignored if the hook isn’t present, well the remove_action() won’t do anything if the corresponding add_action() isn’t present. Confused? Lets try some examples.
add_action('hook', 'function_1'); add_action('hook', 'function_1', 5); remove_action('hook', 'function_1'); remove_action('hook', 'function_2');
Here we have to add_action()s. Both load the same function, but in a different priority. I’ve also added two remove_action()s.
The first remove action will remove the first add_action but ignore the second even though it uses the same hook and function. Because the remove action is not exactly the same, including any priority or accepted argument values, it will not remove that specific action.
The second remove_action() does nothing in this case, it doesn’t have an action that it matches because the actions are using difference functions. If the any part of the add action is not an exact match then the remove action does nothing. It will not return an error though, this is useful if an action is only added conditionally, but you don’t want to build the same conditional contingency for removing the action. For example, removing a portion of the comment form can be done without making sure you are on a single page first, even though the form only loads on single pages.
There is one other caveat. The add_action has to exist before the remove action.
remove_action('hook', 'function_3'); add_action('hook', 'function_3');
This will still load the action because it is added after the remove action has said “now take of this piece.
The short version if all that is: if the remove_action exactly matches the add_action and comes after the add_action, then it will tell WordPress to remove that bit of code.
Actions in Loops
If that last rule of remove_actions seems unfair, this is why it exists. Take a look at my tutorial on the Gallery Post Format mod in Tapestry. I’m nto going to post all that code again, but I’ll put in a few relevant snippets if you don’t feel like clicking back and forth to follow along.
If you notice, the code is added inside the loop (genesis_before_post is the first hook in the loop). This means it is repeated every time a new post is loaded in the loop. Based on what we know about actions, the duplicate add_actions are ignored, and if the actions has already been removed the remove action will do nothing. Since this code deals with two different scenerios, that might change, the actions need to be added/removed every time.
//within the loop if( $foo == $bar ){ add_action('hook', 'function_1'); remove_action('hook_2', 'function_1'); } else { add_action('hook_2', 'function_1'); remove_action('hook', 'function_1'); }
In this code, that we are assuming is being looped and that the $foo and $bar variables change and might be equal at different times and not equal at other times, I have two options. If the first condition is true then I am adding the code to “hook” but I don’t want the code to show on “hook_2” so I have to remove it, even if the code wasn’t added. In the second condition, the first not being true, then I add the code to “hook_2” but have to remove it from “hook” because it may or may not have been added previously.
Because identical actions are not duplicated, and because remove_actions depend on the add_action already existing, this lets me use very simple code to move my function from one hook to the other in a loop, or any number of other really cool things like I did with the Gallery post format in my other tutorial.
And Now You Know
But alas, knowing is just half the battle. You will need to apply this. The next part of the series deals with how to find actions in the Genesis files and alter them within the child theme.
Have anything to add to this? I’d be very happy to hear what you have to say in the comments. If there are other tutorials you would like to read let me know and I’ll see about writing them up.
kari says
Keep going, keep going!!! These are fabulous… I still don’t understand exactly, but have a feeling it will all come together eventually… Thank you again!!
Nick says
What kari said π
Dave T says
Should the use of WordPress hooks be avoided?
Thanks for the posts Nick, look forward to the next.
Dave
nickthegeek says
No, there are many WordPress hooks that are also available, I often use “template_redirect” or “init” when I need those hooks. I might write a post on WordPress Hooks another time, but right now I’m focusing on Genesis.
Ryan says
I have to agree with Nick and Kari who commented earlier. I am new to Genesis and these posts are really helpful! Keep them coming! π
Steve Shead says
I have a question on actions. In learning actions I was trying to have a widget appear on all pages except the home page. I thought this would work:
/** Add widget area for all pages except the home page */
add_action(‘genesis_after_header’, ‘include_page_header’);
function include_page_header() {
if ( !is_home() )
remove_action( ‘genesis_after_header’, ‘include_page_header’ );
}
…it didn’t! π
Being a novice I was playing with a different statement which should have had a ‘return’ parameter. I accidentally left out the ‘return’ statement and I got the desired effect (that confused me). I know the code is wrong so I wanted to understand how to make it work, and why the below code actually worked.
/** Add widget area for all pages except the home page */
add_action(‘genesis_after_header’, ‘include_page_header’);
function include_page_header() {
if (! is_home() )
genesis_widget_area( ‘page-header’, array(
‘before’ => ”,
) );
}
That being said, for now, I used the CSS below to not display on the home page (thanks to Andrea from Studiopress).
.home .page-header {
display:none;
}
I know that works, but in the spirit of learning I wanted to find out why my code didn’t work.
Sorry – lots of info – if you get a moment that’s great. If not, that’s okay too. Your tutorials have helped me a ton along the way already!
Steve
nickthegeek says
The remove_action won’t work when the action you are using it on is running on the same hook. The best solution is more like what you did the second time. The reason it worked in that instance is you said “If this isn’t the home page, put in the widget area.”
Steve Shead says
Oh – so the second instance is acceptable. Excellent! Thanks for taking the time to answer.
Steve
Keith Luo says
Very good tips. Nick, Keep up this good work. It’s very helpful. God bless you….
Philip Gledhill says
Hello Nick
Thanks for all the info about Genesis, Iβve learned a lot of useful stuff from your site.
I’m not sure if you include Youtube videos in your comments, if you do you might consider this video about actions and hooks. I made it after studding your Genesis Explained series.
http://youtu.be/NLJ0NuMGKw8
If you don’t link to Youtube please feel free to delete the comment.
Thanks for all the info
Philip.
nickthegeek says
thanks for sharing. Looks great. At one point I was working on some videos converting my Genesis Explained series into a video series.
Geordie says
Hey Nick: Where did you get those “Previous/Next” post navigation elements with the featured images in them? (The ones at the end of the post?)
nickthegeek says
those are custom and are pretty tricky. I have tried writing a tutorial several times but right now it just has so much code that I haven’t been able to do a good job simplifying it.
Nur Ahmad Furlong says
Thanks as always for being one of the most helpful people around in clearing up the mysteries of the Genesis Framework. Can you advise where we can find a comprehensive list of available hooks, the hook references available only cover the parent level hooks and a few sub items but doesn’t go into all the detailed elements 1 by 1.
I also get so confused about where each standard hook is actually added, so for example ‘genesis_do_breadcrumbs’ is hooked into ‘genesis_before_loop’. Would love to know where each little action is hooked in.
I know for sure I must be confusing hooks and actions, still trying to get through the clouds here.
nickthegeek says
Nur,
I’m not aware of any complete action reference, but you can find them all in the Genesis files. Once you learn the basic file structure it is really easy to find what you are looking for. That is what I do if I can’t remember the exact syntax of an action I don’t mess with that often.
Paul Davidson says
Thank you sir for explaining the priority numbers. So helpful.
Eric says
Thanks for this series, this is very helpful. What I don’t understand is why all content added via hooks is put in functions.php. I’m working on a site with a lot of extra content and that just doesn’t seem like ideal organization. I prefer overwriting files like a normal wp child theme. What do I do if I want to customize single.php, for example? Apologies if you already answered this in this series. Thanks again.