I have a purchased theme that procedurally loads an action like this:

function func() {
    echo "head content";
}
add_action( 'wp_head', 'func', 5 );

Following the remove action codex I tried the following:

remove_action( 'wp_head', 'func', 5 );

Which did not work so I figured it was a priority issue so I adjusted both higher and lower neither worked. Then I tried wrapping the function in another function like:

function testfunc() {
    if (remove_action( 'wp_head', 'func', 5 )) {
        echo "removed action";
    }
}
add_action( 'wp_head', 'testfunc', 1000 );

Again playing with the priority. The whole time remove_action is returning true but not removing the action. Then I tried adding the wrapping function in the init action and it worked. Great! Unfortunately I have no idea why. Somewhat more perplexing is the wrapping function is required. Lastly, the codex specifically states:

It is also worth noting that you may need to prioritise the removal of the action to a hook that occurs after the action is added. You cannot successfully remove the action before it has been added.

And according to this codex entry both init and get_header (which worked) are before the wp_head action the function was hooked into. Can someone demystify this for me?

Edit: To answer @sumit’s question the add_action happens via an include in the main themes functions.php (it includes library/core.php). The remove_action is in the functions.php of the child theme.

1 Answer
1

The issue here is that the child theme functions.php is loaded before the parent theme functions.php. Therefore, the ordering of the add/remove actions would be something like so:

//* From the child theme
remove_action( 'wp_head', 'func', 5 );
//* From the parent theme
add_action( 'wp_head', 'func', 5 );

The callback to func on the wp_head hook is removed before it’s added. Therefore, it will appear that the child theme removing the action doesn’t work. In reality, the remove_action() function is attempting to remove the func callback from the wp_head hook, but it hasn’t been added yet.

The solution is to hook into WordPress anytime after the parent theme functions.php loads and then remove the action.

add_action( 'after_setup_theme', 'wpse_222809_after_setup_theme' );
function wpse_222809_after_setup_theme() {
  remove_action( 'wp_head', 'func', 5 );
}

This works because the after_setup_theme hook fires after the parent theme functions.php, so the ordering of the add/remove actions would thus be:

//* From the child theme
add_action( 'after_setup_theme', 'wpse_222809_after_setup_theme' );
//* From the parent theme
add_action( 'wp_head', 'func', 5 );
//* From the wpse_222809_after_setup_theme function hooked to after_setup_theme 
//*( hook added in child theme )
remove_action( 'wp_head', 'func', 5 );

This would also work with replacing after_setup_theme with init, as you figured out, because the init hook is fired after the parent theme functions.php and before wp_head.

Tags:

Leave a Reply

Your email address will not be published. Required fields are marked *