Theme Overrides: hang on tight we’re goin’ in

A Public Service Message

Document what you do

If you are like me, you are absolutely certain that you will remember why you put in some clever bit of code. But trust me, those people in Harry Potter movies are plucking such memories out of your head daily and using them for nefarious purposes.

It is aggravating to advance your coding skills for a year and then return to some nasty, ludicrous code, and because it’s not commented you have no idea what possessed you to write something so stupid.

There are many ways to document your travels. Following the spirit of documenting why you did it here are some ideas:

  • comments right in the code, of course, be it CSS, HTML, PHP or Javascript
  • git (or other VCS) commit messages, or documentation files in your git repo
  • with WordPress you can also create non-public documentation of your customizations using private posts, pages or via a notes plugin such as .

Ask me for examples if it looks like I’m going to skip this.

Okay, so let’s look at what we can change.

Styles

Although we are discussing child themes here, most of the CSS advice is also applicable to CSS customizations using the Custom CSS interface area of WordPress as well.

CSS additions

CSS additions are not quite a perilous as CSS overrides. An example of CSS additions would be for formatting the addition of a custom post type where no specific CSS exists and the default is not providing what you need.

CSS overrides

This is the most common. Something is lime green or too small and you want to override it with your own choices. Typically I check to see what interface control is provided for design and exhaust the capabilities of the interface before hitting it with custom CSS. This makes it more “it’s somebody else’s project now” proof.

Determining & scope

If I had a nickel for every time I muttered, “where the eff is this coming from” when looking at css, I could buy a ticket to, well, somewhere far away. (Probably not two tickets to paradise though, sorry Eddie).

Open up the developer tools in Chrome or Firefox and use  the styles panel, the “class chain” and the “calculated” panel to do your detective work.

The basic idea is to find some tags, classes and/or IDs to hang your CSS from.

The nature of the over-ride

So, the general rule of thumb for child themes is that if a file (most files, there are a couple of exceptions) exists in the child theme that matches the name and relative directory location of a file in the parent theme, then the file in the child theme will be used instead. That sentence is worth reading a couple of times to make sure that you have got it.

The two exceptions are the styles.css file and functions.php file, there behaviour is a bit different and also different from each other. Let’s take the styles.css first.

Okay, let’s think about the rule for a minute. If I have a style.css file in my child theme then WordPress will use it instead of the one in the parent theme and I won’t have any of the parent theme styles. A few points on this:

  • Remember when we were setting up the child theme files and put the enqueue function in. This function defines the parent style, the child style and then enqueues the child style file with a dependancy on the parent so that they both load in the proper order: parent first, then child.
  • Not loading the parent style file first and then the child theme style is so close to almost never what you want to do that many good quality themes will include code in their functions.php file that checks for a child theme and sets the enqueue order up if it finds one. (Remember the functions.php file is one of the exceptions to the “override it in the child theme” rule.)
  • If you don’t want the parent style to load then probably a different development route is something you want to consider. I have ideas on it that I won’t go into here, email me or buy me a beer or something if you want to hear me blather on about it.)

Challenge #2 CSS changes

Challenge 2 is fairly simple, makes some CSS changes in the styles.css file for your child theme. You can try out something of your own, or use the following:

This CSS does the following:

  • creates a background box behind the heading
  • changes the colour of the type to reverse out of the background
  • changes the hover state colour and removes the underline
.post-title {
    font-family: 'Playfair Display', Georgia, serif;
    font-size: 2.3em;
    line-height: 130%;
    font-weight: 700;
    color: white;
    background-color: darkslategray;
    border: 2px solid black;
    padding: 0px 5px 5px 10px;
}

.post-title a {
    color: #f1f1f1;
}

.post-title a:hover {
    color: rgb(118, 160, 101);
    text-decoration: none;
}

functions.php

Functions.php works a little different that the styles.css does. The word “cascading” in CSS means that a CSS file loaded after another will override it. This is what happens with our enqueuing function above, the parent CSS is loaded first then the child CSS with the result that the child CSS overrides the parent in areas of commonality.

functions.php works almost in reverse, the child theme functions.php is loaded first, followed by the parent. (Bear in mind that lots of other php functions in WordPress core and plugins will already have been loaded at this point.)

There are a couple of “gotcha’s” with function loading. The first one is that only one function with a given name can be loaded. So if I add a function in my child theme to replace one in the parent’s function.php file and use the same name then WordPress will throw an error when it tries to load the parent function.php, something like “function already defined” (I’m too lazy to look up the exact error wording). Unless…

Pluggable functions

In order to understand the “Unless” we need to lay down the concept of “pluggable” functions. WordPress has some pluggable functions in core, and well behaved plugins and themes may also use pluggable functions. The basic idea is to wrap the function in an if( !function_exists() ) statement. In English this means if the function does not already exist (loaded probably in the child theme functions.php file) then load this function. This is not something that is done in a child theme, but in either the parent, a plugin or WordPress core for pluggable functions.

Loading

Back to our “Unless” from above. If I create a child theme function, with the same name as a parent function then the following happens:

  1. child theme function is loaded
  2. parent theme is loaded and a “already defined” error occurs, unless
    • the parent theme has defined the function as pluggable with the if statement. This statement basically says, “let me check if the function exists already, oh, it does, okay, then I won’t load this one.”

So, I can hear you thinking, “all I have to do is use different names for my functions.” Well, yes that is certainly helpful, but does not completely eliminate gotchas, which are more commonly called conflicts. There still can be conflicts if multiple functions are attempting to modify the same thing in WordPress. We’ll talk a little bit about these as we go along.

Adding functions

There are a few more concepts we need to lay down first before we look at adding functions. Let’s get an example up here and then we can talk about these concepts.

function wpb_custom_excerpt( $output ) {
  if ( has_excerpt() && ! is_attachment() ) {
    $output .= wpb_continue_reading_link();
  }
  return $output;
}
add_filter( 'get_the_excerpt', 'wpb_custom_excerpt' );

Okay, this is an example of something that might be be found in a functions.php file.

Hooks

WordPress provides what are called “hooks” that essentially give your functions (whether in a plugin, functions.php or other php) something to hook on to in order to modify WordPress behaviour. There are two types of hooks: actions and filters. The differences are as follows:

Actions
  • Actions are essentially for php functions that do something
  • Your functions are hooked using the add_action ( ‘hook or action name’, ‘name of your function’) statement
  • Reference list of actions
Filters
  • Filters, filter or alter the output of something on its way to the page
  • Your functions are hooked using the add_filter ( ‘hook or filter name’, ‘name of your function’) statement
  • Reference list of filters

Okay, so lets try and break down the example above line by line.

  1. We first define our function by giving it a name. Of note here are the letters at the beginning of the name “wpb”, this is likely an attempt to ‘personalize’ the name to avoid function name conflicts. The rest of the name is descriptive of what the function does. We also see that the input for this function is whatever is in the variable $output, which will no doubt be the output of some other operation.
  2. Then an if statement is set up, so if what is in the $output (likely a WordPress post or page) has an excerpt and is not an attachment then what is inside the next set of curly brackets will happen.
  3. What this line does is adds the output of the wpb_continue_reading_link() function to the original output that entered the function to begin with. A couple of notes: this additional function must have been already defined somewhere else, it is likely a “read more” type link, and it will only be added if the if conditions are met.
  4. Closing curly bracket for the if statement
  5. Return $output statement. So this function takes something in, possibly adds something to it, and then sends it on its way again.
  6. Closing curly bracket for the wpb_custom_except function.
  7. Now, here is the hook. We are using add_filter because this function is filtering/altering the output of something else. Furthermore, we are hooking into WordPress’s get_the_excerpt function. So every time WordPress fires the get_the_excerpt function our filter will filter the output. Finally we name our function that we are hooking in.

As a style note, some developers put the hook statement before the function, some put it after. It works either way, but my limited sense of temporal understanding leads me to put the hook statement after. In any event it is good to keep the function/hook pairing together.

Is everyone okay? That was a bit of a slog.

A final note on some over-ride issues and then we’ll move on.

Overrides

So, what if we find ourselves in the situation where we want to use our own function in place of something already defined in the parent theme. And what if the parent theme developer has not thoughtfully designed their functions as pluggable with the if( !function_exists() ) wrapper?

Well, what we can do is use the opposite commands to the add_action and add_filter functions. We poke about in the parent theme code and (I find copy/paste handy here) take their hook statement and replace add_action/add filter with remove_action/remove_filter.

Challenge #3: Functions in the function.php file

Now the challenges are getting heavier. The aim here is to add one action and one filter to your functions.php file. Again, you can do something of your own, or use the following for simplicity.

// Replaces Howdy with welcome
function replace_howdy( $wp_admin_bar ) {
  $my_account = $wp_admin_bar->get_node('my-account');
  $newtitle = str_replace( 'Howdy,', 'Welcome,', $my_account->title );
  $wp_admin_bar->add_node( array(
    'id' => 'my-account',
    'title' => $newtitle,
  ) );
}
add_filter( 'admin_bar_menu', 'replace_howdy', 20 );


/**
 * add author dropdown filter to media library list view
 */
function media_add_author_dropdown()
{
  $scr = get_current_screen();
  if ( $scr->base !== 'upload' ) return;

  $author   = filter_input(INPUT_GET, 'author', FILTER_SANITIZE_STRING );
  $selected = (int)$author > 0 ? : '-1';
  $args = array(
    'show_option_none'   => 'All Authors',
    'name'               => 'author',
    'selected'           => $selected
  );
  wp_dropdown_users( $args );
}
add_action('restrict_manage_posts', 'media_add_author_dropdown');

Javascript

Javascript does not have the same cascading mechanism that CSS does, nor does it have the same overriding mechanism that we will see with php in the next section.

It does, however, use the same enqueuing system that CSS files do. So, you need to add your js file to the child theme and use a wp_enqueue_script function to enable it.

A couple of notes:

  • If your javascript depends on other javascript (jquery or another library for instance) set the enqueue statement to include the dependency, much as we set our child theme styles.css to depend on the the parent theme’s styles.css.
  • If your javascript conflicts with existing loaded javascript you may need to use a wp_dequeue_script function to remove the file before loading your own. Of course, this may create deficiencies that will need to be tended to.

No Javascript challenge

We don’t do a javascript challenge here, but if you javascript is strong give it a go on your own after the conference.