#18302 closed enhancement (fixed)
Improve child theme file inheritance by introducing a function to locate a file URI
Reported by: | johnbillion | Owned by: | 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)
Change History (125)
#1
@
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
@
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
@
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
@
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?
#7
@
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:
↓ 11
@
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.
#10
@
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
@
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:
↓ 13
@
13 years ago
- Milestone changed from 3.3 to Future Release
Punting enhancements from 3.3
#13
in reply to:
↑ 12
@
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
@
13 years ago
Even with support from a lead dev, if it's not commited on time, it doesn't get in:
#18
@
13 years ago
- Milestone changed from 3.4 to Future Release
Worth pursuing, but punting from 3.4 per bug scrub.
@
12 years ago
Moving function from themes to link-template along with related plugins_url() content_url() and such
#20
@
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
@
12 years ago
- Milestone changed from Future Release to 3.5
I like the name 'theme_url()' better too.
#22
@
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
@
12 years ago
Added in ltrim( $file, '/' );
to account for theme authors using it as theme_url( '/images/logo.gif' );
#23
@
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
@
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.
#25
@
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
@
12 years ago
A note on @since: in other functions we use @since 3.5.0 (vs. 3.5).
Related: #19638
#27
follow-up:
↓ 29
@
12 years ago
Latest patch fixes Sergey's point about 3.5.0, and modifies existing themes to provide examples and use cases.
#30
@
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:
↓ 84
@
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:
↓ 33
@
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
@
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
@
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
@
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
@
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
@
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:
↓ 39
@
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
@
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
@
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:
↓ 43
@
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:
↓ 44
@
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
@
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
@
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.
#45
@
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:
↓ 48
@
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
@
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
@
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
@
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
@
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.
#56
follow-up:
↓ 64
@
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
@
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)
#59
@
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
@
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.
#63
@
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
@
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
@
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:
↓ 69
↓ 78
@
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
@
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
@
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
@
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.
#76
@
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.
#78
in reply to:
↑ 66
@
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:
↓ 85
@
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
@
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
@
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
@
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
@
8 years ago
- Keywords early added; westi-likes removed
- Owner changed from westi to johnbillion
- Priority changed from normal to high
#87
@
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
#88
@
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 function fails, not sure if I fail to understand how the new function works or I'm on the right direction.
#90
follow-up:
↓ 92
@
8 years ago
@gma992 I would assume the correct usage in that case would be:
echo theme_file_uri('/js/foo.js');
#91
@
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();
#92
in reply to:
↑ 90
;
follow-up:
↓ 93
@
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
@
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
@
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()
andget_parent_theme_file()
functions be namedget_theme_file_path()
andget_parent_theme_file_path()
?
#95
follow-up:
↓ 96
@
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
@
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 :-)
This ticket was mentioned in Slack in #core by georgestephanis. View the logs.
8 years ago
#100
@
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 :)
Example usage in TwentyEleven