Opened 19 months ago
Last modified 18 months ago
#19063 new enhancement
Custom post_types and get_template_part
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Template | Version: | |
| Severity: | minor | Keywords: | has-patch 2nd-opinion |
| Cc: | christopher@… |
Description
Can we modify the get_template_part process to allow custom post_type and custom taxonomy from plugins? I'm pretty sure I'm not the only person who uses custom post_types and would like to see an easier way to add a default template file without encroaching upon existing theme files, adding child themes, or requiring themes which are explicitly compatible with the particular post_type.
I've included a patch which is based on my current approach in using the archive_template, single_template, etc filter.
Attachments (6)
Change History (20)
How can you be sure that $slug in "$slug-$type.php" isn't 'page' or 'archive' or some other string that will load a wholly unexpected template file?
Is that really necessary? If a template author creates a template file of archive-magical_mystery_type.php and loads get_template_part('archive') on a post with my_own_custom_type, why should this assume the template file in question doesn't handle magical_mystery_type less than archive.php does? One would think that if a template author goes out of her way to create an archive page for a custom post_type, that file will work for that custom post_type better than the plugin author's default.
Further, all of this still employs WordPress's own process and template logic (e.g. locate_template) with the single addition of allowing plugin authors a last-stop attempt at outputting their templates without using get_content, template_redirect, or template_include -- each which again make it difficult to adjust for different themes (in their own peculiar way).
I couldn't apply your patch.
Please make patches relative to the root WP dir. More importantly, please make them against the current trunk.
I was able to apply new.2.diff and noticed that it doesn't account for when:
- get_query_var('post_type') returns false (default)
- get_query_var('post_type') returns an array of post types
Also, I don't think get_template_part() is the right place for adding this. It should remain a generic function, similar to locate_template().
PS: Please leave a comment when you upload a new patch, as they don't trigger a notification.
Finally, please provide some examples as to which template you think should load for which URL.
If post_type is false, the if(!in_array($post_type, $default_types)) will return false, thereby ignoring the additional template possibilities (after all, the interest is for custom post_types -- which will have post_type set).
For the array, this should be changed to retrieve the post_type for the actual post (easy enough) which cannot be an array (at least according to the DB design). Would using get_post_type() fix this? (posting new patch with this)
I disagree on using something like locate_template() for a few reasons. First, it comes too late in the template loading process. Adjusting get_template_part() as I propose is essentially the same as adjusting locate_template() except in one crucial point, which is my second reason: it would add additional filtering and process time because locate_template() is called for every template piece. Using something like get_template_part() follows what I think are the goals in the template system: modularity. Using locate_template(), while it does this as well, it adds process time without benefit. Thirdly, get_template_part() appears to be the logical choice because that is where possible template names are decided. Pushing this to locate_template() would be obfuscating its function. The options as I see them are to use get_template_part() or to create a new function similar to get_header() (e.g. get_main_content() or something) though even then get_template_part() would need to be modified to allow for a base plugin-defined template (either by postponing load_template() until after a filter check -- like I have done -- or returning a template path to a get_main_content() function which then does load_template() after a filter check).
Since this is meant to enable custom post_types to display properly, a URL like http://mysite.com/records/my-own-musical-beast/ which is used by a music record/album custom post_type might not display anything because the content is a listing of songs generated from the DB. Currently, I would need to filter the_content in order to display this, filter on template_include or single_template to redirect to a template which will show the correct data. In the first case, I am hardcoding the template from my plugin (not good). In the latter two cases, I am overriding the actual template (e.g. what if a template puts the sidebar on the left but does not do so in the template's header.php like TwentyEleven does in footer.php?). By using get_template_part() or something similar, it is easier for my record file to show in a randomly-given theme without forcing a particular template layout. For example, I'm updating the extinct Now Reading plugins to use custom post_types. A book (e.g. http://beta.impleri.net/library/product/the-girl-with-the-dragon-tattoo/ ) needs to be able to have multiple authors, an image, a link to Amazon page, etc. These do not show up on the template pages because, obviously, they are custom data which need to be displayed. What I'm doing right now is using the single_template filter, checking if the custom single-ml_product.php file was found by locate_template() and, if not, redirecting to the single-ml_product.php template file in my plugin directory. This is not a good solution because I've had to copy the entire page layout from TwentyEleven (I'll attach this file as well) which may not work with other templates. I could have filtered the_content but then I am requiring a hardcoded style across which makes it more difficult to users to have template-specific designs. If I could have filtered through get_template_part(), users would only have to worry about minor tweaks for a template which they could put in their template folder without needing to recreate a loop page -- much like TwentyEleven has made it possible with its content-single.php file. Thus far, that seems to be simplest solution which is most extensible and most logical from what I can tell.
Please try not to post big walls of text; it's hard to follow.
I was hoping for a few short examples, in the form of: "When loading URL X, with line of code Y, I can load template Z."
I disagree on using something like locate_template() for a few reasons.
I wasn't suggesting going lower down the stack, but higher i.e. to get_archive_template() etc. as you later suggest.
This is not a good solution because I've had to copy the entire page layout from TwentyEleven
I attempt to tackle that with Theme Wrappers, but it's something that theme authors must adopt.
comment:10
in reply to:
↑ 8
impleri — 19 months ago
Please try not to post big walls of text; it's hard to follow.
Apologies. I write/talk a lot (12+ years of uni does that!)
I was hoping for a few short examples, in the form of: "When loading URL X, with line of code Y, I can load template Z."
Which is why I provided a URL to an actual example I am working with. The URL is for a custom post_type (ml_product) which has its own custom metadata (book information). Since it is a CPT, most of its code is standard WP handling. However, the template needs to display the book metadata (authors, cover image, publication date, whatever). I currently hack the entire template through the archive_template filter.
I wasn't suggesting going lower down the stack, but higher i.e. to get_archive_template() etc. as you later suggest.
Wouldn't going higher make it harder for template authors to provide their own template? Also, using get_*_template() is already possible (through the *_template filter called in get_query_template()). It still requires plugins to output the entire template instead of the small portion which they are adapting (i.e. #div > #content). get_template_part() can handle that exact section.
I attempt to tackle that with Theme Wrappers, but it's something that theme authors must adopt.
I agree that everything should be reduced to a single wrapper, but I don't see how Theme Wrappers does it any differently from get_template_part(). In fact, what differences are there in archive.php and single.php which cannot be resolved by using get_template_part() or abstracting them into loop-archive.php and loop-single.php to complement the content-archive.php and content-single.php files?
comment:11
scribu — 19 months ago
So, how could a plugin use the 'get_custom_template_part' filter generically, without knowing anything about the theme? Code please.
comment:12
impleri — 19 months ago
Easy enough since I already had it planned. Here's the hook for a plugin. It has less dependence on a specific theme, though it's not completely independent. It's perhaps impossible to do this for every theme, but it at least makes it more compatible (and less wasted recycling of layout) with themes.
comment:14
impleri — 18 months ago
Any news (or reviewers)?

first attempt