My parent theme has a structure like this Core\Utilities\Gallery.php
. It's in the namespace of Product\Theme\Core
and the file is loaded using composer's autoload. I thought to myself, I have a great number of filters within the theme, but when it comes to files, it'd be way, way better if one would just simply follow the same structure that the parent theme has in order to overwrite.
I know that child themes can only overwrite template files, but what's a good tool/way in a good developer's bag of tricks to overcome this?
I can even re-write the whole thing if there's a better direction.
My parent theme has a structure like this Core\Utilities\Gallery.php
. It's in the namespace of Product\Theme\Core
and the file is loaded using composer's autoload. I thought to myself, I have a great number of filters within the theme, but when it comes to files, it'd be way, way better if one would just simply follow the same structure that the parent theme has in order to overwrite.
I know that child themes can only overwrite template files, but what's a good tool/way in a good developer's bag of tricks to overcome this?
I can even re-write the whole thing if there's a better direction.
Share Improve this question asked May 7, 2020 at 1:08 Daniel SimmonsDaniel Simmons 1741 silver badge10 bronze badges1 Answer
Reset to default 1Because you're using Composer, none of the normal methods of providing child theme support apply.
For a theme that doesn't use composer, you can allow a child theme to replace a file by including it using the get_theme_file_path()
function. So in functions.php, instead of:
require_once 'Core\Utilities\Gallery.php';
You would use:
require_once get_theme_file_path( 'Core\Utilities\Gallery.php' );
get_theme_file_path()
will return the full path to the given file in the child theme, if it exists, otherwise it will give the path for it in the parent theme. This means that any file included in this way can be replaced by placing a file with that same name and path in the child theme.
For a theme that use Composer to autoload class files, this doesn't apply because you're not manually including PHP files by their path. Instead you're probably using Composer's autoloader by adding something like this in your composer.json file:
"autoload": {
"psr-4": {
"Product\\Theme\\Core\\": "Core/"
}
},
So a class like Product\Theme\Core\Utilities\Gallery
will be loaded from Core\Utilities\Gallery.php
. Since the directory is relative to the parent theme's directory, and Composer is doing the actual including, you can't use get_theme_file_path()
.*
One way to allow child themes to replace classes is to add the child theme folder to your namespace's autoloader in composer.json:
"autoload": {
"psr-4": {
"Product\\Theme\\Core\\": [ "../child-theme/Core", "Core/" ]
}
},
That will work, but the obvious problem is that it requires the child theme's name to be hardcoded into the parent theme. So it's not really a workable solution.
However, if a child theme uses composer itself, it can register one of its directories as a source for files in the parent theme's namespace. For example, if the child theme used composer and added this to its composer.json file:
"autoload": {
"psr-4": {
"Product\\Theme\\Core\\": "Core/"
}
},
Then it could replace class files in the parent theme by placing copies in its own Core/
directory, because composer would look inside the child theme for the class file too.
For this to work though you need to make sure that the child theme's vendor/autoload.php
file loads after the parent theme's, or PHP will look in the parent theme first, because the parent theme's autoloader was registered last. This is because the child theme's functions.php file loads before the parent's. The solution to this is for the child theme to load its autoloader inside the after_setup_theme
hook:
add_action(
'after_setup_theme',
function() {
require_once 'vendor/autoload.php';
}
);
You'll probably notice that with this solution the parent theme doesn't actually do anything. This is the effort a child theme could go to to replace a class, and could be done even if the parent theme didn't intend it.
* For all I know there's a way to configure Composer so that this is possible, but I'm not aware of it.