[theme-reviewers] wrapping functions with if( ! function_exists() ) {…}

Otto otto at ottodestruct.com
Sat Oct 11 16:33:54 UTC 2014


On Sat, Oct 11, 2014 at 10:48 AM, Ulrich Pogson <grapplerulrich at gmail.com>
wrote:

> The guidelines states: "Themes must not provide backward compatibility for
> out-of-date WordPress versions (more than two prior major WordPress
> versions – currently, that means versions prior to WordPress 3.8),
> including using function_exists() conditional wrappers for current *WordPress
> functions*." https://make.wordpress.org/themes/handbook/guidelines/
>
> This is one thing we require but I could not find in the guidelines.
> "Function calls must be placed inside callbacks and hooked into
> appropriate actions or filters (such as after_setup_theme for Theme setup
> functions, or widgets_init for Widgets/dynamic sidebar functions)"
>
> The *theme functions* can be wrapped in a if( !function_exists()) {…}. At
> the moment this is not required nor recommended.
>
> Actually Chris wrote a good answer below Ottos:
> http://wordpress.stackexchange.com/a/111318/17937
>
> P.S I personally don't think every every theme function needs to be
> wrapped in if( !function_exists()) {…} because depending on the function
> you can just as well overwrite it with another function hooking into the
> same hook. If the function was a bit more complex then it would be better
> to make the function extendable with hooks and filters. So that child theme
> could change single values instead of having to copy the whole function.
>


The two version guideline was made back when versions were a bit more
spread out. Two versions now is like 6 months. I think being a bit lenient
on this one makes sense.

As for the if(exists) check, I would recommend against it except when it's
really necessary.

Let's say a theme (parent) defines its functions like this:

function whatever() {
}
add_action('init','whatever');

Now, a child theme can override any function that is hooked into any hook
like that by simply unhooking it in after_setup_theme and replacing it:

function child_override() {
   remove_action('init','whatever');
   add_action('init','child_whatever');
}
add_action('after_setup_theme','child_override');

The exception to this is parent functions that are themselves hooked
into after_setup_theme. A child can't easily override these, because it has
no hooks that fire earlier for it to unhook. And once the action is
running, unhooking from inside it does nothing. So those particular
functions, if any, should be pluggable using an if(exists) check.

You can see this specific case with the twentyfourteen_setup function. It's
not possible for a child theme to unhook that function, only to replace it
by redefining it.

Now, twentyfourteen actually makes a lot of its functions pluggable. The
ones that it makes pluggable are one of the following:

a) Hooked to after_setup_theme

b) Called directly by something else in the theme
(twentyfourteen_the_attached_image), so replacing them in a child is easier
than having to replace their calling files too (image.php in that case).

c) Used as a callback for something else (twentyfourteen_header_style), so
replacing them is simpler than having to adjust the specific callback
location in which they are added

These are all good reasons for pluggable functions. The downside of
pluggables is that they can only be replaced one time. A theme and a plugin
cannot both override a pluggable. So, pluggables should really only be used
when there's little other good avenues. Most of the time, if you're hooking
a function to an action or filter, then it is possible for some other bit
of code to unhook and replace it without a whole lot of difficulty, so
making it pluggable is unnecessary.


-Otto
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.wordpress.org/pipermail/theme-reviewers/attachments/20141011/8b3169ae/attachment.html>


More information about the theme-reviewers mailing list