WordPress.org

Make WordPress Core

Opened 2 years ago

Closed 8 months ago

Last modified 8 months ago

#19063 closed enhancement (wontfix)

Custom post_types and get_template_part

Reported by: impleri Owned by:
Milestone: Priority: normal
Severity: minor Version:
Component: Template Keywords: has-patch
Focuses: Cc:

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)

new.diff (896 bytes) - added by impleri 2 years ago.
first attempt
new.2.diff (973 bytes) - added by impleri 2 years ago.
second try
get_post_type.diff (959 bytes) - added by impleri 2 years ago.
Using get_post_type instead
single-ml_product.php (2.5 KB) - added by impleri 2 years ago.
Example of current template hacking
custom_hook.php (539 bytes) - added by impleri 2 years ago.
Hook file
single-ml_product.2.php (1.8 KB) - added by impleri 2 years ago.
Modified for get_custom_template_part

Download all attachments as: .zip

Change History (24)

impleri2 years ago

first attempt

comment:1 impleri2 years ago

  • Cc christopher@… added

comment:2 scribu2 years ago

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?

Last edited 2 years ago by scribu (previous) (diff)

comment:3 impleri2 years ago

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 magical_mystery_type.php, 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).

Last edited 2 years ago by impleri (previous) (diff)

comment:4 scribu2 years ago

I couldn't apply your patch.

Please make patches relative to the root WP dir. More importantly, please make them against the current trunk.

impleri2 years ago

second try

comment:5 scribu2 years ago

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.

comment:6 scribu2 years ago

Finally, please provide some examples as to which template you think should load for which URL.

comment:7 impleri2 years ago

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.

impleri2 years ago

Using get_post_type instead

impleri2 years ago

Example of current template hacking

comment:8 follow-up: scribu2 years ago

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.

comment:9 scribu2 years ago

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 impleri2 years 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 scribu2 years ago

So, how could a plugin use the 'get_custom_template_part' filter generically, without knowing anything about the theme? Code please.

comment:12 impleri2 years ago

Easy enough since I already had it planned. Here's the hook for a plugin.

Version 0, edited 2 years ago by impleri (next)

impleri2 years ago

Hook file

impleri2 years ago

Modified for get_custom_template_part

comment:13 scribu2 years ago

  • Keywords 2nd-opinion added

Ok, thanks for the example.

comment:14 impleri2 years ago

Any news (or reviewers)?

comment:15 follow-up: c3mdigital8 months ago

  • Keywords 2nd-opinion removed
  • Resolution set to wontfix
  • Status changed from new to closed

get_template_part() Is meant to be a simple tempting function that gets a template part. This complicates our template hierarchy. Couldn't you do basically the same thing in your archive.php file? Put your function that returns the $slug-$type part then in your archive.php

$template = your_slug_type_function();
get_template_part( $template. '-loop'  );

comment:16 SergeyBiryukov8 months ago

  • Milestone Awaiting Review deleted

comment:17 in reply to: ↑ 15 impleri8 months ago

Replying to c3mdigital:

get_template_part() Is meant to be a simple tempting function that gets a template part. This complicates our template hierarchy. Couldn't you do basically the same thing in your archive.php file? Put your function that returns the $slug-$type part then in your archive.php

That's fine for theming stuff, but I'm coming at it from the perspective of a plugin author. I have a plugin which uses CPT to display books. For someone to be able to use my plugin, they cannot simple install it. They have to either edit their template files (as you suggest) or create their own template files. So, are you suggesting that I, as a plugin author, create a theme template and require users to use it or roll their own just so that my CPT is actually viewable?

This kind of leaving third party developers out to dry is a reason why I've slowly left using WP. Both Joomla and Drupal have this kind of functionality out of the box. Sad, because I'd rather use WP than the others or forking WP for such a small change. All I'm asking is for post types to be included in the get_post_template() magic and an additional WP hook to allow plugins to define initial template parts for those CPT.

Note: See TracTickets for help on using tickets.