Sage 9 child theme

Has anyone attempted using Sage 9 as a parent/child theme?

Yes. This is a pretty vague post :eyes:

Sorry for the vagueness.

I am running into a problem with templates. My child theme doesn’t inherit the parent’s themes templates. Both parent and child are latest Sage 9.

The issue most likely lies in functions.php. We had always planned on writing some instructions on how to handle child themes with Sage 9’s custom template directory. If I get time, I’ll look into it this weekend.

2 Likes

I m thinking to do that.Because When we need we can update parent themes.

I m also agree because sage always upgrade their framework. So, child theme is best option now.Waiting for child theme.

@ben I am having problems using Roots 9 in a parent and child theme setup. My main problem is that the child theme does not inherit templates from its parent. I tried updating the template option in the parent theme, like you do with the stylesheet option, but that seems to break a bunch of stuff… Any guidance would be much appreciated.

I’m trying use Sage 9 for a child theme. Not sure this is best practice, but it worked for me:

In functions.php:

add_filter('template', function ($stylesheet) {
  $this_theme = wp_get_theme();
  return $this_theme['Template'];
});

if (basename($stylesheet = get_option('template')) !== 'templates') {
  $theme_dir = get_option('stylesheet');
  update_option('template', "{$theme_dir}/templates");
  wp_redirect($_SERVER['REQUEST_URI']);
  exit();
}
4 Likes

Any thoughts on this for Sage 9? I’ve tried to implement a parent/child theme, but am getting a broken theme error message on child themes saying it cannot find the parent.

@timothy_m_alber I’ve managed to change the functions.php file to get child themes working, which version of Sage 9 are you running so that I can help out?

You can find this out by checking out the CHANGELOG.MD file in the root of the theme

2 Likes

thanks @craigpearson – I am using beta 3. Very interested to know how you were able to get this working!

1 Like

Sorry about the delay, I’m looking into this now.

I had thought I’d got a solution to this but there’s an issue which I didn’t pick up on previously. And that is the template hierarchy doesn’t get overridden due to the way blade is working. i.e. creating an index.blade.php file in the child theme won’t actually override it’s equivalent in the parent - I’m not sure how I missed such a big issue.

Weirdly this behaviour is only present in beta 3 and seems to work in beta 2. I’m going to stick at this for a couple of hours and post my findings

So I don’t think this is possible with Sage 9 Beta 3.

Moving styles.css to /resources in beta 3 has had an adverse affect on the effectiveness of the WordPress function locate_template which is also used by get_template_part.

You can see that function here: https://developer.wordpress.org/reference/functions/locate_template/#source

On a singular theme level moving the style.css doesn’t really have any downsides as Sage 9 Beta 3 also has stylesheet filters in place in functions.php - when the stylesheet entry doesn’t find a template file it defaults to the template entry. All is good in the world.

However, on a child theme level the locate_template function ceases to work as expected due to the constant STYLESHEETPATH. This constant expects wordpress templating files to be in the same directory as itself for child themes to work and override templates as we’re used to. This is why get_stylesheet_directory_uri and get_template_directory_uri yield different results when used in child themes.

In a child theme when STYLESHEETPATH is filtered/changed it causes the theme to deactivate or miss template overwrites. This is because at child level the stylesheet location is used both for activation, and theme file location. When in a child and parent scenario the stylesheet entry must be the child theme’s stylesheet location, and the template entry must be the parent theme. To my knowledge it’s not possible to have your pie and eat it because of this.

The only solutions I can see for this issue are:

  • Manually require_once the parent functions file after load and drop WordPress default parent / child relationship - Most plugins, frameworks (WooCommerce etc) and themes depend on this ordering quite religiously so I don’t see this as feasible
  • Move styles.css and functions.php back to the root of the theme like in beta 2 and adjust the template directory filter when it is a child
  • Move styles.css and functions.php into the views folder or a templates folder to make finding a solution easier
  • Request a patch in WordPress core for the loading order of these files (Stupid to event think that’d be accepted)
  • Do some trickery with Laravel / Blade - a wrapper for locate template perhaps

Of course I could be completely wrong and the roots team may already have their eye on a fix

2 Likes

Thanks for the investigation @craigpearson! I hope the Roots team will have a solution for child theme compatibility!

How’d you get it working in beta 2? I’m happy to use beta 2 instead of 3.

Hey @Luke_Abell,

I’ll try and get this up for the weekend - my themes have quite a few customizations on top of sage so I need to clear out the unnecessary before sharing :thumbsup:

Thanks! Any luck getting this set up?

@Luke_Abell Really sorry about the delay with this I’m mid project and the heat is on. As a rough guide:

  • Grab the roots theme at this point before the directory change. Then cherry pick any other changes which have been merged to roots thereafter. You can cherry pick those improvements from the commit history but be sure to understand that this may well be a hands on manual process.

  • Duplicate that project as a child theme. Being sure the appropriate Template: parent-theme-folder is in your chld theme style.css in the top comments. And that your theme name is unique.

  • In the parent theme’s function file replace this block with the following:

/**
 * Sage required files
 *
 * The mapped array determines the code library included in your theme.
 * Add or remove files to the array as needed. Supports child theme overrides.
 */
array_map(function ( $file ) use ( $sage_error ) {
	if ( is_child_theme() ) {
		$file = "../src/{$file}.php";
	} else {
		$file = "src/{$file}.php";
	}

	if ( ! locate_template( $file, true, true ) ) {
		$sage_error(sprintf( __( 'Error locating <code>%s</code> for inclusion.', 'sage' ), $file ), 'File not found');
	}
}, [ 'helpers', 'setup', 'filters', 'admin' ]);
  • In the child theme functions file replace this block with the one below:
/**
 * Here's what's happening with these hooks:
 * 1. WordPress initially detects theme in themes/sage
 * 2. Upon activation, we tell WordPress that the theme is actually in themes/sage/templates
 * 3. When we call get_template_directory() or get_template_directory_uri(), we point it back to themes/sage
 *
 * We do this so that the Template Hierarchy will look in themes/sage/templates for core WordPress themes
 * But functions.php, style.css, and index.php are all still located in themes/sage
 *
 * This is not compatible with the WordPress Customizer theme preview prior to theme activation
 *
 * get_template_directory()   -> /srv/www/example.com/current/web/app/themes/sage
 * get_stylesheet_directory() -> /srv/www/example.com/current/web/app/themes/sage
 * locate_template()
 * ├── STYLESHEETPATH         -> /srv/www/example.com/current/web/app/themes/sage
 * └── TEMPLATEPATH           -> /srv/www/example.com/current/web/app/themes/sage/templates
 */
if ( is_customize_preview() && isset( $_GET['theme'] ) ) {
	$sage_error(__( 'Theme must be activated prior to using the customizer.', 'sage' ));
}

if ( basename( $stylesheet = get_option( 'template' ) ) !== 'templates' ) {
	update_option( 'template', "{$stylesheet}/templates" );
	wp_redirect( $_SERVER['REQUEST_URI'] );
	exit();
}

Finally in your child theme remove the includes which only need to be part of the parent, so for example change this block to this:

array_map(function ( $file ) use ( $sage_error ) {
	$file = "src/{$file}.php";

	if ( ! locate_template( $file, true, true ) ) {

		// $sage_error(sprintf( __( 'Error locating <code>%s</code> for inclusion.', 'sage' ), $file ), 'File not found');
	}
}, [ 'setup' ]);
  • Finally, and this is the hackiest part, manually include your parents functions file. By adding this line to very bottom of your childs functions.php file like so. Be sure to change both parent-theme-folder lines
require_once( get_theme_root( 'parent-theme-folder-name' ) . '/parent-theme-folder-name/functions.php' );

Now the reason there’s a delay in me getting this to you is that this isn’t the most elequent way, and I have got a more pragmatic solution as opposed to a manual include of the parent functions file. However that code is wrongly entwined with some other must use plugins. I’ll update this thread as soon as I can with that solution, hopefully in ~2 weeks

NB in your setup file in your child you may also want to include your parent css file, or alternatively alter your main.scss file to import your parents main.scss file depending on how you want your CSS/JS relationship to work

2 Likes

Thanks @craigpearson – have you looked into their new child theme support in beta 4?

Yep, I’d recommend updating, it works like a dream!

There’s still some modifications to make on getting JS and SASS inheriting from the parent (if needed) but definitely a lot more reliable than my hacky solution!