Opened 7 months ago
Last modified 8 days ago
#22355 new enhancement
Template stack - Beyond parent/child theme relationships
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Themes | Version: | |
| Severity: | normal | Keywords: | has-patch |
| Cc: | obenland, justinsainton@…, curtis@…, pippin@…, mike@…, contact@…, mercijavier@…, ryan@…, mzaweb, alexvornoffice@…, xoodrew@…, maorhaz@…, jondavis, sabreuse, kovshenin, tarasm@…, meloniq@…, chacha102, pauldewouters@…, dailyrants@…, ian.dunn@…, nashwan.doaqan@…, chip@…, wordpress@… |
Description (last modified by johnjamesjacoby)
Problem
Robust plugins (BuddyPress, bbPress, et all) are unable to break out of the parent/child restrictions that WordPress imposes on template output. For these plugins to include their own template parts, elaborate code must be written to hook into several different execution points, requiring an intimate knowledge of the inner workings of WordPress's template loading system.
Solution
Create a stack of template locations, and allow WordPress to transverse this array following the same STYLESHEETPATH/TEMPLATEPATH order it always has, while also enabling additional paths to be added with a priority (similar to the filters API.)
Details
The attached patch includes two new functions in wp-includes/template.php:
- register_template_stack()
- get_template_stack()
Register template stack is a wrapper for the 'template_stack' filter. get_template_stack() is a variation of apply_filters() that returns the array of filtered template locations.
A modification to wp-settings.php calls register_template_stack() two times, passing get_stylesheet_directory() and get_template_directory() as callbacks, to initialize the core parent/child relationship, ensuring complete backwards compatibility.
Result
This allows for plugins to register additional paths in the template loader hierarchy, and enables plugins that may come with their own default template parts the option of registering a fallback template location.
This works with both locate_template() and get_template_part(), and has the added benefit removing duplicate items inside of get_template_stack(), resulting in avoiding an additional file system check should the parent and child themes be the same.
Attachments (3)
Change History (41)
johnjamesjacoby — 7 months ago
comment:2
JustinSainton — 7 months ago
- Cc justinsainton@… added
comment:3
SergeyBiryukov — 7 months ago
comment:4
curtismchale — 7 months ago
- Cc curtis@… added
comment:6
MikeSchinkel — 7 months ago
- Cc mike@… added
comment:7
johnjamesjacoby — 7 months ago
- Description modified (diff)
comment:8
stephenh1988 — 7 months ago
- Cc contact@… added
comment:10
follow-up:
↓ 11
scribu — 7 months ago
A usage example from start to finish would be helpful.
comment:11
in reply to:
↑ 10
johnjamesjacoby — 7 months ago
Replying to scribu:
A usage example from start to finish would be helpful.
Imagine a plugin registers a custom post type 'foo' and wants to bundle templates for twentytwelve support. This plugin would:
- Call: register_theme_stack( 'my_plugin_twentytwelve_template_path', 10 );
- Now, /plugins/my-foo/twentytwelve/single-foo.php is in the stack.
- locate_template() finds a match in the plugin directory.
- Profit.
comment:12
follow-up:
↓ 16
scribu — 7 months ago
And you could control the order (parent theme, child theme, plugin) via the priority arg. Got it.
Instead of:
register_template_stack( 'get_stylesheet_directory', 10 );
why couldn't you do:
register_template_stack( get_stylesheet_directory(), 10 );
since the callback just returns a path, which needs to be computed only once.
comment:13
wpmuguru — 7 months ago
+1 - I've used templates located im plugins several times for a variety of reasons.
comment:14
mordauk — 7 months ago
+1 as well. I've built templating systems into plugins as well and this would dramatically cut down the work load.
comment:15
ryanduff — 7 months ago
- Cc ryan@… added
comment:16
in reply to:
↑ 12
johnjamesjacoby — 7 months ago
Replying to scribu:
why couldn't you do (...) since the callback just returns a path, which needs to be computed only once.
I went the callback route because it came with the filters API; either approach would work.
comment:17
MikeSchinkel — 7 months ago
Related #21062?
comment:18
mzaweb — 7 months ago
- Cc mzaweb added
comment:19
alexvorn2 — 7 months ago
- Cc alexvornoffice@… added
comment:20
DrewAPicture — 7 months ago
- Cc xoodrew@… added
Pretty neat, and we drop STYLESHEETPATH and TEMPLATEPATH in the process. +1
comment:21
follow-ups:
↓ 23
↓ 30
johnbillion — 7 months ago
I like this idea.
Is there really a need for the register_template_stack() wrapper function? I'd prefer to stick with add_filter(), which is self explanatory.
comment:22
maor — 7 months ago
- Cc maorhaz@… added
comment:23
in reply to:
↑ 21
johnjamesjacoby — 7 months ago
Replying to johnbillion:
I like this idea.
Is there really a need for the register_template_stack() wrapper function? I'd prefer to stick with add_filter(), which is self explanatory.
add_filter() alone would work. The reason to use a dedicated function is to make it API agnostic. Should we want to move it off of the filters API later, we can do so without changing the name of the function or it's parameters.
comment:24
jondavis — 7 months ago
- Cc jondavis added
comment:25
sabreuse — 7 months ago
- Cc sabreuse added
comment:26
DrewAPicture — 4 months ago
#23180 was marked as a duplicate.
comment:27
kovshenin — 4 months ago
- Cc kovshenin added
comment:28
tarasm — 4 months ago
- Cc tarasm@… added
comment:29
meloniq — 4 months ago
- Cc meloniq@… added
comment:30
in reply to:
↑ 21
chacha102 — 3 months ago
Replying to johnbillion:
Is there really a need for the register_template_stack() wrapper function? I'd prefer to stick with add_filter(), which is self explanatory.
But it isn't a filter. The values of previous function aren't passed to the next function. If I understand correctly, I don't think anything is passed to the function at all.
Right now the filter API is simply a storage mechanism, which doesn't seem right.
comment:31
chacha102 — 3 months ago
- Cc chacha102 added
comment:32
pauldewouters — 3 months ago
- Cc pauldewouters@… added
Patch according to @scribu and @chacha102 suggestions: uses separate global instead of filters api, pass path instead of callback, added 'remove' and 'has' functions
comment:33
meloniq — 2 months ago
Above patch uses way of registering locations suggested by @scribu : add_template_stack( get_template_directory(), 12 ); , stop to use filters api as suggested @chacha102 - uses $wp_template_stack global, and adds functions to remove and check for existence of template location.
comment:34
mindctrl — 7 weeks ago
- Cc dailyrants@… added
comment:35
iandunn — 3 weeks ago
- Cc ian.dunn@… added
comment:36
alex-ye — 3 weeks ago
- Cc nashwan.doaqan@… added
comment:37
chipbennett — 2 weeks ago
- Cc chip@… added
comment:38
emzo — 8 days ago
- Cc wordpress@… added

Related: #20509