Make WordPress Core

Opened 13 years ago

Closed 8 years ago

Last modified 7 years ago

#18302 closed enhancement (fixed)

Improve child theme file inheritance by introducing a function to locate a file URI

Reported by: johnbillion's profile johnbillion Owned by: johnbillion's profile johnbillion
Milestone: 4.7 Priority: high
Severity: normal Version:
Component: Themes Keywords: has-patch commit has-unit-tests
Focuses: template Cc:

Description

Child theme file inheritance isn't quite as slick as it could be. A child theme should be able to selectively override any of its parent theme's files (ie. CSS & JS), not just template files.

For example, there's no easy way for a parent theme to enqueue a JavaScript file that can be easily overridden by a child theme. This is because there's no URI version of locate_template() for themes to use.

Example: A parent theme includes a JavaScript file like so:

wp_enqueue_script( 'foo', get_template_directory_uri() . '/foo.js' );

A child theme couldn't simply include a foo.js file to override its parent's as the file is always loaded from the template directory, not the stylesheet directory. If the parent theme used get_stylesheet_directory_uri() instead, then the child theme could override it but it would have to override it, otherwise we'd end up with a file not found.

The answer is to introduce a function that does the same as locate_template() but returns a URI instead of a path.

Example usage:

wp_enqueue_script( 'foo', locate_theme_file( 'foo.js' ) );

This would load foo.js from the child theme if it existed, and the parent theme if not.

The function could also be used for CSS files:

wp_enqueue_style( 'bar', locate_theme_file( 'bar.css' ) );

And for images too:

<img src="<?php echo locate_theme_file( 'icon.png' ); ?>" />

Stand by for a patch.

Attachments (21)

18302.patch (1.5 KB) - added by johnbillion 13 years ago.
18302.twentyeleven.patch (1.9 KB) - added by johnbillion 13 years ago.
Example usage in TwentyEleven
18302.2.patch (3.0 KB) - added by johnbillion 13 years ago.
18302.2.2.patch (1.5 KB) - added by johnbillion 13 years ago.
18302.theme_url.diff (1.2 KB) - added by georgestephanis 12 years ago.
Moving function from themes to link-template along with related plugins_url() content_url() and such
18302.theme_url.2.diff (1.3 KB) - added by georgestephanis 12 years ago.
Added in ltrim( $file, '/' ); to account for theme authors using it as theme_url( '/images/logo.gif' );
18302.theme_url.3.diff (1.7 KB) - added by georgestephanis 12 years ago.
18302.theme_url.4.diff (1.0 KB) - added by georgestephanis 12 years ago.
18302.theme_url.5.diff (1.1 KB) - added by georgestephanis 12 years ago.
Changing away from TEMPLATEPATH and STYLESHEETPATH as per #18298
18302.theme_url.6.diff (1.2 KB) - added by georgestephanis 12 years ago.
Tweaks, etc.
18302.theme_url.7.diff (1.2 KB) - added by georgestephanis 12 years ago.
Adding in caveat for not passing argument
18302.theme_url.8.diff (7.7 KB) - added by georgestephanis 12 years ago.
Patching over twentyten twentyeleven twentytwelve as per westi
18302.9.diff (7.5 KB) - added by georgestephanis 12 years ago.
18302.10.diff (7.7 KB) - added by georgestephanis 12 years ago.
18302.11.diff (7.7 KB) - added by georgestephanis 12 years ago.
18302.12.diff (1.5 KB) - added by georgestephanis 12 years ago.
18302.13.diff (1.5 KB) - added by georgestephanis 12 years ago.
18302.14.diff (1.5 KB) - added by georgestephanis 12 years ago.
WTF, I missed a parentheses? DAGNABBITT!
18302.15.diff (1.5 KB) - added by gma992 8 years ago.
link-template.php needed refresh, nothing new added
18302-test.php (648 bytes) - added by gma992 8 years ago.
Starting Unit Testing
18302.diff (9.8 KB) - added by johnbillion 8 years ago.

Download all attachments as: .zip

Change History (125)

@johnbillion
13 years ago

@johnbillion
13 years ago

Example usage in TwentyEleven

#1 @johnbillion
13 years ago

  • Keywords has-patch dev-feedback added; needs-patch removed

Here we have a patch that introduces locate_theme_file(). It does the same as locate_template() but returns a URI instead of the file name.

There's also a patch showing usage in TwentyEleven. A child theme of TwentyEleven could now simply include its own version of any of its CSS or JS files and they would be used in place of TwentyEleven's.

To discuss:

  • Does this function need a better name?
  • Do we also need an abstracted wrapper function in general-template.php?

#2 @westi
13 years ago

  • Keywords westi-likes added
  • Owner set to westi
  • Status changed from new to reviewing

I like the idea here of simplification the override in child themes.

I'll have a look at the current proposal and give some feedback

#3 @scribu
13 years ago

+1 on the idea. On to specifics:

  • We shouldn't use STYLESHEETPATH and TEMPLATEPATH anymore: #18298
  • There's no rhyme and reason between the names 'locate_theme_file' and 'locate_template'. Maybe call it locate_template_uri() instead?

#4 @johnbillion
13 years ago

Patch refreshed. Ignore 18302.2.patch as it accidentally contains other unrelated changes.

18302.2.2.patch changes the function name to locate_template_uri() and uses get_template|stylesheet_directory() instead of the constants.

I'm still wondering whether a nicer named template function could be a good idea. locate_template_uri() is rather a technical name and something like get_theme_file() would be nicer for theme developers to use. Suggestions?

#5 @DrewAPicture
13 years ago

  • Cc DrewAPicture added

#6 @scribu
13 years ago

  • Keywords dev-feedback removed
  • Milestone changed from Awaiting Review to 3.3

#7 @F J Kaiser
13 years ago

  • Cc 24-7@… added

+1

A drawback of <code>locate_template()</code> is that you can't really use it to locate templates from within a plugin directory - which imo would make sense if you consider the number of plugins working with custom post types. I hope there's a slight chance that <code>locate_template_uri()</code> also supports plugin directories, so default styles could be packed right with the plugin.

#8 follow-up: @scribu
13 years ago

A drawback of <code>locate_template()</code> is that you can't really use it to locate templates from within a plugin directory

That's a whole other can of worms and should be discussed in a different ticket.

#9 @strider72
13 years ago

  • Cc strider72 added

#10 @DrewAPicture
13 years ago

Any movement on this ticket? As somebody who does an awful lot of child themeing, the ability to overload javascript/almost any parent theme file is HUGE. What can we do to push this through?

#11 in reply to: ↑ 8 @F J Kaiser
13 years ago

Replying to scribu:

A drawback of <code>locate_template()</code> is that you can't really use it to locate templates from within a plugin directory

That's a whole other can of worms and should be discussed in a different ticket.

I understand that the discussion should/could be in some other ticket, but this would also mean that we have to wait until this ticket is approved and then make the next step.

#12 follow-up: @ryan
13 years ago

  • Milestone changed from 3.3 to Future Release

Punting enhancements from 3.3

#13 in reply to: ↑ 12 @johnbillion
13 years ago

Replying to ryan:

Punting enhancements from 3.3

Why? This is a functional addition and has a patch and has support from core devs.

#14 @scribu
13 years ago

Even with support from a lead dev, if it's not commited on time, it doesn't get in:

http://wpdevel.wordpress.com/version-3-3-project-schedule/

#15 @scribu
13 years ago

Closed #19267 as dup.

#16 @scribu
13 years ago

  • Milestone changed from Future Release to 3.4

#17 @eddiemoya
13 years ago

  • Cc eddie.moya+wptrac@… added

#18 @ryan
13 years ago

  • Milestone changed from 3.4 to Future Release

Worth pursuing, but punting from 3.4 per bug scrub.

#19 @picklesworth
13 years ago

  • Cc picklesworth added

@georgestephanis
12 years ago

Moving function from themes to link-template along with related plugins_url() content_url() and such

#20 @georgestephanis
12 years ago

Rewrote patch as new function theme_url() in 18302.theme_url.diff and migrated to wp-includes/link-template.php to be with its family.

Related: #19267

theme_url( 'images/logo.gif' ); is going to be a lot easier for people to remember than locate_theme_file( 'images/logo.gif' );

#21 @scribu
12 years ago

  • Milestone changed from Future Release to 3.5

I like the name 'theme_url()' better too.

#22 @georgestephanis
12 years ago

  • Summary changed from Improve child theme file inheritance by introducing a function to locate a file URI to Improve child theme file inheritance by introducing `theme_url()` to locate a file URI

@georgestephanis
12 years ago

Added in ltrim( $file, '/' ); to account for theme authors using it as theme_url( '/images/logo.gif' );

#23 @nacin
12 years ago

This looks great in theory. Digging into how it works, here are my thoughts:

This function is designed to allow child themes to override parent themes, without the parent theme needing to jump through hoops to prevent the requirement that a child theme override a random file such as an image. To me, it sounds like it should always return a URI. It's a simple check: If the file exists in the child theme, use it. Otherwise, return the URL as if it exists in the parent theme. And if we're not dealing with a child theme, we can even avoid any file_exists() checks this way.

#24 @georgestephanis
12 years ago

Two rewrites, one for still accepting an array of fallbacks, one for simply taking a string, and checking the child theme first.

@georgestephanis
12 years ago

Changing away from TEMPLATEPATH and STYLESHEETPATH as per #18298

@georgestephanis
12 years ago

Tweaks, etc.

@georgestephanis
12 years ago

Adding in caveat for not passing argument

#25 @westi
12 years ago

I like the look of 18302.theme_url.7.diff

Can we also have a patch now for how this would be used in the default themes and for some unit tests for the new functions usage?

#26 @SergeyBiryukov
12 years ago

A note on @since: in other functions we use @since 3.5.0 (vs. 3.5).
Related: #19638

@georgestephanis
12 years ago

Patching over twentyten twentyeleven twentytwelve as per westi

#27 follow-up: @georgestephanis
12 years ago

Latest patch fixes Sergey's point about 3.5.0, and modifies existing themes to provide examples and use cases.

#28 @nacin
12 years ago

  • Keywords needs-unit-tests added

#29 in reply to: ↑ 27 @scribu
12 years ago

Should we make all JS files overwritable, though?

#30 @georgestephanis
12 years ago

I would think so. That way if you want to change something in a scripts.js file in the parent theme, you can easily, but you're not forced to.

#31 follow-up: @scribu
12 years ago

The problem is that it's all-or-nothing; if you overwrite a file, you have to copy all the other code that you're not interested in changing, which hurts maintenance and back-compat. Parent theme developers would then be inclined to split their JS code into more files, which hurts performance.

In contrast, if the JS file isn't overwritable, you're inclined to just enqueue another one on top, which also hurts performance, but not as much.

#32 follow-up: @georgestephanis
12 years ago

Right, so let's give them the choice. The parent theme writer doesn't NEED to use theme_url().

OR, we could add a boolean argument to let them force the URL to come from the parent theme.

#33 in reply to: ↑ 32 @scribu
12 years ago

I guess I should have made my question more explicit:

Should we make all JS files in the Twentytwelve theme overwritable?

#34 @scribu
12 years ago

I guess most people will start using theme_url() anyway, since it's just nicer than using get_template_directory_uri().

#35 @scribu
12 years ago

Or, we could just trust that child theme devs will have the sense to enqueue an additional small JS file, instead of copying over hundreds of lines of JS code that they'll have to maintain afterwards. :)

#36 @georgestephanis
12 years ago

I would say yes, as it would simplify child theme inheritance. If they want to override a file, they can do it. ::thumbsup:: If they don't, they aren't forced to.

#37 @georgestephanis
12 years ago

Following discussion in IRC, I'll rewrite the patch to add a second boolean parameter to theme_url() of $overwritable, defaulting to true. If the user sets it to false, it forces the returned URL to be from the parent theme. Otherwise, it's child first, if it exists, otherwise parent.

#38 follow-up: @Otto42
12 years ago

Suggestion: Naming confusion abounds around there. Why not go whole hog and rethink the naming, deprecating old confusing naming along with it.

Straw man Proposal:

function theme_url($path='', $theme='') : Gets the URL to a specified file ($path) in the current theme, accounting for existence of the file in the child/parent situation (child if exists, parent if not). If the $theme is specified via the slug (or __FILE__), then the child/parent is not accounted for, using the specified theme directly.

function child_theme_url($path='') : same, but only accounts for child, false if no file exists. Essentially a shortcut to theme_url with the child theme specified as the $theme.

function parent_theme_url($path='') : same but only accounts for parent. Essentially a shortcut to theme_url with the parent theme specified as the $theme.

Like-named functions: theme_file, child_theme_file, parent_theme_file: Do the same as above but return full path to the file, suitable for including or whatever.

Is there anything else that is ever needed at this low of a level? We have many things like locate_template and such, and those might be able to be simplified greatly using something along these lines.

Naming is dealer's choice, I'm thinking about overall functionality here to simplify the whole system.

#39 in reply to: ↑ 38 @scribu
12 years ago

Replying to Otto42:

function theme_url($path='', $theme='') : Gets the URL to a specified file ($path) in the current theme, accounting for existence of the file in the child/parent situation (child if exists, parent if not). If the $theme is specified via the slug (or __FILE__), then the child/parent is not accounted for, using the specified theme directly.

-1 on passing the theme slug as a parameter. There's only one parent theme and possibly one child theme running at a time; we should continue to take advantage of that.

So, the $theme parameter should only take two values: 'child' or 'parent'.

#40 @Otto42
12 years ago

scribu: I included that for parity with the plugins_url() function. It's possible that other code may want to use this outside of the current theme. Plugins, stuff in the WP_Theme, dunno. I was trying to be generic as possible.

#41 follow-up: @georgestephanis
12 years ago

Why would we want to force a child url if the file it's pointing at doesn't exist?

#42 follow-up: @scribu
12 years ago

Parity with plugins_url() doesn't make that much sense, since you can run 100 plugins at the same time.

Super-generic API like that can go in WP_Theme, not in theme_url(), which is basically a template tag.

#43 in reply to: ↑ 41 @Otto42
12 years ago

Replying to georgestephanis:

Why would we want to force a child url if the file it's pointing at doesn't exist?

How do you know it exists until you check?

Perhaps a theme would want to do something different if the child theme includes a specific file. If you're allowing children to override JS/CSS code, then this is possible.

#44 in reply to: ↑ 42 @Otto42
12 years ago

Replying to scribu:

Parity with plugins_url() doesn't make that much sense, since you can run 100 plugins at the same time.

Super-generic API like that can go in WP_Theme, not in theme_url(), which is basically a template tag.

Presumably, most themes wouldn't be using that parameter anyway.

Also, if you limit it to child/parent, then there is no point to having that parameter at all, since other functions would exist to take care of that for you. In which case the function would be themes_url($path='') and no optional second parameter.

Note that I'm assuming that the guts of this function is essentially going to be a call into the WP_Theme API in the first place, like it should be. Like all theme template tags should be. All theme related stuff should eventually move into there, with suitable wrappers for usage by themes/plugins to make life simpler.

Last edited 12 years ago by Otto42 (previous) (diff)

#45 @georgestephanis
12 years ago

Okay, just added 18302.9.diff

Here's my defense for this implementation:

IF YOU WANT:

to use the file 'js/foo.js' that exists in the child theme, call theme_url( 'js/foo.js' ); -- as it will always return the child theme url if the file exists. I don't think anyone would want it to return a url to a file that doesn't exist!

to use the file 'js/foo.js' from the parent theme without checking the child theme, call theme_url( 'js/foo.js', false ); -- to skip even checking if a child theme exists and kick it directly to the parent theme.

to use the file 'js/foo.js' if it exists in the child, or fall back to the parent if it doesn't (allow for graceful inheritance) just call theme_url( 'js/foo.js' ); -- and be happy.

I think that anyone trying to do special things if a file exists in a child theme are definitely out of the mainstream, and that's kinda overthinking the issue at hand. Let's keep it clean, simple, and functional. If someone wants to do a trapeze act, they can write their own function for it, as it's very much a hyperspecialized task.

#46 follow-up: @georgestephanis
12 years ago

Latest patch accounts for use cases where people do something like theme_url( 'js/foo.js?version=1.8.1' ); to avoid caching problems.

#47 @georgestephanis
12 years ago

Ugh. Last change, I promise. Stashed $rawfile argument, so it could be passed cleanly to the filter at the end.

#48 in reply to: ↑ 46 @scribu
12 years ago

Replying to georgestephanis:

Latest patch accounts for use cases where people do something like theme_url( 'js/foo.js?version=1.8.1' ); to avoid caching problems.

And with that you're stepping into the turf of wp_register_script().

#49 @georgestephanis
12 years ago

It's not meant to be used that way, I only included it to prevent it from failing to detect a file because someone used it that way. I ran it by nacin in IRC, and it seemed far better than the function eternally missing a file in a child theme because someone left a get variable in it, and file_exists() couldn't spot it.

#50 @Otto42
12 years ago

I agree with scribu here, that shouldn't be a viable use case. If you want to do that sort of thing, then you should properly enqueue the script. A child theme can dequeue your script and enqueue their own on the after_setup_theme hook if they want to do so.

If you include support for GET variables, then somebody most certainly *will* use it that way, even when they definitely should not be. And then we'll have to add new checks to theme-check, and new rules to prevent people from using it incorrectly...

No, limit the scope back to files only. If somebody does it wrong, then they should get wrong results.

#51 @georgestephanis
12 years ago

Okiedok, then should be good to do 18302.9.diff instead. :)

#52 @ramiy
12 years ago

Related: #19200

#53 @toscho
12 years ago

  • Cc info@… added

#54 @nacin
12 years ago

This is on the agenda for the Sept 26 dev meeting.

#55 @georgestephanis
12 years ago

Fourth and inches, the call comes down to punt.

#56 follow-up: @nacin
12 years ago

  • Milestone changed from 3.5 to Future Release

I think this is one of those situations where it is so close but we don't have it. The feature doesn't quite know what it wants to do, what it is supposed to do, or where it should be used. From IRC:

  • "my original use case was for overriding images and JS in a child theme, but i can see that it could potentially introduce bad practices in child themes" (johnbillion)
  • "I'm currently in punt because it keeps getting more weird and awkward" (westi)
  • "I think the original idea was great, but it just seems to open the door for too much strange/bad practice" (westi)
  • "I'm ok with punting, i use my own version of the function in my own themes anyway" (johnbillion)

#57 @WraithKenny
12 years ago

also from the IRC logs, a potential future direction for this:

"theme_url() (parent theme only) and child_theme_url() (uses child theme URL if it exists) in the future could potentially handle it" (nacin)

#58 @greenshady
12 years ago

  • Cc justin@… added

#59 @georgestephanis
12 years ago

18302.12.diff splits the force_parent out into its own function, so we've got theme_url() and parent_theme_url()

#60 @scribu
12 years ago

The thing that makes these functions valuable is the filters; the most obvious example I can think of is using them to serve all the assets from a CDN.

#61 @georgestephanis
12 years ago

Can we get this into 3.6?

#62 @amommy
12 years ago

  • Cc amommy added

#63 @chipbennett
12 years ago

  • Cc chip@… added

I was just about to propose a nearly identical patch to:
http://core.trac.wordpress.org/attachment/ticket/18302/18302.12.diff

What can we do to get this pushed into 3.6?

#64 in reply to: ↑ 56 @chipbennett
12 years ago

Replying to nacin:

I think this is one of those situations where it is so close but we don't have it. The feature doesn't quite know what it wants to do, what it is supposed to do, or where it should be used. From IRC:

  • "my original use case was for overriding images and JS in a child theme, but i can see that it could potentially introduce bad practices in child themes" (johnbillion)
  • "I'm currently in punt because it keeps getting more weird and awkward" (westi)
  • "I think the original idea was great, but it just seems to open the door for too much strange/bad practice" (westi)
  • "I'm ok with punting, i use my own version of the function in my own themes anyway" (johnbillion)

My preference would be to limit the function to return a file URL: i.e. a function that is analogous to locate_template(), except that it doesn't try to load anything, and simply returns either get_stylesheet_directory_uri() . '/' . $file or get_template_directory_uri() . '/' . $file. I could attach the patch I was going to submit, but I think it's covered in the latest diff already.

My naming preference would therefore also be: theme_file_uri(), rather than theme_url(). The latter is confusing, because it implies that the function is return the URL of the Theme, rather than the URL of a file contained in the Theme.

#65 @greenshady
12 years ago

This should be simple. Here's the code I've been using, which works fine. From here:
https://github.com/justintadlock/hybrid-core/blob/1.5/functions/utility.php#L224

function hybrid_locate_theme_file( $file_names ) {

	$located = '';

	/* Loops through each of the given file names. */
	foreach ( (array) $file_names as $file ) {

		/* If the file exists in the stylesheet (child theme) directory. */
		if ( is_child_theme() && file_exists( trailingslashit( get_stylesheet_directory() ) . $file ) ) {
			$located = trailingslashit( get_stylesheet_directory_uri() ) . $file;
			break;
		}

		/* If the file exists in the template (parent theme) directory. */
		elseif ( file_exists( trailingslashit( get_template_directory() ) . $file ) ) {
			$located = trailingslashit( get_template_directory_uri() ) . $file;
			break;
		}
	}

	return $located;
}

That's all we need. Something simple that allows child themes to overwrite the file.

#66 follow-ups: @georgestephanis
12 years ago

Yeah, we'd suggested that earlier, but occasionally the parent theme will want to include a file that they don't want the child theme to override.

Because ... reasons. Or whatever. Scribu put a case for it together in an earlier comment (http://core.trac.wordpress.org/ticket/18302#comment:31)

We were toying with making it one function with a boolean to let you choose whether to override or not, but it seemed overly complicated, and our core structures should value understandability over cleverness, so down at Tybee there was a conversation out on the deck of the Jitterbug to do what's currently here, theme_url() -- which lets overrides, but falls back to parent, and parent_theme_url() -- which forces the parent. As noone will ever want to force child if the file doesn't exist, as that's just silly.

ANYWAY.

New patch 18302.13.diff attached incorporating Chip's proposed naming schema, and upping the phpdoc @since parameter to 3.6.0

#67 @greenshady
12 years ago

For the purposes of the ticket as outlined, I'd just go with the one function to locate a theme file. The ticket description actually covers a real need, and that's to allow child themes to overwrite parent theme files. That's not something that's currently possible without a custom theme function, which is something both others and I have done in our themes.

Outside of that, I wouldn't mind seeing a few functions like these:

function parent_theme_path( $file ) {}

function parent_theme_uri( $file ) {}

function child_theme_path( $file ) {}

function child_theme_uri( $file ) {}

I think this is outside the scope (but somewhat related) to this ticket. Although, it's something we can already do by just tacking the file name onto the end of the appropriate get_template_*() and get_stylesheet_*() functions. I'd say open a separate ticket for those things.

#68 @georgestephanis
12 years ago

For the theme_path ones, you could just use locate_template with $load left as FALSE.

But that's kinda what spawned this in the first place, and now we digress.

#69 in reply to: ↑ 66 @chipbennett
12 years ago

Replying to georgestephanis:

Yeah, we'd suggested that earlier, but occasionally the parent theme will want to include a file that they don't want the child theme to override.

That's what get_template_directory_uri() is for. There is no need to over-complicate this function, just to duplicate something that Theme developers can already do with existing functions.

@georgestephanis
12 years ago

WTF, I missed a parentheses? DAGNABBITT!

#70 @azizur
12 years ago

  • Cc azizur added

#71 @alex-ye
12 years ago

  • Cc nashwan.doaqan@… added

#72 @TJNowell
11 years ago

  • Cc contact@… added

#73 @meloniq
11 years ago

  • Cc meloniq@… added

#74 @nacin
11 years ago

#19200 was marked as a duplicate.

#75 @nacin
11 years ago

  • Component changed from Template to Themes
  • Focuses template added

#76 @rmccue
11 years ago

Hello fellow developers. I am +1 on this ticket.

Can we please add this (at least for parity with plugins_url), and include filters as in #13239? I'm working on theme hierarchy support (that is, grandparent themes, etc) and this would be insanely useful.

#77 @wonderboymusic
11 years ago

I can't hear you over your lack of unit tests

#78 in reply to: ↑ 66 @johnjamesjacoby
10 years ago

Replying to georgestephanis:

Yeah, we'd suggested that earlier, but occasionally the parent theme will want to include a file that they don't want the child theme to override.

Themes are for styling output to the browser, they are not for dictating what other libraries can or cannot do inside the application. Allowing themes to black-list which template parts and assets child themes can never override is a slippery slope.

Themes would go from 'not officially supporting BuddyPress' to 'officially not supporting BuddyPress' which seems like behavior we wouldn't want to enable.

#79 follow-up: @greenshady
10 years ago

I'm not sure what the hangup is with this ticket. The purpose of the ticket is to propose a function for loading resources (images, styles, scripts, etc.) from either the stylesheet directory (child theme) or the template directory (parent theme). It really shouldn't do anything else.

This function should search for a file (or an array of files) in the child theme, then the parent theme and return the found URI. I proposed a solution that I've been using for 2 years in my themes without issues: https://core.trac.wordpress.org/ticket/18302#comment:65

Basically, we want a function similar to locate_template() that works with file URIs.

If a theme author doesn't want to allow child theme overriding for a particular resource (lots of good reasons not to), don't use the function. Simply go about using get_template_directory_uri() like always.

This ticket was mentioned in Slack in #core by georgestephanis. View the logs.


10 years ago

This ticket was mentioned in Slack in #core by georgestephanis. View the logs.


10 years ago

This ticket was mentioned in Slack in #core by georgestephanis. View the logs.


10 years ago

#83 @strider72
9 years ago

+! on this patch from me. Please can we get this into Core soon? It's been languishing for years, which seems odd for a reasonably straightforward change. What's the holdup? What can I do?

#84 in reply to: ↑ 31 @GaryJ
9 years ago

Replying to scribu:

Parent theme developers would then be inclined to split their JS code into more files, which hurts performance.

With the eventual prevalence of HTTP/2, this wouldn't apply.

#85 in reply to: ↑ 79 @ericlewis
9 years ago

Replying to greenshady:

I'm not sure what the hangup is with this ticket.

This has been given the thumbs up and marked for a Future Release. Although the ticket has a patch, it needs unit tests to be considered for commit.

#86 @johnbillion
8 years ago

  • Keywords early added; westi-likes removed
  • Owner changed from westi to johnbillion
  • Priority changed from normal to high

#87 @johnbillion
8 years ago

  • Summary changed from Improve child theme file inheritance by introducing `theme_url()` to locate a file URI to Improve child theme file inheritance by introducing a function to locate a file URI

@gma992
8 years ago

link-template.php needed refresh, nothing new added

@gma992
8 years ago

Starting Unit Testing

#88 @gma992
8 years ago

I'd love some advice to keep building the tests regarding this ticket, for example when the style-sheet or file is in a sub-directory the test fails as the path given is just after the theme folder, for example:

echo theme_file_uri('/foo.js');

> 'http://localhost/wp-content/themes/twentyfifteen/foo.js'

If 'foo.js' is inside a folder like '/js', the path will be wrong. Not sure if I fail to understand how the new function works or I'm on the right direction.

Last edited 8 years ago by gma992 (previous) (diff)

#89 @johnbillion
8 years ago

  • Milestone changed from Future Release to 4.7

#90 follow-up: @JakePT
8 years ago

@gma992 I would assume the correct usage in that case would be:

echo theme_file_uri('/js/foo.js');

#91 @JakePT
8 years ago

Would having theme_file_uri() and get_theme_file_uri() as functions be a good idea? Seems common with other functions, and get_ seems to be the standard when a function returns a value.

I'm imagining something like:

<?php
get_theme_file_uri();
theme_file_uri();

(I'm not sure you'd ever need to echo the file path?)

Version 1, edited 8 years ago by JakePT (previous) (next) (diff)

#92 in reply to: ↑ 90 ; follow-up: @gma992
8 years ago

Replying to JakePT:

@gma992 I would assume the correct usage in that case would be:

echo theme_file_uri('/js/foo.js');

Yes indeed, If '/js/foo.js' is passed as a parameter it pass the test, but the intention is to grab only the name of the file, isn't it? not just for consistency with similar functions but also because themes or plugins can have pretty different folder organization, just guessing here.

#93 in reply to: ↑ 92 @JakePT
8 years ago

Replying to gma992:

Replying to JakePT:

@gma992 I would assume the correct usage in that case would be:

echo theme_file_uri('/js/foo.js');

Yes indeed, If '/js/foo.js' is passed as a parameter it pass the test, but the intention is to grab only the name of the file, isn't it? not just for consistency with similar functions but also because themes or plugins can have pretty different folder organization, just guessing here.

No I don't believe it's supposed to work that way. Neither get_template_part() or locate_template() work that way. Besides, the idea is to use in the theme, so the theme author would know their own folder structure. And a child theme author would be organising the theme the same way, as they would when replacing templates or template parts.

#94 @johnbillion
8 years ago

  • Keywords commit has-unit-tests added; needs-unit-tests early removed
  • Status changed from reviewing to accepted

18302.diff (yay for messed up attachment numbering) is my latest incarnation of this. I would very much like to commit this to core this week in order to gauge feedback. Summary:

  • get_theme_file_uri() function to return the URL to a file in either the child or parent theme as relevant.
  • get_parent_theme_file_uri() function to return the URL to a file in the parent theme.
  • get_theme_file() function to return the path to a file in either the child or parent theme as relevant.
  • get_parent_theme_file() function to return the path to a file in the parent theme.
  • The $file parameter is optional in all four functions.
  • Unit tests for all the things.

Some notes:

  • get_ has been added as a prefix to the function names as per feedback.
  • wp_ could also be added as a further prefix, but this makes the function names very long. I'm -1 on this.

One remaining question:

  • Should the get_theme_file() and get_parent_theme_file() functions be named get_theme_file_path() and get_parent_theme_file_path()?
Last edited 8 years ago by johnbillion (previous) (diff)

@johnbillion
8 years ago

#95 follow-up: @johnjamesjacoby
8 years ago

One remaining question:

-1 for adding wp_
+1 for adding _path

At the risk of derailing this, these function names would be the first times in code that parent is officially acknowledged, over the existing template & stylesheet usages. Existing experiences with blog/site/network confusion leave me dubious, but I'm mostly ambivalent, and know that people will figure it out regardless.

#96 in reply to: ↑ 95 @johnbillion
8 years ago

Replying to johnjamesjacoby:

At the risk of derailing this, these function names would be the first times in code that parent is officially acknowledged, over the existing template & stylesheet usages.

This also crossed my mind a while ago, but I decided I preferred get_parent_theme_file_uri() over the rather confusing sounding get_template_theme_file_uri(). Also, yeah, at some point we just need to commit this, lest another five years pass :-)

#97 @johnbillion
8 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 38578:

Themes: Improve child theme file inheritance by introducing functions for locating and fetching the URL or path to files within child and parent themes.

The most useful function this introduces is get_theme_file_uri(), which returns the URL to the specified file in the child theme if it exists, and falls back to the URL to the specified file in the parent theme. This allows parent themes to reference files (including enqueuing CSS and JavaScript files) that can be overridden by the child theme simply by existing.

This change also introduces get_theme_file_path(), which is the file path equivalent of get_theme_file_uri().

Finally, get_parent_theme_file_uri() and get_parent_theme_file_path() are also introduced, which allow a theme to specifically reference a file URL or file path in the parent theme. These can be used as replacements for get_template_directory_uri() and get_template_directory() respectively, for consistency.

Props johnbillion, georgestephanis, gma992.
Fixes #18302

#98 @johnbillion
8 years ago

In 38579:

Taxonomy: Revert accidental changes introduced in [38578].

See #18302

This ticket was mentioned in Slack in #core by georgestephanis. View the logs.


8 years ago

#100 @ChiefAlchemist
8 years ago

fwiw (read: I'm seeing this too late), this wasn't really a function issue. It was a structure and theme'ing mindset issue. It's possible using get_template_part() along with being mindful of structure and the fact that someone else might use the parent to build a child. On the other hand, if anyone can do anything anyway they way...well, that's going to be a painful way to approach something that by definition is structured. I know. I know. #Duh :)

#101 @SergeyBiryukov
8 years ago

In 38605:

Docs: Use a third-person singular verb for theme_file_uri, parent_theme_file_uri, theme_file_path, and parent_theme_file_path filters added in [38578].

See #18302.

#102 @SergeyBiryukov
8 years ago

In 38606:

Docs: Use a third-person singular verb in the DocBlock summary for get_theme_file_uri(), get_parent_theme_file_uri(), get_theme_file_path(), and get_parent_theme_file_path(), introduced in [38578].

See #18302.

This ticket was mentioned in Slack in #forums by sergey. View the logs.


7 years ago

This ticket was mentioned in Slack in #themereview by greenshady. View the logs.


7 years ago

Note: See TracTickets for help on using tickets.