Finding theme folders for parent and child
When I started working on my theme, I was lost on finding resources like images and code files.
Child themes was a great addition to Wordpress, but IMHO it lacked support from functions to locate data that is easier to find on a unique theme structure. Functions are not intuitive, same functions behave differently when we are in parent-child structure from when we have only 1 active theme, and documentation also doesn't help.
With this article I try to clear it up a bit and share what I've learned.
- Introduction
- The needs
- How parent and child themes behave
- Getting current theme folder path and <abbr>URL</abbr>... but what's current theme?
- Let's have wider and more general control
- Getting the whole info at once!
- Plugin equivalent?
- Conclusion
- Related Posts
- Comments (0)
The needs
First, let's list our main needs when developing parent and child themes.
- Every theme must support random slug: users must be allowed to change themes slug, themes shouldn't hardcode their slug, they must get their slug dynamically and support slug renaming.
- When we are using parent-child themes, part of resources is stored on parent theme, and other part is inside child theme, for exemple child's "template files" merge child's with parent's files all together... we must have access to all resources we need, what means child theme having access to parent files
- Users may install Wordpress in a variety of ways, so themes can't force users do keep wp-content in Wordpress root and themes folder inside wp-content, for exemple
- To fulfill these needs, we must find a way to access themes files without previously knowing where each theme is, we must find theme folders on the fly, dynamically
How parent and child themes behave
This seems a lot, but during theme development we may face all these needs.
To understand how to get these data, first we must understand how child themes interact with their parent.
This may be intuitive to some ppl, but it's better to leave it explicit: child themes are always attached to a specific parent theme. Normally we can't just get a theme that is child of 'theme A' and change it to use 'theme B' as parent. A child theme is designed as extension to a specific parent theme, and also can't work without its parent, since child themes are not complete themes.
We can develop child themes to tradicional themes, but in this case we are pratically limited into tweaking its styles (we can add a new CSS file that works over original one, extending it, or remove original file and use a completely new style to it). The real power of parent and child themes is when a theme is developed to be expandable and support child themes, adding actions and filters everywhere, so that we can add new features in any place and remove code we don't want.
When Wordpress needs a file, let's say single.php
, first it searches for it in the child theme, and when not found it searches in parent theme, and when also not found it tries default theme. With this simple search structure, child themes can overwrite parent files, but that's not recommended. Normally we don't need to change whole files, but only small amount of codes, and overwriting whole files generate duplication and makes it harder to support parent theme updates, which is what child themes wanna make easier.
Anyway, all this is Wordpress work and we rarely need to bother about it. What matters is that Wordpress seems to "merge" parent and child themes into one, but paths continue separated. As I said, child theme must be developed having a specific parent theme as a basis, we can't just make a "general child theme" and get any theme as its parent.
Getting current theme folder path and URL... but what's current theme?
See how things get complicated when we use 2 themes together? When developing a parent theme, we must open space for a child we don't know how will be. And when developing a child theme, "current theme" is 2 themes together, whose files are separated. And we don't know themes' root and themes slugs when developing.
Basically, Wordpress understands "template" as "the theme that's a real theme and can run by itself". That's the parent theme when we have a child, or current theme when we use a single theme (whithout child).
We can get current parent theme URL root using get_bloginfo('template_directory')
, and folder path using TEMPLATEPATH
. This way, parent theme can securely access its files regardless if it's being used alone or with a child theme above it, it always works. Child themes also can securely access their parent files using these codes.
Now, the only file that a child theme is forced to have is style.css
. I believe that's why get_bloginfo('stylesheet_directory')
relates to child theme when one is used, and its relative local file path is STYLESHEETPATH
.
Then, "stylesheet" means "where style.css
is, regardless of if it's inside 'template' or not", which points to the child theme when there's one.
The problem is that when a single theme is used, both "template path" and "stylesheet path" points to the same place, since style.css
is inside our "template". Tradicional themes and themes that are not designed and tested to work with a child may not note this "small" difference, and may refere to "stylesheet", which will point to its child theme when one is available, and break what it's trying to access.
Resuming: complete themes, that can be used alone or with a child, should always see themselves as "template", using get_bloginfo('template_directory')
to access its own root as URL, and TEMPLATEPATH
as local path. These codes can also be used when child themes need access to their parents!
And when child themes must access their own files, the best way is using get_bloginfo('stylesheet_directory')
for URL, and STYLESHEETPATH
for local access. Although these codes work when single themes are used, they should be avoided since they won't work as expected if a child theme is in use, but themes designed to be parent can use them when they must access some child resource, just have in mind that a child may not be there and in this case they (the parent theme running as single) will point to themselves.
Let's have wider and more general control
Yes, I know, that's far from intuitive and very confusing. Something based in "parent" and "child", "this", "single" and stuff like that would be much better than "template" and "stylesheet".
There are other ways to get themes paths that I found out, and here I'm gonna list some alternatives.
If we call get_theme_root()
passing no parameter to it, we'll get themes folder's local path, for exemple /home/user/www/wordpress/wp-content/themes
. If we knew themes slugs, we could just append it to this function and we'd have the path root to any available theme... if we knew, because as I said we can't hardcode themes and plugins slugs and block users from renaming them.
But there's also another problem with using this function without passing a parameter. I don't know how, but it seems that we can store different themes in different places, at least Wordpress supports it.
If we call get_theme_root($slug)
passing a theme slug to it, it returns that theme root path, as in /home/user/www/wordpress/wp-content/themes
. And there's another function, get_theme_root_uri($slug)
, that does the same thing, but now with themes URL: http://domain.org/wp-content/themes
.
But, after all, how to we get themes slugs??
get_theme_roots()
is the answer. This function returns an array of themes, whose indexes are the slugs, and their values are their roots. As I've just said, because of this function it seems each theme can be installed in a different place. IDK how to do that, my guess is that we can't, but Wordpress API supports it in case it's implemented in the future, or maybe it's related to Wordpress MU where it seems each site can have its own themes and there's a place where "global" themes are stored. Well I don't know why, but each theme has its own root, so we must support it too!
To better understand it, use the following code in your Wordpress install:
<?php echo 'get_theme_roots(): <br /><pre>'.print_r(get_theme_roots(),true).'</pre><br /><br /><br />'; echo '<ol>'; foreach(get_theme_roots() as $slug => $root){ ?> <li><?php echo $slug; ?> theme: <ul> <li><strong>slug / array index</strong>: <?php echo $slug; ?></li> <li><strong>root</strong>: <?php echo $root; ?></li> <li><strong>folder path</strong>: <?php echo get_theme_root($slug).'/'.$slug.'/'; ?></li> <li><strong><abbr>URL</abbr></strong>: <?php echo get_theme_root_uri($slug).'/'.$slug.'/'; ?></li> </ul> </li> <?php } echo '</ol>'; ?>
Here's what I get in my development environment:
Array ( [classic] => /themes [default] => /themes [hikari-semantic-website] => /themes [hikari-semantic] => /themes )
- classic theme:
- slug / array index: classic
- root: /themes
- folder path: D:\dev\apache\htdocs\dev/wp-content/themes/classic/
- URL: http://localhost/dev/wp-content/themes/classic/
- default theme:
- slug / array index: default
- root: /themes
- folder path: D:\dev\apache\htdocs\dev/wp-content/themes/default/
- URL: http://localhost/dev/wp-content/themes/default/
- hikari-semantic-website theme:
- slug / array index: hikari-semantic-website
- root: /themes
- folder path: D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website/
- URL: http://localhost/dev/wp-content/themes/hikari-semantic-website/
- hikari-semantic theme:
- slug / array index: hikari-semantic
- root: /themes
- folder path: D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/
- URL: http://localhost/dev/wp-content/themes/hikari-semantic/
As you can see, with get_theme_roots()
results we get a list of all themes slugs, and then we just need to use get_theme_root($slug)
or get_theme_root_uri($slug)
to get any theme's local and URL root, and append the slug again to get their specific folder.
But there's still something not so good... if users can rename themes slugs, it's not confortable, to say the least, browse get_theme_roots()
's array for slugs, searching for something "somehow similar" to our themes names. What if the uset changes his themes slugs to "theme1", "theme2", "theme3"? Our theme code would totally break, since we'd not be able to find which of these themes is ours and get its folder path.
There must be some better and more secure way to find themes infos...
Getting the whole info at once!
get_themes()
, that's Wordpress's greatest magic! it returns an array with all themes, and for each theme an array with aaaaaaaal available data about it! Take a look on what this array has in my system!:
Array ( [WordPress Classic] => Array ( [Name] => WordPress Classic [Title] => WordPress Classic [Description] => The original WordPress theme that graced versions 1.2.x and prior. [Author] => Dave Shea [Version] => 1.5 [Template] => classic [Stylesheet] => classic [Template Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/comments-popup.php [1] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/comments.php [2] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/footer.php [3] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/functions.php [4] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/header.php [5] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/index.php [6] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/sidebar.php ) [Stylesheet Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/rtl.css [1] => D:\dev\apache\htdocs\dev/wp-content/themes/classic/style.css ) [Template Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/classic [Stylesheet Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/classic [Status] => publish [Screenshot] => screenshot.png [Tags] => Array ( ) [Theme Root] => D:\dev\apache\htdocs\dev/wp-content/themes [Theme Root URI] => http://localhost/dev/wp-content/themes [Parent Theme] => ) [WordPress Default] => Array ( [Name] => WordPress Default [Title] => WordPress Default [Description] => The default WordPress theme based on the famous Kubrick. [Author] => Michael Heilemann [Version] => 1.6 [Template] => default [Stylesheet] => default [Template Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/default/404.php [1] => D:\dev\apache\htdocs\dev/wp-content/themes/default/archive.php [2] => D:\dev\apache\htdocs\dev/wp-content/themes/default/archives.php [3] => D:\dev\apache\htdocs\dev/wp-content/themes/default/attachment.php [4] => D:\dev\apache\htdocs\dev/wp-content/themes/default/comments-popup.php [5] => D:\dev\apache\htdocs\dev/wp-content/themes/default/comments.php [6] => D:\dev\apache\htdocs\dev/wp-content/themes/default/footer.php [7] => D:\dev\apache\htdocs\dev/wp-content/themes/default/functions.php [8] => D:\dev\apache\htdocs\dev/wp-content/themes/default/header.php [9] => D:\dev\apache\htdocs\dev/wp-content/themes/default/index.php [10] => D:\dev\apache\htdocs\dev/wp-content/themes/default/links.php [11] => D:\dev\apache\htdocs\dev/wp-content/themes/default/page.php [12] => D:\dev\apache\htdocs\dev/wp-content/themes/default/search.php [13] => D:\dev\apache\htdocs\dev/wp-content/themes/default/searchform.php [14] => D:\dev\apache\htdocs\dev/wp-content/themes/default/sidebar.php [15] => D:\dev\apache\htdocs\dev/wp-content/themes/default/single.php [25] => D:\dev\apache\htdocs\dev/wp-content/themes/default/images/header-img.php ) [Stylesheet Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/default/rtl.css [1] => D:\dev\apache\htdocs\dev/wp-content/themes/default/style.css ) [Template Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/default [Stylesheet Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/default [Status] => publish [Screenshot] => screenshot.png [Tags] => Array ( ) [Theme Root] => D:\dev\apache\htdocs\dev/wp-content/themes [Theme Root URI] => http://localhost/dev/wp-content/themes [Parent Theme] => ) [Semantic Hikari Website] => Array ( [Name] => Semantic Hikari Website [Title] => Semantic Hikari Website [Description] => Semantic Hikari Website theme is a child of <a href="http://Hikari.ws">Hikari Semantic Theme</a> [Author] => <a href="http://Hikari.ws" title="Visit author homepage">Hikari</a> [Version] => 0.00 [Template] => hikari-semantic [Stylesheet] => hikari-semantic-website [Template Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website/functions.php [1] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/404.php [2] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/503.php [3] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/archive.php [4] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/attachment.php [5] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/comments.php [6] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/footer.php [7] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/admin.php [8] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/classes.php [9] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/comments.php [10] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/libs.php [11] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/options.php [12] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/plugin.php [13] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/tags.php [14] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions.php [15] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/header.php [16] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/images/index.php [17] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/index.php [18] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/page.php [19] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/search.php [20] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/searchform.php [21] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-bottom.php [22] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-bottomcontent.php [23] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-comment.php [24] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-left.php [25] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-top.php [26] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-topcontent.php [27] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar.php [28] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/single.php [29] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/src/index.php ) [Stylesheet Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website/style-hkws.css [1] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website/style.css ) [Template Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website [Stylesheet Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic-website [Status] => publish [Screenshot] => screenshot.png [Tags] => Array ( ) [Theme Root] => D:\dev\apache\htdocs\dev/wp-content/themes [Theme Root URI] => http://localhost/dev/wp-content/themes [Parent Theme] => Hikari Semantic Theme ) [Hikari Semantic Theme] => Array ( [Name] => Hikari Semantic Theme [Title] => Hikari Semantic Theme [Description] => <a href="http://Hikari.ws">Hikari</a>’s theme to be used as a base to his other themes. [Author] => <a href="http://Hikari.ws" title="Visit author homepage">Hikari</a> [Version] => 1.00 [Template] => hikari-semantic [Stylesheet] => hikari-semantic [Template Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/404.php [1] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/503.php [2] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/archive.php [3] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/attachment.php [4] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/comments.php [5] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/footer.php [6] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions.php [7] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/header.php [8] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/index.php [9] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/page.php [10] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/search.php [11] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/searchform.php [12] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-bottom.php [13] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-bottomcontent.php [14] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-comment.php [15] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-left.php [16] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-top.php [17] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar-topcontent.php [18] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/sidebar.php [19] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/single.php [26] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/admin.php [27] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/classes.php [28] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/comments.php [29] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/libs.php [30] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/options.php [31] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/plugin.php [32] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/functions/tags.php [35] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/images/index.php [48] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/src/index.php ) [Stylesheet Files] => Array ( [0] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/ie6.css [1] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/reset.css [2] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/style-hksmtc-default.css [3] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/style-hksmtc.css [4] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic/style.css ) [Template Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic [Stylesheet Dir] => D:\dev\apache\htdocs\dev/wp-content/themes/hikari-semantic [Status] => publish [Screenshot] => screenshot.png [Tags] => Array ( ) [Theme Root] => D:\dev\apache\htdocs\dev/wp-content/themes [Theme Root URI] => http://localhost/dev/wp-content/themes [Parent Theme] => ) )
Awesome, isn't it? Array's index is themes name, so we can just use $themes['theme name']
, being 'theme name' the name we set in style.css
, that never changes, and then we have an array with everything we may want!
Use $themes['parent theme name']['Version']
and we can verify our parent version, for compatibility for exemple.
Use $themes['this theme name']['Template']
and we have the slug of our parent theme or current single theme (if it's called from a full theme that can run alone or be a parent theme). Or use $themes['this theme name'][' Stylesheet']
and we have the slug of our child theme (or our current single theme, if there's no child theme in use).
Big and with more info than we need, but fully complete, and secure to access!
Plugin equivalent?
With this kind of data being available for themes, we start wanting the same for plugins, of course. And to make this tutorial complete I'm gonna teach some tricks for them too.
In our plugin main file, we can use plugin_basename(__FILE__)
and we'll have a string with the plugin's slug + main file name. That's used for exemple to generate activating and deactivating links.
plugin_dir_path(__FILE__)
returns the plugin local root path, and plugin_dir_url(__FILE__)
its URL root.
get_plugin_data(__FILE__)
gives us all info we add to our plugin header, but to use this function we must use require_once ABSPATH.'\wp-admin\includes\plugin.php';
before it, because the file it's defined is only included when user is in admin pages.
Conclusion
I hope this tutorial helps Wordpress developers to have an easier time accessing their themes and plugins resources.
For sure these solutions are not simple, easy or intuitive as we'd like them, but that's what Wordpress offers us, and at least we can access any resource we want with them.
I hope ppl can get something useful from this article, any question or suggestion just leave a comment .
Popularity: 6%
- action hook
- child theme
- development environment
- dynamic
- extension
- filter hook
- folder
- get_bloginfo
- get_plugin_data
- get_theme_root
- get_theme_root_uri
- get_theme_roots
- get_themes
- parent theme
- plugin
- plugin_basename
- plugin_dir_path
- plugin_dir_url
- root
- slug
- stylesheet
- stylesheet_directory
- STYLESHEETPATH
- template
- template_directory
- TEMPLATEPATH
- theme
- Tutorial
It has accumulated a total of 20,287 views. You can follow any comments to this article through the Comments RSS 2.0 Feed. You can leave a comment, or trackback from your own site.
Comentando vc contribui e participa na criação do conteúdo do site.
Contribua. Commente. :)
(Os comentários abaixo representam a opinião dos visitantes, o autor do site não se responsabiliza por quaisquer consequências e/ou danos que eles venham a provocar.)