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
.