Child Theme Functions.php Explained

Sometimes, you follow directions to create a child theme, and it does not work. You activate your child theme, only to find a formatting issue. Most likely, the issue will be related to the order your style sheets are loaded. I experienced this when trying to create a child theme for Activello Version 1.42, and learned several changes you can make to resolve this problem.

The first of these is to use @import in the child style sheet. You might because all the docs recommended not doing it this way. If you want to go that route, skip to Why is it so broken? for an explanation and instructions.

To get an Activello child theme working without using @import, there are two other options.

option 1 – use wp_dequeue_style()

The problem with the parent theme is that it uses get_stylesheet_uri() when enqueuing its style sheet. This function by design will return the stylesheet for the child theme. The proper way to get the parent style sheet is to use “get_template_directory_uri() . ‘/style.css’“. We need to do three things to fix this.

  1. dequeue the style sheet set by the parent theme
  2. queue the parent style sheet
  3. queue the child style sheet

We can dequeue a stylesheet by using wp_dequeue_style(), but he way child themes work, our functions.php runs first. This is a problem because we can not dequeue what has not yet been queued. Also, our queued styles will come first, but we want them to be last. We can fix both of these problems by passing a higher execution priority with add_action to force our function.php to execute after the parent’s. I searched the theme and could not find any other specified priority. Since the default is 10, I chose to pass 11.

<?php
 /**
 Activello-child Theme functions and definitions
 *
 @link https://developer.wordpress.org/themes/advanced-topics/child-themes/
 *
 @package activello-child
 */ 
 add_action('wp_enqueue_scripts', 'activello_child_enqueue_styles',11);
 function activello_child_enqueue_styles()
 {
     $theme = wp_get_theme();
     $parent_handle = 'activello-style';
     $new_parent_handle = 'activello-parent-style'; //reusing dequeued handles re-enqueues them!
     $no_dependencies = array();
     wp_dequeue_style($parent_handle);
     wp_enqueue_style(
         $new_parent_handle,
         get_template_directory_uri() . '/style.css',
         $no_dependencies,
         $theme->parent()->get('Version')
     );
     wp_enqueue_style(
         'activello-child-style',
         get_stylesheet_uri(),
         array($new_parent_handle),
         $theme->get('Version')
     );
 }

I found that reusing the dequeued handle re-enqueued the old style sheet, hence the new parent handle in the code.

I confirmed my style sheets were ordered properly, by comparing the generated HTML of the themes. You can do this quickly with a command if you have access through a terminal, otherwise you can use the View Page Source feature of your browser.

$ php index.php | grep stylesheet

<link rel='stylesheet' id='activello-bootstrap-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/bootstrap.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-icons-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/font-awesome.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-fonts-css'  href='//fonts.googleapis.com/css?family=Lora%3A400%2C400italic%2C700%2C700italic%7CMontserrat%3A400%2C700%7CMaven+Pro%3A400%2C700&#038;ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-parent-style-css'  href='http://dpotus.org/wp-content/themes/activello/style.css?ver=1.4.2' type='text/css' media='all' />
<link rel='stylesheet' id='activello-child-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=1.0.0' type='text/css' media='all' />

The last two links are to the parent and child theme style sheets respectively, which is exactly what we want.

option 2 – using dependencies

You can force the order of the style sheets by setting them as dependencies. Unlike dequeuing, it is fine to let our functions.php runs first. To create a functions.php with dependencies, first examine the way the style sheets are enqueued in the parent theme functions.php, and used that information to add dependencies as needed.

<?php
 /**
 Activello-child Theme functions and definitions
 *
 @link https://developer.wordpress.org/themes/advanced-topics/child-themes/
 *
 @package activello-child
 */ 
 add_action('wp_enqueue_scripts', 'activello_child_enqueue_styles');
 function activello_child_enqueue_styles()
 {
     $theme = wp_get_theme();
     $parent_handle = 'activello-style';
     $parent_dependency_handles = array('activello-bootstrap','activello-icons','activello-fonts');
     // Add slider dependancy handle only if is front page ans slider is enabled
     if ((is_home() || is_front_page()) && get_theme_mod('activello_featured_hide') == 1) {
         $parent_dependency_handles[] = 'flexslider-css';
     }
     wp_enqueue_style(
         $parent_handle,
         get_template_directory_uri() . '/style.css',
         $parent_dependency_handles,
         $theme->parent()->get('Version')
     );
     wp_enqueue_style(
         'activello-child-style',
         get_stylesheet_uri(),
         array( $parent_handle ),
         $theme->get('Version')
     );
 }

WordPress uses our styles, because we queued them first. It ignore the erroneous declaration in the parent because we used the same handle, and the parent theme enqueue using the same handle silently fails.

<link rel='stylesheet' id='mkaz-code-syntax-css-css'  href='http://dpotus.org/wp-content/plugins/code-syntax-block/assets/blocks.style.css?ver=1608286373' type='text/css' media='all' />
<link rel='stylesheet' id='mkaz-code-syntax-prism-css-css'  href='http://dpotus.org/wp-content/plugins/code-syntax-block/assets/prism-ghcolors.css?ver=1608286373' type='text/css' media='all' />
<link rel='stylesheet' id='activello-bootstrap-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/bootstrap.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-icons-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/font-awesome.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-fonts-css'  href='//fonts.googleapis.com/css?family=Lora%3A400%2C400italic%2C700%2C700italic%7CMontserrat%3A400%2C700%7CMaven+Pro%3A400%2C700&#038;ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-style-css'  href='http://dpotus.org/wp-content/themes/activello/style.css?ver=1.4.2' type='text/css' media='all' />
<link rel='stylesheet' id='activello-child-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=1.0.0' type='text/css' media='all' />

How I got there…

Reading through Child Themes on developer.wordpress.org was very helpful. I searched the parent theme source code for all the occurrences of wp_enqueue_style in order to find all the relevant handles and to determine how the parent enqueues it’s style sheets. Depending on what is found, you may or may not need to enqueue anything.

// Add Bootstrap default CSS
 wp_enqueue_style( 'activello-bootstrap', get_template_directory_uri() . '/assets/css/bootstrap.min.css' );
 // Add Font Awesome stylesheet
 wp_enqueue_style( 'activello-icons', get_template_directory_uri() . '/assets/css/font-awesome.min.css' );
 // Add Google Fonts
 wp_enqueue_style( 'activello-fonts', '//fonts.googleapis.com/css?family=Lora:400,400italic,700,700italic|Montserrat:400,700|Maven+Pro:400,700' );
 // Add slider CSS only if is front page ans slider is enabled
 if ( ( is_home() || is_front_page() ) && get_theme_mod( 'activello_featured_hide' ) == 1 ) {
   wp_enqueue_style( 'flexslider-css', get_template_directory_uri() . '/assets/css/flexslider.css' );
 }
 // Add main theme style sheet
 wp_enqueue_style( 'activello-style', get_stylesheet_uri() );

I found Activello was using get_stylesheet_uri(), so according to the doc, I needed to enqueue the parent and child theme style sheets.

My first attempt at getting the child theme to work was following the instructions. I ended up with this:

function activello_child_enqueue_styles()
 {
     $parent_handle = 'activello-style';
     $theme = wp_get_theme();
     wp_enqueue_style(
         $parent_handle,
         get_template_directory_uri() . '/style.css',
         array(),
         $theme->parent()->get('Version')
     );
     wp_enqueue_style(
         'activello-child-style',
         get_stylesheet_uri(),
         array( $parent_handle ),
         $theme->get('Version')
     );
 }

It did not work. The parent and child style sheets were loading before bootstrap, causing styles to be overridden and my website to look weird. In hindsight, this makes sense, because my functions.php was running first, so the styles I enqueued came first.

<link rel='stylesheet' id='activello-style-css'  href='http://dpotus.org/wp-content/themes/activello/style.css?ver=1.4.2' type='text/css' media='all' />
<link rel='stylesheet' id='activello-child-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=1.0.0' type='text/css' media='all' />
<link rel='stylesheet' id='activello-bootstrap-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/bootstrap.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-icons-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/font-awesome.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-fonts-css'  href='//fonts.googleapis.com/css?family=Lora%3A400%2C400italic%2C700%2C700italic%7CMontserrat%3A400%2C700%7CMaven+Pro%3A400%2C700&#038;ver=5.6' type='text/css' media='all' />

One popular remedy I found for this situation is to set a priority on add_action so our function is executed later. I searched the theme and could not find any other specified priority. The default is 10, so I chose 11.

add_action('wp_enqueue_scripts', 'activello_child_enqueue_styles',11);

Sure enough, when I examined my HTML, I could see my style sheet links had moved to the bottom. Sadly, they both pointed to my child theme! This is because the parent enqueued the style using get_stylesheet_uri() which by design returns the child style sheet. Subsequently, my enqueue using the same handle was silently ignored. My child enqueue did work, however, but was essentially a duplicate.

<link rel='stylesheet' id='activello-bootstrap-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/bootstrap.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-icons-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/font-awesome.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-fonts-css'  href='//fonts.googleapis.com/css?family=Lora%3A400%2C400italic%2C700%2C700italic%7CMontserrat%3A400%2C700%7CMaven+Pro%3A400%2C700&#038;ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-child-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=1.0.0' type='text/css' media='all' />

Next I tried adding “activello-fonts” as a dependant to the parent style sheet. I erroneously thought this would cause the parent to load after the dependant. I soon learned that it causes the dependency to be loaded before the sheet being enqueued, so I ended up with fonts being the first thing loaded, probably ok, but not what I was trying to do.

<link rel='stylesheet' id='activello-fonts-css'  href='//fonts.googleapis.com/css?family=Lora%3A400%2C400italic%2C700%2C700italic%7CMontserrat%3A400%2C700%7CMaven+Pro%3A400%2C700&#038;ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-style-css'  href='http://dpotus.org/wp-content/themes/activello/style.css?ver=1.4.2' type='text/css' media='all' />
<link rel='stylesheet' id='activello-child-style-css'  href='http://dpotus.org/wp-content/themes/activello-child/style.css?ver=1.0.0' type='text/css' media='all' />
<link rel='stylesheet' id='activello-bootstrap-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/bootstrap.min.css?ver=5.6' type='text/css' media='all' />
<link rel='stylesheet' id='activello-icons-css'  href='http://dpotus.org/wp-content/themes/activello/assets/css/font-awesome.min.css?ver=5.6' type='text/css' media='all' />

This is when I realized I could add all the dependencies and force them to load in order. Even though this works it is not a great solution, because if things change in the parent theme something could break. This is how I decided to do it though, so I will need to check my HTML next time I upgrade the parent. Not a bad idea anyway!

Why is it so broken?

The simple answer is Activello 1.4.2 is set up to use @import. Adding the @import line to style.css and not enqueuing anything in functions.php works fine.

@import url("../activello/style.css");

Not ideal, but not a big deal either. If you check your HTML after a theme upgrade you will catch when it breaks, which will be when the theme is changed to do its own child enquing.

For the Activello parent theme to properly support enqueued style sheets in functions.php the following changes need to be made.

// Add main theme style sheet
wp_enqueue_style( 'activello-style', get_stylesheet_uri() );
// Add main theme style sheets
wp_enqueue_style('activello-style',  get_template_directory_uri() . '/style.css');
if (is_child_theme()) {
  wp_enqueue_style('activello-child', get_stylesheet_uri());
}

Then function.php in the child theme does not have to load anything, because the parent and loads both styles as WordPress recommends.