Make WordPress Core

Opened 13 years ago

Closed 10 years ago

Last modified 7 years ago

#18561 closed enhancement (wontfix)

Better Way to Insert Things Below Individual Posts

Reported by: jane's profile jane Owned by:
Milestone: Priority: normal
Severity: minor Version: 3.2.1
Component: General Keywords:
Focuses: Cc:

Description

More and more plugins want to drop stuff in below each post (especially common among plugins focused on encouraging the sharing of content). There's not really a great way to do it, though, if your single-post-area doesn't end with the last line of body text. Many themes put the byline/date/metadata below -- rather than above, which used to be the norm -- the post content, including our own Twenty Eleven. See the screenshot to see how ugly it is when a plugin (or two, or more) uses the the_content filter to insert something at the "end" of each post.

Inserting the sharing and like rows (in this example) at the bottom of the post text before the byline/classification metadata seems wrong. It should go below that, so it is closely related to commenting, not part of the content itself. The plugin-generated widget is not "by" the post author, after all.

I have been told that options for addressing this are basically either modifying the theme and/or getting a new filter in place. Whatever we need to do, let's do it, because misplacing plugin-provided tools inside the content rather than after it is a) really bad IA, and b) crazy ugly.

Attachments (9)

Screen shot 2011-08-31 at 9.56.48 PM.png (44.9 KB) - added by jane 13 years ago.
Twenty Eleven with 2 sharing plugins using the_content
comment-template.diff (759 bytes) - added by trepmal 13 years ago.
pre/post_comments_template action hook idea
the_rest.diff (538 bytes) - added by helenyhou 13 years ago.
What I was thinking, except with the cleverness of johnjamesjacoby
post-template.php.diff (516 bytes) - added by nathanrice 13 years ago.
Hooks before and after content.
18561.get_template_part.patch (757 bytes) - added by Otto42 13 years ago.
get_template_part_{$slug}_after
18561.get_template_part_slug.patch (1.4 KB) - added by SergeyBiryukov 13 years ago.
query.php.the_post_before.the_post_after.hooks.diff (292 bytes) - added by chipbennett 13 years ago.
Add the_post_before and the_post_after hooks to fire inside of the_post()
18561.diff (588 bytes) - added by aaroncampbell 13 years ago.
Adds the_rest()
18561.twentyeleven.diff (1.3 KB) - added by aaroncampbell 13 years ago.
Adds support for the_rest() to Twenty eleven

Download all attachments as: .zip

Change History (140)

@jane
13 years ago

Twenty Eleven with 2 sharing plugins using the_content

#1 @bi0xid
13 years ago

This seems a good idea.

One new filter called before_the_content (and after the title) and another called after_the_content will be very useful for social plugins.

#2 @technosailor
13 years ago

It still would be theme dependent. It could be done for twentyeleven but it's up to theme people to integrate this methodology.

#3 @mikeschinkel
13 years ago

At first blush I would save to have add_theme_support() and hooks for both before_post_content' and 'after_post_content'` then plugins could choose to use the new hooks if the theme supports it.

#4 @rmccue
13 years ago

In the software I develop, I use an action here linked to an internal function. The internal function has an array of "services" which have registered to be output here. The internal function then takes care of adding before/after things depending on the theme's settings (perhaps via add_theme_support() in this case?).

It also allows grouping various items together (ala the rows here) based on the "type" that the service sets.

#5 @Otto42
13 years ago

I would suggest adding this to the end of the get_template_part function instead.

do_action( "get_template_part_{$slug}_after", $slug, $name );

(what the name of the hook actually is is dealer's choice)

This would allow a plugin to hook into a common place, if the theme is using get_template_part included files. For the specific case of twenty-eleven, it's using get_template_part('content', 'single') to include the content at that point, and an after action hook would allow you to put in something after the *whole* content part, which includes everything in the content.php file.

There's already an action hook at the top of the function that can be used for the "before" part.

This wouldn't work on all themes, but it would provide a mechanism for hooking before and after any use of get_template_part, and a naming scheme could quickly emerge among themes for part-naming, allowing for an ad-hoc standard.

Furthermore, the plugin could only hook on specific "names" if it chose to, behaving differently for single post pages vs. post formats on the home page, etc.

Advantage: Themes that use get_template_part wouldn't need any changes. Themes not using it could start, which I believe should be encouraged anyway.

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

#6 @helenyhou
13 years ago

Maybe I am wandering down a really wrong path in my head (promises of brownies will do that), but what if a filter was named something not really having to do with the content? Maybe something like post_extras or more clever. Then a theme could more readily anticipate and incorporate all this kind of social media, etc. people want to add. A theme could even have an option about where to put the extras, because who knows - maybe it would really be in the sidebar, or something not really related to the_content at all.

#7 @trepmal
13 years ago

Could add some hooks to the comments_template() function to make it easy to add content before/after the entire comments area. I don't currently see any easy way to hook in before or after that area that isn't theme dependent.

Just my humble 2¢

Last edited 13 years ago by trepmal (previous) (diff)

#8 @johnjamesjacoby
13 years ago

The problem isn't hooking into 'the_content' it's executing code after everything else.

What we need is something like :

function the_rest() {
    global $post;

    // Always fires before the rest of a posts extra content
    do_action( 'before_the_rest' );

    // Execute the rest of a posts content
    do_action( 'the_rest', $post );

    // Always fires after the rest of a posts extra content
    do_action( 'after_the_rest' );
}

With something like this, themes use the_rest(); like they use the_content(); but are able to hook whatever they want into it. This lets theme authors decide where the rest of a posts additional content should go. I'm passing the $post global here for convenience, so plugin and theme authors don't even need to declare it themselves; it gets passed as a parameter and can be used to make decisions about what to display there in what context.

Even though actions do have priorities, I've added 'before' and 'after' actions here too. This is so plugins and themes can play politely with each other regardless of their action priority. They obviously aren't *needed* but I included them as a reminder that themes with more actions allow for more flexibility like this when it's needed.

#9 @johnjamesjacoby
13 years ago

Otto's idea is good too. WordPress has it's basic template hierarchy, so it's only natural there be a template part hierarchy as well.

#10 @helenyhou
13 years ago

Man, the_rest is way more clever. And now I feel better that I wasn't really wandering down a wrong path.

#11 @jb510
13 years ago

Funny my thought was "isn't that already there", but then I realized I just spend way too much time with Genesis. http://genesistutorials.com/visual-hook-guide for reference, hooks before and after the_content and it works quite well. Having it in core though would make a lot more sense so plugin devs could rely on it being there.

@trepmal
13 years ago

pre/post_comments_template action hook idea

#12 @trepmal
13 years ago

Just expanding on my previously mentioned idea

With suggested hooks, easy to add content above - or below - the comments area (which is generally below the post content...)

$post is passed to make it possible to customize the added content as needed.

Very easy to use (screenshot: http://cl.ly/9mUI):

add_action( 'pre_comments_template', 'before_comments_template' );
function before_comments_template( $post ) {
	?>
	<div style="text-align:center;"><p style="border-top: 1px solid #333;border-bottom: 1px solid #333;">before the comments!</p></div>
	<?php
}

add_action( 'post_comments_template', 'after_comments_template' );
function after_comments_template( $post ) {
	if ( 'closed' == $post->comment_status ) return;
	?>
	<div style="text-align:center;clear:both;"><p>after the comments, if comments are open!</p></div>
	<?php
}
Last edited 13 years ago by trepmal (previous) (diff)

@helenyhou
13 years ago

What I was thinking, except with the cleverness of johnjamesjacoby

#13 @helenyhou
13 years ago

I lightly tested using JJJ's the_rest and it seems to work. Patch is really just what he wrote out :)

#14 @M66B
13 years ago

My first thought was before/after post widgets (as in side bar widgets). In this way users can order before/after post content of multiple plugins.

#15 @GaryJ
13 years ago

+1 to Helen's / JJJ's idea about using post extras / the_rest.

The issue isn't where on the page (before, during, after element X) the plugin output gets displayed, but which hook / filter they try and attach to. Get that right, and supporting themes can display it wherever in their theme they want. No need for any add_theme_support(), since themes supporting it will be the ones calling the_rest().

We have the_title, the_content, and the_comments, so it only makes sense that there is the_rest / the_extras / the_tools / the_resources (or whatever else might be a suitable name) for each post too.

#16 follow-up: @Otto42
13 years ago

If we can modify something already there (like get_template_part) to accomplish the goal, rather than add yet-another-thing for themes to put in them, I'd kinda prefer that. You're more likely to get adoption by making something that already exists more capable instead of making a totally new thing.

#17 in reply to: ↑ 16 @GaryJ
13 years ago

Replying to Otto42:

If we can modify something already there (like get_template_part) to accomplish the goal, rather than add yet-another-thing for themes to put in them, I'd kinda prefer that. You're more likely to get adoption by making something that already exists more capable instead of making a totally new thing.

Agreed, but what percentage of themes are using the_content() (and could easily drop in the_rest()) compared to the number of themes that make use of template parts?

#18 @Otto42
13 years ago

The idea behind the_rest doesn't accomplish that goal, since using the_rest wouldn't be a drop in. You'd have to reformat your output for the other stuff not in the_content (ie, the header and footer surrounding the_content) into action hooks. It's not as easy to implement as it seems at first glance.

get_template_part is equally not easy, but a fair number of themes are already using it, and there's a lot of advantages to it beyond just this particular case. So making it capable of handling this case as well, along with giving a reason to standardize on "parts", solves more problems and has greater benefits. Plus it's a lot simpler and doesn't needlessly add one-more-thing.

The problem with adding new things is that once they're in, they're in forever and have to be supported until the end of time. Modifying existing things to be more capable is a better long run approach, when it makes sense to do so.

#19 @satollo
13 years ago

Themes are too much different to standardize them. Even if there are some commons parts on each theme, breaking up them with too much part is not so good (IMHO). I prefer an approach like the sidebar.

There are many themes that use the sidebars to define NOT sidebars but generic content area. Technically a theme can define sidebars even before and after the post or after the title and the user can add widgets there.

If widgets will be created to add social button with that kind of sidebars in mindthe problem is solved... even if the average user (in my experience) is not very skilled with widgets.

An alternative is to define "template zones". A theme can "declare" as many zone as it wants, may be some zones can be documented as de facto standard. On that zones the theme calls do_action('zone_{name}') while it declared register_zone({name/id}, 'Long descriptive name').

The declaration is used by plugins for their configuration panel so they can ask: "where do you want to inject the social button" showing a list of checkboxes or a drop down selection. Plugins will call "get_zones()" to have all defined zones.

This is far wawy more simple that writing a widget, the plugin must only attach to the action and print out the content...

#20 @iandstewart
13 years ago

I like Otto's idea of using get_template_part for this. It might be neat if there was an additional parameter that held some semantic information about the template part being included. So you could choose to hook your plugin bits into the theme after the 'post' template part. It would have to be a set universal number of semantIc names like post formats, maybe even just limited to 'post' for now.

#21 follow-up: @scribu
13 years ago

Can't this be done using the loop_start or loop_end hooks?

Or even the_post: http://scribu.net/wordpress/inserting-a-banner-between-posts.html

#22 in reply to: ↑ 21 ; follow-up: @cochran
13 years ago

Replying to scribu:

Can't this be done using the loop_start or loop_end hooks?

Or even the_post: http://scribu.net/wordpress/inserting-a-banner-between-posts.html

The loop_start and loop_end hooks will be at the end of the loop and the start of the loop. So for example on archive pages it will not be available for each post. Also, since some one referenced it already you can see those two hooks on my genesis hook guide http://genesistutorials.com/visual-hook-guide and see that loop_end will actually be after the comment section as well and The goal with this ticket will be to have it right after the_content.

Version 0, edited 13 years ago by cochran (next)

#23 follow-ups: @helenyhou
13 years ago

I actually agree that modifying something that exists would be better, but I also don't think that having this attached to the loop/the content in terms of placement is very flexible. I can easily imagine a theme author wanting to put it in the loop on an archive page but then in a sidebar or widget area on a single. Then again, maybe it's completely possible to make get_template_part have the ability to be just as flexible and I'm just not seeing it.

#24 in reply to: ↑ 23 @jane
13 years ago

Replying to helenyhou:

I can easily imagine a theme author wanting to put it in the loop on an archive page but then in a sidebar or widget area on a single.

YES.

#25 follow-up: @scribu
13 years ago

I can easily imagine a theme author wanting to put it in the loop on an archive page but then in a sidebar or widget area on a single.

What exactly are we talking about here? The ticket's title is "better way to insert things below individual posts".

#26 @scribu
13 years ago

Note that The Loop is called for single posts as well, not just on archive pages.

#27 @scribu
13 years ago

And that's what conditional flags are for: is_single(), is_page() etc. so I don't see where the lack of flexibility is.

#28 in reply to: ↑ 22 @scribu
13 years ago

Replying to cochran:

The loop_start and loop_end hooks will be at the end of the loop and the start of the loop. So for example on archive pages it will not be available for each post.

You can use 'the_post' instead.

that loop_end will actually be after the comment section as well and The goal with this ticket will be to have it right after the_content.

Yeah, that's a valid point.

#29 @ev3rywh3re
13 years ago

I know it might sound a little push-backish on theme developers, but developing a standard set of get_template_parts and do_actions that's already mentioned would definitely solve the problem.

I know most decent themes (base themes, frameworks, ack, etc.) already implement these types of filters, but there is no standard naming convention for the filters(actions). Once there is an action or filter that is documented to be used for a specific purpose, I'd target that first. if some theme isn't using it then I'll either use something that does or hack it so it works (not that any plugins or theme need any hacking :P)

<?php do_action( 'the_content_after' ) ?>

@nathanrice
13 years ago

Hooks before and after content.

#31 follow-up: @nathanrice
13 years ago

I think using get_template_part would make sense if more themes were using it. But they're not. And likely won't.

What we do know is that themes DO use the_content(). See my patch for a simple solution that will probably work in 99% of themes without asking theme developers to change anything.

#32 in reply to: ↑ 31 ; follow-up: @scribu
13 years ago

Replying to nathanrice:

That doesn't fix anything. The idea is to add stuff after the post meta, i.e. not like this:

http://core.trac.wordpress.org/attachment/ticket/18561/Screen%20shot%202011-08-31%20at%209.56.48%20PM.png

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

#33 in reply to: ↑ 32 @nathanrice
13 years ago

Replying to scribu:

That doesn't fix anything.

It doesn't specifically fix the issue brought up by Jane, but no single solution is going to do that. WordPress is due to have some strategically placed hooked that file before/after elements in the loop, without having to rely on theme developers putting in those do_action references manually, IOW work with existing template tags.

Some already exist (your example of the loop hooks), and some need to be created (before/after content, before/after comments template, before/after comment elements, etc.).

New template tags like the_rest() are probably a good idea too. It'll be a while before they catch on, but they will eventually. (especially if made part of the standards on WordPress.org Extend).

#34 in reply to: ↑ 25 @helenyhou
13 years ago

Replying to scribu:

What exactly are we talking about here? The ticket's title is "better way to insert things below individual posts".

Speaking for myself, I tend to look for intentions, not just words. Side effect of the type of people I've worked with, I guess. If the usual course of action around here is to stick to a ticket title for a solution, then get_template_part makes way more sense. Unfortunately, I don't know what usually happens, but I am trying to learn.

I really only mean flexibility in terms of pure placement. Again, if the end goal is to stick to putting things after (or maybe before) the content or somewhere in the loop, then I've totally wandered down the wrong path. At least it doesn't seem like I'm alone on it...?

#35 @SergeyBiryukov
13 years ago

I like Otto's idea of using get_template_part().

Plugins could then hook to get_template_part_content_after, assuming that more themes would use get_template_part( 'content', 'single' ).

In this case, don't we need a way for plugins to determine when to use get_template_part_content_after and when to fall back to the_content?

Edit: Some add_theme_support() option, perhaps?

Last edited 13 years ago by SergeyBiryukov (previous) (diff)

#36 @mattwiebe
13 years ago

There's no way we can kludge this into the currently existing theme infrastructure. Here's a thought for a new loop syntax that would be less radical than the Loop Standard, but easy to implement for themers:

the_loop();

Which wraps a standard WP loop in some extra goodness, including actions.

function the_loop( $slug = 'loop', $name = null ) {
	global $post;
	do_action( 'wp_before_loop' );
	while ( have_posts() ) : the_post();
		do_action( 'wp_before_loop_contents', $post );
		get_template_part( $slug, $name );
		do_action( 'wp_after_loop_contents', $post );
	endwhile;
	do_action( 'wp_after_loop' );
}

This accomplishes the goals of having multiple hook'ed places to park extra content in loop contexts, as well as taking the loop itself into a separate file, loop.php by default. As you can see, the_loop(); accepts the same args as get_template_part();, so we can use whichever loop file makes most sense in our context if we're into specificity and overrides. It does not accomplish the goal of working without retrofitting, but I think that's not possible with our current API.

What I like about this API is it's simultaneously easier for themers (no PHP looping syntax in theme files) and more powerful for plugin developers.

We then would do something like add_theme_support( 'loop' ); to signal to plugin developers that they should use the new hooks rather than the_content filter.

Note: obviously this would be an aliased method in WP_Query, just like have_posts() and the_post(), but this was easier to post here.

#37 @danielbachhuber
13 years ago

  • Cc wordpress@… added

#38 @DrewAPicture
13 years ago

  • Cc xoodrew@… added

+1 on the the_rest() idea.

I see where Otto is coming from on get_template_part but I think we'd have a hard time convincing theme developers to standardize across the board, especially as many of them still aren't even using template parts to begin with. It seems like a natural progression to continue to divide the page into separate sections e.g. the_title, the_content, the_excerpt, the_rest.

On another note, I think it should be said that template parts seem to be overwhelmingly used specifically for content-elements. the_title, the_content, the_excerpt, etc. while inherently work toward displaying content, they themselves are not indicative of producing content as are template parts. My 2¢.

Last edited 13 years ago by DrewAPicture (previous) (diff)

#39 in reply to: ↑ 23 ; follow-up: @Otto42
13 years ago

Replying to helenyhou:

I actually agree that modifying something that exists would be better, but I also don't think that having this attached to the loop/the content in terms of placement is very flexible. I can easily imagine a theme author wanting to put it in the loop on an archive page but then in a sidebar or widget area on a single. Then again, maybe it's completely possible to make get_template_part have the ability to be just as flexible and I'm just not seeing it.

Yes, you're not seeing it. get_template_part, as used in twentyeleven, does exactly what you're talking about.

add_action ( 'get_template_part_content_after', 'demo', 10, 2);
function demo($slug, $name) {
  if ($name == 'single') {
    // do output for below the post area
  }
}

Calls to get_template_part('content',...); are used throughout twenty-eleven, but with differing second parameters. If there was an after hook (like there already is one for the "before" case), then hooking in and outputting stuff below the post proper would be easy, and you could be specific about what areas in the theme that it's in.

Theme authors are already starting to use get_template_part, and will be using it more in the future. Now is a good time to start pushing for part naming standards and to support them well. Doesn't have to be a formal standard, enforced by code. Just a list of common part names would work.

As pointed out above, there is no possible generic solution that will work with all themes from all time. Themes will have to support any solution you use. Better to introduce a standard using methods theme authors already know about than to create something new that they don't understand and will use wrong. For the specific example of "the_rest" that JJJ came up with, people in this very thread are already starting to use-it-wrong from the original idea, and not one line of code has been written.

#40 @seanconklin
13 years ago

There is an existing plugin called "Plugin Organizer" that would seemingly fix this by allowing the admin to override the hook priority ordering, thus being able to choose the order the plugins are displayed. Perhaps this concept could be brought into the core, similar to how widgets allow custom ordering? http://wordpress.org/extend/plugins/plugin-organizer/

Ditto scribu on trying the loop_end action hook to get the output below the byline.

#41 follow-up: @Otto42
13 years ago

loop_end won't work because it only fires after the last post in the loop. You can't use it on a page with more than one post, for example.

There is the_post hook in setup_postdata, however this has the problem that it fires before every post's output, and that it has the next post already set up by the time it fires. So having it output something specific to the previous post is problematic.

There is no currently existing hook that will work.

As for standardizing on part names, we already have two examples of "standard" names:

Twenty Eleven uses the "content" name for calling a template to output a single post. The get_template_part call for the "content" is always called inside an existing Loop.

Twenty Ten uses the "loop" name for calling a template that runs an entire Loop from inside a normal template. So the get_template_part('loop',...); is used to run possibly more than one post.

This would make a decent starting point for a naming scheme.

#42 follow-up: @mikeschinkel
13 years ago

+1 to offer a few different new approaches that are designed to leverage the same plugin hooks; a template tag (i.e. the_rest()), sidebars as template zones, and especially a huge +1 to the_loop().

JMTCW but -1 for extending get_template_part(); I think one reason why more themes don't use it is that it can be counter-intuitive to people, or at least to me. Everytime I see it I have to rethink how it works, and I find I have to force myself to think about using it when I build a theme because it doesn't make sense to me. Otto makes a good point that once something is in WordPress it is here to stay; pity that get_template_part() is one of those.

OTOH, if the_loop() was added it might hide the more common uses of get_template_part() and those make it less onerous.

#43 in reply to: ↑ 39 ; follow-up: @helenyhou
13 years ago

Replying to Otto42:

Theme authors are already starting to use get_template_part, and will be using it more in the future.

Does this mean that plugin authors have to anticipate or provide options for what the theme is calling their template part(s), though? What if it should be attached to a completely different template part depending on context? Is that for the plugin to control then, or for the theme author? A list of common names would help, but what would happen if multiple common names were being used in a theme?

I don't mean to just fire off questions and perhaps sound belligerent or defensive on teh internetz, because I don't mean it that way at all. I'm clearly having a hard time figuring out how that would work, but I'm genuinely interested/curious and want to understand better. I figure you know way better than I do and I guess you can never account for what everybody might do. I do still agree that it's better to use something that's already there...

#44 @WraithKenny
13 years ago

  • Cc Ken@… added

#45 in reply to: ↑ 43 ; follow-up: @Otto42
13 years ago

Replying to helenyhou:

Does this mean that plugin authors have to anticipate or provide options for what the theme is calling their template part(s), though?

Not at all. But if there was a standard naming scheme, then theme authors would likely use it to be compatible.

What if it should be attached to a completely different template part depending on context?

A plugin could provide an option to do that, if it was desired. That sorta depends on what the plugin does.

I don't mean to just fire off questions and perhaps sound belligerent or defensive on teh internetz, because I don't mean it that way at all. I'm clearly having a hard time figuring out how that would work, but I'm genuinely interested/curious and want to understand better. I figure you know way better than I do and I guess you can never account for what everybody might do. I do still agree that it's better to use something that's already there...

What I'm thinking is that if there was a standard way to name things, much like the template hierarchy, then theme authors could choose to use it. Plugin authors could use that to hook into specific places in the theme. This doesn't have to be limited to the content and the loop and such. The idea can expand beyond that.

For example, what if the concept of a "menu" became a part? Theme authors could call get_template_part('menu') and have a menu.php file that output their menu. Maybe this would be as simple as a call to wp_nav_menu or maybe it could be complex. Depends on the theme.

But if they were calling this function, then a plugin could hook into get_template_part_menu or get_template_part_menu_after to put things before or after the menu area on the page.

The idea of template parts, as a whole, allows the theme author to break the page down into specific "areas" and have the output for each of them separated. This allows child themes to easily override whole areas of the page without affecting the rest of it. It also allows themes to define these named areas with fallbacks, so I could say get_template_part('menu','page_slug') for example (replace 'page_slug' with whatever gets the current page slug), and then be able to define menu-slug.php for having individual menus for different pages. get_template_part already does this.

So it makes sense, if you're giving theme authors a way to divide their theme into areas, to allow plugins to hook in before and after those areas to produce content. Simple as that, really. If we let theme authors divide the page into named chunks, then give them a standard for naming those chunks, then we can have known names.

If themes don't use those area names, then you have the same situation as now. Themes have to be modified by the end user to include calls to functions in plugins, or whatever. This is unchanged. But the goal is to make it so plugins can try to hook into those standard named areas, and then if the theme supports them, it "just works".

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

#46 in reply to: ↑ 42 ; follow-ups: @Otto42
13 years ago

Replying to mikeschinkel:

+1 to offer a few different new approaches that are designed to leverage the same plugin hooks; a template tag (i.e. the_rest()), sidebars as template zones, and especially a huge +1 to the_loop().

A massive -1 million to "the_loop()". Theme authors *won't* use it. They'll flat out rebel against you for trying.

Look at my post on my blog about the comment_form(). Look real closely at the comments on that post. Theme authors *hate* it when you take away any amount of their ability to output HTML. Theme authors *hate* it when you tell them to use actions and filters to modify HTML. They don't get it, and they never will.

get_template_part() is a great solution because it lets you divide up a theme into areas and retain control over those areas. Which is all plugin authors really want, the ability to insert things into proper places on the page. Standardizing away whole sections of themes into core doesn't really work, and people hate it.

#47 @nathanrice
13 years ago

I think adding contextual hooks to get_template_part() is a great idea. But a solution to the problem posed by the OT, it is not.

A standard like the_rest() is FAR more likely to be adopted by the majority of theme authors than the use (or perhaps some would say, overuse) of get_template_part(). For instance, I could implement the_rest() in Genesis TOMORROW, whereas trying to use get_template_part() in Genesis would require much more work and forethought.

A comprehensive solution (with before/after hooks firing in pre-existing template tags, introducing the_rest() or something similar, etc.) is long overdue.

As for the_loop(), I agree with @Otto. It's not something that would be embraced very quickly, if at all.

#48 follow-up: @greenshady
13 years ago

My idea would be to allow themes to register support for "post hooks". Then, a plugin could check if a theme supports this before deciding to filter the_content. This solution would offer backwards compatibility with old hooks in themes that are already doing this and offer a lot of flexibility for theme authors in terms of where they'd want to place these hooks in their themes.

A theme would register support for this like so:

add_theme_support( 'post-hooks', array( 'before' => 'before_post_hookname', 'after' => 'after_post_hookname' ) );

before and after should have some defaults (e.g., before_post, after_post) so that we could start standardizing on this method. Allowing them to be custom would offer some backwards compatibility for themes with existing hooks.

A theme would use this like so in their theme templates:

do_action( 'before_post' );

Post stuff

do_action( 'after_post' );

A plugin's use:

if ( current_theme_supports( 'post-hooks' ) ) {

	$post_hooks = get_theme_support( 'post-hooks' );

	add_action( $post_hooks[0]['after'], 'some_function' );

} else {
	add_filter( 'the_content', 'some_function' );
}

That's my idea anyway. There's not going to be a solution that'll work for everyone without all themes adding the code in.

I think a lot of other theme devs are in the same boat as me. We absolutely hate that plugins hook everything to the_content because it ruins our designs. We'll settle on any standard.

There can be some control over whatever solution is decided upon though. The theme review team will take strides in getting themes up to par. That will at least offer some standardization with themes on the repository.

#49 in reply to: ↑ 45 @helenyhou
13 years ago

Replying to Otto42:

Thanks for taking the time to explain it to me, Otto. I appreciate it, and it makes more sense now.

What if it should be attached to a completely different template part depending on context?

A plugin could provide an option to do that, if it was desired. That sorta depends on what the plugin does.

I guess I see this as something a theme author should usually be in control of instead of relying on a plugin to do the right thing, at least in the original context of sharing plugins and the like. To me it still makes more sense to keep these items a little more conceptually separate from the body of content itself, even just in terms of placement. It seems like we're talking about a funny middle ground between postmeta and comments and some are stuck on it being attached to the content (or the_content).

I personally would still prefer something separate, even if it's something like a standardized get_template_part('the_rest'). And then having contextual hooks for get_template_part() would make it even better!

#50 @mfields
13 years ago

I really like the prospect of filtering get_template_part() and think that it would be a great addition to core to allow better communication between plugins and themes. For this specific issue, @greenshady's idea is one that I really like. Many themes add custom actions both before and after the loop to allow for customizations to be made. A standard in this area would be really great IMHO. Allowing a theme to identify that it supports post_hooks would make it really easy for plugins to decide where to hook.

@Otto42
13 years ago

get_template_part_{$slug}_after

#51 in reply to: ↑ 46 ; follow-up: @mattwiebe
13 years ago

  • Cc matt@… added

Replying to Otto42:

Replying to mikeschinkel:

+1 to offer a few different new approaches that are designed to leverage the same plugin hooks; a template tag (i.e. the_rest()), sidebars as template zones, and especially a huge +1 to the_loop().

A massive -1 million to "the_loop()". Theme authors *won't* use it. They'll flat out rebel against you for trying.

Did you read what I wrote there re: the_loop? I'm not taking anything away. I'm just moving loop contents into loop.php (by default), where they can do whatever the hell they want HTML-wise. Plus hooks that'll run before and after each iteration of the loop.

#52 in reply to: ↑ 51 ; follow-up: @Otto42
13 years ago

Replying to mattwiebe:

Did you read what I wrote there re: the_loop? I'm not taking anything away. I'm just moving loop contents into loop.php (by default), where they can do whatever the hell they want HTML-wise. Plus hooks that'll run before and after each iteration of the loop.

Okay, I see that now, but the function you posted is doing it wrong. You're using the "loop" part name for the contents of the loop, instead of for the loop itself. This conflicts with twentyten's use of the "loop" part name, and does essentially what twentyeleven's "content" part name does.

Also, just wrapping the while ( have_posts() ) : the_post(); ... endwhile; with some hooks around it seems of limited benefit to me. Theme authors understand the loop already. Wrapping it isn't really needed.

#53 @ev3rywh3re
13 years ago

get_template_part is just a fantastic way to extend plugins and themes and I'm said more themes don't use it. You add some logic around it and you've something really powerful (especially in building enterprise-esqe intertwined child themes, but what the heck do I know?)

One suggestion I do hope for is that form follows function in the naming scheme. It's easer to grok the_content_before the_loop_start than before_the_content start_the_loop. I know in english it's just easier to say, but I see a bunch of that in core so sorting filters, css, and other stuff can be a real bear.

Only a naming scheme suggestion if one arrives.

#54 follow-ups: @johnjamesjacoby
13 years ago

I think my "the_rest()" approach is the simplest and easiest to wrap your head around for 3.3.

That said, I'm all for get_template_part() getting more muscle. It's because of a lack of filters and actions that bbPress 2.0 has its own wrapper for it: http://bbpress.trac.wordpress.org/browser/branches/plugin/bbp-includes/bbp-core-compatibility.php#L82

Otto's patch is a good start but get_template_part() could/should be much more powerful. Example: bbPress 2.0 uses template parts to power its shortcodes so that a theme *can* dictate the appearance if it elects to, but it doesn't have to. Template parts are loaded into on output buffer, and presented wherever you put them. Easy.

WordPress could work similarly with a more powerful get_template_part(). Imagine WordPress coming not just with a new default theme every year, but a default theme-construct of common template parts. Those parts are used when the existing theme does not include them, like how comments works now, but for the header, footer, sidebar, archive, you-name-it. Generic core template parts, always built on the latest and greatest web standard, maintained by the community, for the community.

Last edited 13 years ago by johnjamesjacoby (previous) (diff)

#55 @johnjamesjacoby
13 years ago

More to my point above, if Jane's active theme doesn't have a template part for 'the_content_intro' or 'the_content_closer', WordPress can automatically insert them for her, if plugins tell WordPress those templates are needed.

#56 in reply to: ↑ 54 ; follow-up: @Otto42
13 years ago

Replying to johnjamesjacoby:

That said, I'm all for get_template_part() getting more muscle. It's because of a lack of filters and actions that bbPress 2.0 has its own wrapper for it: http://bbpress.trac.wordpress.org/browser/branches/plugin/bbp-includes/bbp-core-compatibility.php#L82

Otto's patch is a good start but get_template_part() could/should be much more powerful. Example: bbPress 2.0 uses template parts to power its shortcodes so that a theme *can* dictate the appearance if it elects to, but it doesn't have to. Template parts are loaded into on output buffer, and presented wherever you put them. Easy.

BTW, I was looking at this the other day, and for your specific use case in bbPress, I think a filter down in locate_template makes the most sense. Putting this in there would work:

$located = apply_filters( 'locate_template', $located, $template_names );

It allows a plugin to either override any existing template, or find/add a different template from a different directory, if needed. This would give the functionality you were talking about back in Chicago without the wrapper.

#57 in reply to: ↑ 48 ; follow-ups: @aaroncampbell
13 years ago

This thicket was moving so fast this morning that I couldn't post to it! Anyway, I'm with Otto that editing something that exists is a better idea. However, to give the flexibility that Jane is looking for I don't think you can assume that the end of any given template file is the correct place to put the post extras. Not to mention, themes can call files whatever they want when using get_template_part, so how would a plugin know WHICH file to hook to?

I think using hooks like 'before_post_content' and 'after_post_content' makes the most sense, but a plugin needs to be able to fall back to using the the_content filter if those don't exist, so I think using add_theme_support() make sense (basically just what mikeschinkel and greenshady said). The disadvantage is that until now we've only asked theme authors to add something like do_action( 'wp_head' ) but it would be best to have them call this one like do_action( 'after_post_content', $post ). I'm always cleaning up after poorly coded plugins that are overwriting the global $post, but if it was passed to the action it wouldn't be an issue.

Last edited 13 years ago by aaroncampbell (previous) (diff)

#58 in reply to: ↑ 56 @johnjamesjacoby
13 years ago

Replying to Otto42:

Replying to johnjamesjacoby:

That said, I'm all for get_template_part() getting more muscle. It's because of a lack of filters and actions that bbPress 2.0 has its own wrapper for it: http://bbpress.trac.wordpress.org/browser/branches/plugin/bbp-includes/bbp-core-compatibility.php#L82

Otto's patch is a good start but get_template_part() could/should be much more powerful. Example: bbPress 2.0 uses template parts to power its shortcodes so that a theme *can* dictate the appearance if it elects to, but it doesn't have to. Template parts are loaded into on output buffer, and presented wherever you put them. Easy.

BTW, I was looking at this the other day, and for your specific use case in bbPress, I think a filter down in locate_template makes the most sense. Putting this in there would work:

$located = apply_filters( 'locate_template', $located, $template_names );

It allows a plugin to either override any existing template, or find/add a different template from a different directory, if needed. This would give the functionality you were talking about back in Chicago without the wrapper.

I will do you one better. You get the idea:

function locate_template($template_names, $load = false, $require_once = true ) {

	// Setup names and paths
	$template_paths = array( TEMPLATEPATH, STYLESHEETPATH );
	$template_names = apply_filters( 'locate_template_names', $template_names );
	$template_paths = apply_filters( 'locate_template_paths', $template_paths );

	// Remove empties
	$template_names = array_filter( $template_names );
	$template_paths = array_filter( $template_paths );

	// Reverse paths so no reordering is needed by themes or plugins
	$template_paths = array_reverse( $template_paths );

	// Allow overloading of locate_template
	$located        = apply_filters( 'pre_locate_template', '', $template_names, $template_paths );

	// Skip the check if 'pre_locate_template' overloaded everything
	if ( empty( $located ) ) {
		
		// Loop through template names
		foreach ( (array) $template_names as $template_name ) {

			// Loop through paths (in hierarchical order!)
			foreach ( (array) $template_paths as $template_path ) {

				// File exists
				if ( file_exists( $template_path . '/' . $template_name ) ) {
					$located = $template_path . '/' . $template_name;
					break;
				}
			}
		}
	}

	// Only load the template if one is found
	if ( $load && '!empty( $located ) )
		load_template( $located, $require_once );

	return $located;
}

The concept here is to allow file names AND paths to be filtered. Plugins then can include their own fall-back templates in their own locations. In this scenario, bbPress can add itself to the available arrays based on the context and provide an appropriate WordPress core fall-back in the event something is missing that shouldn't be.

Last edited 13 years ago by johnjamesjacoby (previous) (diff)

#59 in reply to: ↑ 57 ; follow-up: @johnjamesjacoby
13 years ago

Replying to aaroncampbell:

This thicket was moving so fast this morning that I couldn't post to it! Anyway, I'm with Otto that editing something that exists is a better idea. However, to give the flexibility that Jane is looking for I don't think you can assume that the end of any given template file is the correct place to put the post extras. Not to mention, themes can call files whatever they want when using get_template_part, so how would a plugin know WHICH file to hook to?

I think using hooks like 'before_post_content' and 'after_post_content' makes the most sense, but a plugin needs to be able to fall back to using the the_content filter if those don't exist, so I think using add_theme_support() make sense (basically just what mikeschinkel and greenshady said). The disadvantage is that until now we've only asked theme authors to add something like do_action( 'wp_head' ) but it would be best to have them all this one like do_action( 'after_post_content', $post ). I'm always cleaning up after poorly coded plugins that are overwriting the global $post, but if it was passed to the action it wouldn't be an issue.

The flaw with the before/after logic is that this information may not truly exist in a physical place directly before or after the_content(). It might be after the content AND after a bio of the author, but before the prev/next navigation and comment river. Due to the unpredictability of theme layouts and needs, that approach doesn't apply to this scenario. It is however an approach that I am in agreement with, just not to solve this particular problem. :)

#60 in reply to: ↑ 59 @aaroncampbell
13 years ago

Replying to johnjamesjacoby and Otto42:
Adding one or more of these filters would help with the HTML E-Mails too since it wraps get_template_part in order to load a template from somewhere other than TEMPLATEPATH or STYLESHEETPATH

Replying to johnjamesjacoby:
You're right. Those are poorly named, but I think they're still what you want. Maybe 'before_post' and 'after_post' or maybe call it something completely different like 'post_extras' as someone above mentioned. I just think it needs to be paired with the add_theme_support() bit so that plugins can fall back. This way plugins still WORK on all themes but work BETTER on themes that support this.

#61 @johnjamesjacoby
13 years ago

Another approach would be to hook into 'loop_end', check is_single(), and call some action then. That guarantees code execution at the bottom of every content area, since 'loop_end' fires after the loop has already ran it's full course on a single page/post.

The problem I see with this is having WordPress core hook directly into the query layer for something only the theme layer will use. If we're willing to make that compromise, it's the most reliable way to guarantee code execution at the very bottom of a post loop.

#62 @brianlayman
13 years ago

  • Cc Brian@… added

#63 in reply to: ↑ 54 @helenyhou
13 years ago

Replying to johnjamesjacoby:

I think my "the_rest()" approach is the simplest and easiest to wrap your head around for 3.3.

I (obviously) agree, for whatever that's worth :)

#64 in reply to: ↑ 52 @mattwiebe
13 years ago

Replying to Otto42:

Okay, I see that now, but the function you posted is doing it wrong. You're using the "loop" part name for the contents of the loop, instead of for the loop itself. This conflicts with twentyten's use of the "loop" part name, and does essentially what twentyeleven's "content" part name does.

Sure. Use content instead of loop. That makes sense.

Also, just wrapping the while ( have_posts() ) : the_post(); ... endwhile; with some hooks around it seems of limited benefit to me. Theme authors understand the loop already. Wrapping it isn't really needed.

The "limited" benefit is that we now own the process. We can change it down the road if need be. This buys us way more future-proofing. Also, this is even easier for theme authors to understand, whereas trying to convince them to use get_template_part() is harder. Not only that, but we need to get them to standardize around the $name part in order for plugin filtering to even be useful, which would again probably just require a wrapper function of some type.

#65 in reply to: ↑ 57 @SergeyBiryukov
13 years ago

Replying to aaroncampbell:

Not to mention, themes can call files whatever they want when using get_template_part, so how would a plugin know WHICH file to hook to?

That same idea of add_theme_support() can be applied here too.

Twenty Eleven could use something like:

add_theme_support( 'template-parts', array( 'content' => 'content' ) );

Twenty Ten:

add_theme_support( 'template-parts', array( 'content' => 'loop' ) );

18561.get_template_part_slug.patch introduces the get_template_part_slug() function to determine the actual template part slug used by current theme.

A plugin could then use something like:

if ( $content = get_template_part_slug( 'content' ) ) {
	add_action( "get_template_part_{$content}_after", 'some_function' );
} else {
	add_filter( 'the_content', 'legacy_function' );
}

#66 in reply to: ↑ 57 @jb510
13 years ago

Replying to aaroncampbell:

This thicket was moving so fast this morning that I couldn't post to it! Anyway, I'm with Otto that editing something that exists is a better idea. However, to give the flexibility that Jane is looking for I don't think you can assume that the end of any given template file is the correct place to put the post extras. Not to mention, themes can call files whatever they want when using get_template_part, so how would a plugin know WHICH file to hook to?

I think using hooks like 'before_post_content' and 'after_post_content' makes the most sense, but a plugin needs to be able to fall back to using the the_content filter if those don't exist, so I think using add_theme_support() make sense (basically just what mikeschinkel and greenshady said). The disadvantage is that until now we've only asked theme authors to add something like do_action( 'wp_head' ) but it would be best to have them all this one like do_action( 'after_post_content', $post ). I'm always cleaning up after poorly coded plugins that are overwriting the global $post, but if it was passed to the action it wouldn't be an issue.

Aaron gets to the problem I see with template_part which is how any plugin author would know what part to rely on. If plugin authors are just creating template parts on their own then they are not going to coincide and group properly which I think is what Jane is (wisely) after. Hooks in core would provide a reliable place for plugin authors. Relying on theme support again means that plugin authors can't rely on it and would need to write extra conditional code to handle when the theme doesn't offer support wouldn't it?

BTW, was thicket a freudian slip?

#67 @coffee2code
13 years ago

Tangential, in reply to Otto42 and johnjamesjacoby:

Check out #13239 for a discussion and patch in the vein of adding filters to locate_template(). My original patch from a year ago includes the filter that @Otto42 proposed above (amongst other related filters in the function) but I pared it out at @nacin's request to reduce the number of filters added and kept to a single, more versatile filter located at the beginning of the function (the spirit of @johnjamesjacoby's patch above, but without additional filters to separately pre-filter the template names and paths or pre-locate).

Happy to see more feedback there. 13239.c2c.4.diff is my latest patch, with an eye towards minimizing the change footprint.

#68 in reply to: ↑ 41 @azaozz
13 years ago

Replying to Otto42:

There is the_post hook in setup_postdata, however this has the problem that it fires before every post's output, and that it has the next post already set up by the time it fires. So having it output something specific to the previous post is problematic.

IMHO this is the right hook to use. It fires exactly between the posts.

We can even split it into two new hooks if need be (don't see the point though). Can make 'the_post' to call 'after_the_content' and provide the previous $post (can be kept in a static or a global) followed by 'before_the_content' and provide the new $post.

Perhaps it will be simpler to just provide both posts as args, so 'the_post' will have access to both the previous and next posts. That will make it useful in all cases.

#69 in reply to: ↑ 46 @GaryJ
13 years ago

Replying to Otto42:

Theme authors *hate* it when you take away any amount of their ability to output HTML. Theme authors *hate* it when you tell them to use actions and filters to modify HTML. They don't get it, and they never will.

All the developers creating child themes of Thesis, Genesis and likely other theme frameworks would disagree with that - make one alteration, and hooking it in once makes far more sense (and far less work) than altering duplicate code in several files as was traditionally done; it solves the same problem that template parts does (as I understand them), and it's just a different way of working. One has a (typically parent) theme with lots of hooks scattered around, the other expects files to have certain names.

If theme authors aren't switching over to using template parts, then the benefits of them need to be explained clearer, and get the theme framework guys on board. Maybe having an agreed list of parts that are intended to cover all the areas that hooks within the frameworks do would be a start. Even so, getting existing frameworks to switch would be a big ask.

What we need is something that all theme authors know should be in their themes if they want them to play nicely with plugins - a la wp_head(), wp_footer() etc. and that includes making use of the common ways of grabbing the content: the_title(), the_content(), the_excerpt() and so on - it's for this reason that a simple the_post_extras() or the_rest() will solve the issue for now, until the above problems of turning the tide and getting everyone on board with using template parts is solved.

#70 @aaroncampbell
13 years ago

Replying to jb510:

BTW, was thicket a freudian slip?

Possibly...that or just a typo ;)

Replying to azaozz:

IMHO this is the right hook to use. It fires exactly between the posts.

What about single posts where there is no second post to set up? Also this increases the complexity of the plugin logic require because it needs to ignore the first the_post call and then take action on the next ones (although if you pass current post and previous post it could just look for previous post)...but still how do you handle the last post in the set?

#71 @KMBredt
13 years ago

What about a more extreme-version of the get_template_part by introducing an selector-approach probably known from jQuery. I stumbled upon it, while dealing with the Infinite Scroll plugin, although they are using it on the client-side, a server-side version should be able to provide what's needed (if that is even possible). Instead of targeting specific files one could target a <div> with a certain ID or other HTML-elements with IDs or classes.

You would have a function (e.g.: wp_selector()) which has at least three arguments. One for what to select (to help theme- and plugin-developers a CSS/jQuery-syntax is probably preferred), one to decide if the content or the actions, which should be inserted or happen, are inserted/do happen before or after the found selector, and the third argument gives the content or action.

For example:

wp_selector('.postmetadata','after','gplusbutton');

Plugin-developers would need to add an option or two to let the designer/user insert the specified selector to satisfy all needs. This should make it very easy to set the right hooks at the right places. Perhaps a fourth option could add a z-index-like approach to deal with plugins rooting for the same place.

If the selector is not present or couldn't be found a more common hook can be set as a fifth argument and act as a fallback.

Please note, that I have absolutely no clue if this is even technically possible.

#72 @DrewAPicture
13 years ago

Instead of targeting specific files one could target a <div> with a certain ID or other HTML-elements with IDs or classes.

This is kind of a novel solution. I'm mildly more on board with Otto's suggestion about get_template_part but I still strongly believe you'd be hard-pressed to standardize the process. The frameworks seem to be using get_template_part calls but a lot of the indie shops seem to be completely ignoring them. I'd say our best bet is to come up with the solution that the most theme authors can A) Easily adapt to and B) Easily implement. It's a delicate balance between satisfying all of the communities with a workable solution.

Either way, I think KMBredt wants the Brownies

Last edited 13 years ago by DrewAPicture (previous) (diff)

#73 follow-up: @azaozz
13 years ago

Replying to aaroncampbell:

I'd imagine it working like this:

add_action( 'the_post', 'my_func', 10, 2 );

function my_func($next_post, $previous_post) {

  if ( $previous_post ) { // will be null for the 1st post in the loop
    // do something after the post content
  }

  if ( $next_post ) {
    // do something before the next post content
  }
}

For the last post it would need to hook into 'loop_end':

add_action( 'loop_end', 'my_end' );

function my_end() {
  global $post;

  my_func(null, $post);
}

Perhaps that's a bit complicated. We still can make two new actions that are fired like the above functions.

Last edited 13 years ago by azaozz (previous) (diff)

#74 @mikeschinkel
13 years ago

Replying to Otto42:

Also, just wrapping the while ( have_posts() ) : the_post(); ... endwhile; with some hooks around it seems of limited benefit to me. Theme authors understand the loop already. Wrapping it isn't really needed.

Wrapping eliminates the need to duplicate commonly-used code in every theme file, but more importantly it opens the door to be able to annotate the_loop() with new "standard" hooks that plugins can depend on, when the theme specifies that it is using 'the_loop() of course.

Replying to johnjamesjacoby:

The concept here is to allow file names AND paths to be filtered. Plugins then can include their own fall-back templates in their own locations.

+1

#75 in reply to: ↑ 73 @aaroncampbell
13 years ago

Replying to azaozz:

Replying to aaroncampbell:

I'd imagine it working like this:

[...]

Perhaps that's a bit complicated. We still can make two new actions that are fired like the above functions.

I suppose. The problem is that this puts something at the end of the loop, but that's not guaranteed to be where a theme wants the "post extras" to go any more than the end of the_content is. If we create common hooks that we encourage theme authors to use and then let plugins fall back to the_content (or exactly what you proposed above) then we can allow theme authors to decide where this kind of content goes, which I *think* is exactly who SHOULD decide...right?

#76 follow-up: @johnjamesjacoby
13 years ago

I think there are a few different approaches here. To summarize, the ideas on the table are:

  • Create a template tag to output the rest of a posts non-metadata. [get_the_rest() + the_rest()]
  • Create a template part hierarchy to compliment the existing template hierarchy.
  • Hook theme specific actions into WordPress core functions, so code can be executed within any WordPress theme more predictably, regardless of the theme. (This includes the before/after suggestions)

All of these are great ideas but only the template tag approach accurately solves this particular problem. Functions are easy for people to remember because they are native to PHP, unlike WordPress action names which are native to WordPress. Functions that start with "the_" are the first thing most people learn about WordPress, so they are an easy addition in moderation.

The next best approach is having a dedicated set of theme actions fire at appropriate times in the page-load process. This is what most theme frameworks already attempt to do, so clearly it's popular and functional. BuddyPress and bbPress both already take this approach with their default themes, and having a standardized set of WordPress core theme actions would be, in a word, awesome.

The get_template_part() and locate_template() tweaks also should make their way into WordPress core. These enhancements along with a set of core theme actions are the plugin authors' holy grail to reliably piggy backing any WordPress theme without jumping through flaming hoops of fearful incompatibility with thousands of awesome themes.

Last edited 13 years ago by johnjamesjacoby (previous) (diff)

#77 in reply to: ↑ 76 @aaroncampbell
13 years ago

Replying to johnjamesjacoby:

I agree, I think the template tags are a the best option here (basically a helper function used to fire the actions). The problem is that the functions aren't enough. Plugins need to know whether a theme uses them, so we still need something like add_theme_support( 'the_rest' )

#78 @greenshady
13 years ago

I wrote a post that better explains my thoughts from above instead of cluttering up this ticket:
http://devpress.com/blog/a-better-way-for-plugins-to-hook-into-theme-templates/

I believe this idea would work hand-in-hand with the idea of using template tags.

#79 @ericmann
13 years ago

Another alternative is to create a hook/filter like we do with contact methods in the user profile. The function _wp_get_user_contact_methods() returns a filterable list that's turned into the input fields for AIM, Yahoo, and Jabber in the profile. A similar (filterable) function _wp_get_social_media_icons() would be able to do the same thing.

#80 @chipbennett
13 years ago

  • Cc chip@… added

Okay, so, this seems so obvious and simple to me - so clearly I'm missing something.

Why not just change this:

function the_post() {
	global $wp_query;
	
	$wp_query->the_post();
}

...to this:

function the_post() {
	global $wp_query;

	do_action( 'the_post_before' );
	
	$wp_query->the_post();

	do_action( 'the_post_after' );
}

It supports the existing Loop markup of every Theme in existence. It requires no changes to the Theme template for either the Theme or Plugins to hook into the the_post_before and the_post_after hooks.

What am I missing?

@chipbennett
13 years ago

Add the_post_before and the_post_after hooks to fire inside of the_post()

#81 @Otto42
13 years ago

Chip: the_post() doesn't create the output. It just sets up the post variables. Having a before and after in there wouldn't work for this.

Consider the standard loop:

while (have_posts()) : the_post();

That "the_post" call is where you're putting your before and after. Not the right place.

#82 follow-up: @chipbennett
13 years ago

@Otto42 see, I knew I was missing something!

So, it would work for firing a hook before the post output, but not after.

Back to the drawing board.

@aaroncampbell
13 years ago

Adds the_rest()

@aaroncampbell
13 years ago

Adds support for the_rest() to Twenty eleven

#83 follow-up: @chipbennett
13 years ago

After reading over all of the comments, my initial opinion is that hacking up get_template_part() really isn't the best approach. I think the the_rest() idea has merit (although we need to come up with a much more semantic name for the function).

However, if the intent is to implement standard hooks, then let's just do that: define and implement standard hooks. The idea was brought up a long time ago, but as far as I could tell, no consensus was ever reached.

So, I propose that we do this, and we do it right, the first time:

  • Standardize on a hook nomenclature
  • Standardize a list of Theme "locations" for which action hooks are appropriate
  • Wrap those hooks in template tags, as with wp_head() and wp_footer()
  • Require Themes to implement the template tags, as is currently required for wp_head() and wp_footer()

In the long run, this approach has all the benefits of both the get_template_part_{hook} approach and the the_rest() approach, and will be far more flexible for Themes, Plugins, AND core.

#84 @aaroncampbell
13 years ago

Ok, I put up two patches:

18561.diff adds the_rest which was JJJ's idea. I simplified his original idea by removing the before_the_rest and after_the_rest actions because you can just add a low or high priority to your action to accomplish the same thing.

18561.twentyeleven.diff adds the_rest support to TwentyEleven by having it use the_rest() as well as having it announce that it does with add_theme_support. Hopefully one of the theme guys can add any styling that is needed for properly positioning it, but it will put this content BELOW the "This entry was posted in..." line.

I tested it with a plugin of mine that adds related posts by appending to the_content. This is the basic code that a plugin would use:

function how_to_insert() {
	if ( current_theme_supports( 'the-rest' ) )
		add_action( 'the_rest', 'show_via_the_rest' );
	else
		add_filter( 'the_content', 'filter_post_content' );
}
add_action( 'after_setup_theme', 'how_to_insert', 99 );

function show_via_the_rest( $post ) {
	echo get_related_posts( $post );
}

function filter_post_content($content) {
	$content .= get_related_posts();
	return $content;
}

#85 @brianlayman
13 years ago

I second Chip on this. Adding the extra hooks & tags won't break anything in current themes. It goes well beyond the specific issue in this ticket, but it addresses the core problem and will reduce the number of times we have to hack existing themes to do what the customer wants. Getting the list will be the most controversial process as there will always be room for more. But as long as we don't go hog wild, we won't affect page generation speed.

#86 in reply to: ↑ 83 @GaryJ
13 years ago

Replying to chipbennett:

(although we need to come up with a much more semantic name for the function).

+1. I've given a few suggestions in my various posts above - not sure if people were using "the_rest" because they liked it (I don't), or just making it clear they were referring to that particular idea.

It's kind of like content meta, content extras, or content aside, or perhaps content tools - something related to that particular content.

#87 follow-up: @aaroncampbell
13 years ago

Replying to chipbennett:

I think that what you're talking about is actually an extension of the_rest. If you look at my patch ( 18561.diff and 18561.twentyeleven.diff ) it's basically just what you're saying just only for ONE hook. Coming up with a list of standard hooks would be great. If we start requiring them in the theme directory maybe we won't need the add_theme_support() calls.

Replying to brianlayman:

Adding the extra hooks & tags won't break anything in current themes.

While it won't break current themes, it WILL be difficult for plugins that use them to transition, requiring them to have some way to fall back for themes that DON'T have the new hooks.

#88 @helenyhou
13 years ago

Replying to chipbennett:

we need to come up with a much more semantic name for the function

Stepping back from it, I think I agree. We could always go back to what I was first calling it, post_extras (or, rather, the_post_extras) :) Not that I'm biased or anything, you know.

+1 to add_theme_support(), at least for now.

#89 in reply to: ↑ 87 @chipbennett
13 years ago

Replying to aaroncampbell:

Replying to chipbennett:

I think that what you're talking about is actually an extension of the_rest. If you look at my patch ( 18561.diff and 18561.twentyeleven.diff ) it's basically just what you're saying just only for ONE hook.

Looking at the patch, probably so (though I would recommend naming it something like wp_after_post() or something equally semantic). The point is, though, that we should first standardize, and then patch. Adding pre/post-post hooks makes perfect sense - so much so, that the idea will prompt addition of other equally useful hooks. Let's plan ahead for that happening, so that we have an established location/naming convention.

Coming up with a list of standard hooks would be great. If we start requiring them in the theme directory maybe we won't need the add_theme_support() calls.

Going this route makes it easier to add to the Theme Review guidelines support for any such hooks. Rolling out support for these hooks would be pretty easy, since 1) we could establish easy-to-follow instructions for the Theme Review Guidelines, and 2) most commercial Themes implement similar hooks anyway, and would very easily be able to support WP-core variations of those hooks.

Replying to brianlayman:

Adding the extra hooks & tags won't break anything in current themes.

While it won't break current themes, it WILL be difficult for plugins that use them to transition, requiring them to have some way to fall back for themes that DON'T have the new hooks.

The same is true for wp_head() and wp_footer(). As with these template tags, the key is developer education of importance and proper implementation.

Another benefit of first creating a standard nomenclature is that we can begin developer education long before implementation happens.

#90 @ev3rywh3re
13 years ago

I think an additional template tag function is appropriate and usable as it won't break anything new. I like the name the_post_extras() and as a template function you could pretty much wrap as much complex junk as you wan into it.

the_post_extras( 'extra_name', 'place_before_after_etc', 'type_templatePart_action' );

Something like that maybe? Without arguments it does some expected defaults? You can make some wrappers like the_post_extras_before() the_post_extras_after() to give some simple help.

#91 in reply to: ↑ 82 @jb510
13 years ago

<deleted>

Last edited 13 years ago by jb510 (previous) (diff)

#92 follow-up: @azaozz
13 years ago

Replying to chipbennett:

This makes sense. So, to summarize:

  • decide on new (compulsory?) template tags,
  • use add_theme_support for them so plugins "know" the currently used theme supports them (this could be only for the transition period, but once theme authors start to use it there's no point of taking it out),
  • popularize/educate theme authors before these template tags become a requirement.
  • decide on a cut-off date by which all themes in the repository should include the new template tags.

#93 in reply to: ↑ 92 ; follow-up: @chipbennett
13 years ago

Replying to azaozz:

Replying to chipbennett:

This makes sense. So, to summarize:

  • decide on new (compulsory?) template tags,
  • use add_theme_support for them so plugins "know" the currently used theme supports them (this could be only for the transition period, but once theme authors start to use it there's no point of taking it out),
  • popularize/educate theme authors before these template tags become a requirement.
  • decide on a cut-off date by which all themes in the repository should include the new template tags.

I'm not sold on the add_theme_support() implementation, because as you noted, once adoption is widespread, add_theme_support() becomes superfluous. If that's the way it gets implemented, so be it. My major concern is the standardization of nomenclature and Theme locations/actions where such hooks get fired.

As for the implementation process: yeah, that's pretty much how I see it.

If I were to start up a conversation among the Theme Developers, should I direct them to this ticket, or just start a discussion thread on the make.wordpress.org/themes site?

#94 in reply to: ↑ 93 @azaozz
13 years ago

Replying to chipbennett:

I'm not sold on the add_theme_support() implementation...

Yes, but during the transition we need to let plugins know when a theme supports the new template tags. The add_theme_support seems the best way to do it. The transition would probably be at least few months, maybe longer.

If I were to start up a conversation among the Theme Developers, should I direct them to this ticket, or just start a discussion thread on the make.wordpress.org/themes site?

I'm thinking it's better to start by posting on make.wordpress.org/themes. This ticket is getting far too long as is :). Also (I hope) we have decided to do that, the discussion should probably be about what template tags, where exactly, naming, cut-off date, etc.

Going through the tons of comments here, seems we can do something like this as proposed by @mattwiebe:

wp_before_the_loop();
while ( have_posts() ) : the_post();
  ?>
  // opening div?
  <?php wp_before_post_content(); ?>

  // theme specific code...

  <?php wp_after_post_content(); ?>
  // closing div?
  <?php
endwhile;
wp_after_the_loop();

#95 @sbressler
13 years ago

  • Cc sbressler@… added

#96 @sirzooro
13 years ago

  • Cc sirzooro added

#97 @anonymized_7658014
13 years ago

Don't really have a say here, but maybe one of you guys is able to see the idea behind this:

  1. Add a new metabox to the edit-screen similar to this plugin, but with wysiwyg and all.
  2. This way create a widget area on a per-post basis and fill it with wysiwyg content.
  3. Maybe even make widgets accessible from the edit-screen to be inserted into that new widget area.

Benefits:

  • Enable the user to control secondary content on a per-post basis.
  • All that plugin authors would have to do is include a shortcode and/or editor-button and/or widget for their plugin (as many do already) to enable the user to insert plugin content next to their post content.

#98 @mau
13 years ago

  • Cc ngomau@… added

#99 @strider72
13 years ago

I hope I'm not too late to the party, but there's a solution to this that could be implemented in a theme that requires NO CHANGES to Core whatsoever.

Fight fire with fire. How about a theme just using the the_content hook to add the post meta, at an early priority?

#100 follow-up: @husobj
12 years ago

  • Cc ben@… added

I certainly would like to have more control over locate_template() including files with a filter.

I like both Otto's filter:
http://core.trac.wordpress.org/ticket/18561#comment:56

and, JJJ's filter:
http://core.trac.wordpress.org/ticket/18561#comment:58

Having that extra control over templates seems almost like a separate issue to the title of this ticket though.
Should that have it's own Trac ticket?

#101 in reply to: ↑ 100 @coffee2code
12 years ago

Replying to husobj:

I certainly would like to have more control over locate_template() including files with a filter.

...

Should that have it's own Trac ticket?

See #13239 (and my comment above).

#102 @jane
12 years ago

So... what's the best/right answer for this? Calling all lead developers and committers for an opinion.

#103 @Ipstenu
12 years ago

  • Cc ipstenu@… added

#104 @dd32
12 years ago

So... what's the best/right answer for this? Calling all lead developers and committers for an opinion.

Because it can't be done automatigically for all themes (due to structure and layout) I believe the answer is add_theme_support() + a function with a before/after string.. This is probably something worth working out and adding for TwentyTwelve and back-porting to TwentyTen/TwentyEleven.

#105 @chipbennett
12 years ago

@dd32:

What if Twenty Twelve implemented a new, standard set of Theme action hooks, intended to become the de facto standard for other Themes to emulate?

From a Theme Review Team perspective, I would like that approach, because it is something that we could then phase into the Theme Review guidelines, to help promote Theme adoption of the standard set of Theme hooks.

#106 follow-ups: @GaryJ
12 years ago

Instead of a set of hooks, could they be covered by a single hook function call, such as post_intents(), with a strong eye on Web Intents? That may become the de facto standard in the wider web dev (outside of WP), and there's already a shiv for browsers that don't yet support it natively.

As was previously suggested for the_rest() above, the post_intents() function could be called wherever the theme author wanted (if they wanted) - before the post, after the post, in the sidebar etc. meaning the concept of wanting to do something with the post (share, save, edit, etc.) is separate from any preferred location that the TwentyTwelve authors decide upon.

#107 @bi0xid
12 years ago

  • Cc raven@… added

#108 in reply to: ↑ 106 ; follow-up: @chipbennett
12 years ago

Replying to GaryJ:

The reason I'm proposing a set of hooks is because I'm thinking beyond just the after-post action hook. While right now, the after-post template location might be the most important one to address, in the long run, it would facilitate standardization for a full set of hooks to be created at once, rather than try to add them piece-meal later on.

So, hopefully without hijacking this ticket too much, my thought for the best approach is:

1) Decide on the template locations for which action hooks should be defined
2) Create a standard naming convention for those action hooks (e.g. post_before vs before_post vs post_pre vs pre_post)

For example, the template locations might be:

  • body_before
  • header_before
  • header_after
  • content_before
  • loop_before
  • post_before
  • post_after
  • post_comments_before
  • post_comments_after
  • loop_after
  • content_after
  • footer_before
  • footer_after
  • body_after

See, there really aren't that many to define. And if we need some dynamic hooks, based on get_*() calls for template parts (these could be fired by core, via the get_*() call):

  • sidebar_before
  • sidebar_after
  • sidebar_{slug}_before
  • sidebar_{slug}_after
  • search_form_before
  • search_form_after
  • template_part_{slug}_before
  • template_part_{slug}_after

#110 @helenyhou
12 years ago

While I think the template hooks are nice and would serve their own purposes, I still think that the *before|after nomenclature doesn't really serve what Jane is looking for here, despite what the ticket title says about "below". I think somewhere in this pile of comments, there are thoughts about how these "things" (social media buttons, related posts, whatever else) may actually show in very different places in different templates (under in an archive, sidebar on single, etc.). I recall getting an all-caps YES from Jane :)

So, add_theme_support() plus some kind of location-independent template tag would be my humble vote.

#111 in reply to: ↑ 108 @aaroncampbell
12 years ago

Replying to chipbennett:
I like the idea of a standard set of hooks. Maybe one more of "post_extras" would work to make on that's a little less location-specific.

#112 in reply to: ↑ 106 ; follow-up: @ericmann
12 years ago

Replying to GaryJ:

Instead of a set of hooks, could they be covered by a single hook function call, such as post_intents(), with a strong eye on Web Intents?

I'm all for embracing/setting standards while we make changes like this. And Web Intents seem to be exactly what we're talking about here.

Replying to chipbennet:

The reason I'm proposing a set of hooks is because I'm thinking beyond just the after-post action hook.

As much as I like the idea of a set of hooks, I think that many hooks might just clutter things up. Don't get me wrong, I like having plenty of hooks, but some of the advanced "frameworks" out there already do this. And some are essentially unapproachable for newer theme devs. I get more "how do I do X with Genesis? I can't find the right hook!" emails than anything else.

Replying to aaroncampbell:

Maybe one more of "post_extras" would work to make on that's a little less location-specific.

I think post_intents() in this case is a bit more descriptive than post_extras(). We have a lot of things in the WP ecosystem that are poorly named as is ... so let's try to keep an eye on what it is we're trying to build, what standards we may/may not be trying to reflect, and try to keep on target. "Extras" is too ambiguous IMO.

#113 in reply to: ↑ 112 ; follow-up: @aaroncampbell
12 years ago

Replying to ericmann:

Replying to aaroncampbell:

Maybe one more of "post_extras" would work to make on that's a little less location-specific.

I think post_intents() in this case is a bit more descriptive than post_extras(). We have a lot of things in the WP ecosystem that are poorly named as is ... so let's try to keep an eye on what it is we're trying to build, what standards we may/may not be trying to reflect, and try to keep on target. "Extras" is too ambiguous IMO.

It was the first thing that came to mind. I'm on board with post_intents() if that's the way we decide to go. Having said that, I'm not sure that everything that would go in that area would be web intents.

#114 in reply to: ↑ 113 @chipbennett
12 years ago

Replying to aaroncampbell:

I think post_intents() in this case is a bit more descriptive than post_extras(). We have a lot of things in the WP ecosystem that are poorly named as is ... so let's try to keep an eye on what it is we're trying to build, what standards we may/may not be trying to reflect, and try to keep on target. "Extras" is too ambiguous IMO.

It was the first thing that came to mind. I'm on board with post_intents() if that's the way we decide to go. Having said that, I'm not sure that everything that would go in that area would be web intents.

At the risk of bike-shedding, might I suggest post_meta or post_metadata?

I do like the idea of having such a hook, separate from post_before and post_after, so that the Theme developer has more flexibility in putting the Post's "meta" information (which could include social links, taxonomy, author info, timestamp, etc.) wherever is appropriate for the Theme.

Replying to ericmann:

As much as I like the idea of a set of hooks, I think that many hooks might just clutter things up. Don't get me wrong, I like having plenty of hooks, but some of the advanced "frameworks" out there already do this. And some are essentially unapproachable for newer theme devs. I get more "how do I do X with Genesis? I can't find the right hook!" emails than anything else.

The "frameworks" should be able to support standard hooks with little to no problem.

I use hooks in Oenology, and don't see any problem with incorporating standard hooks. For example, for the body_before standard hook, I have one called oenology_hook_extent_before, that gets called via custom function oenology_hook_post_before():

function oenology_hook_post_before() {
    do_action( 'oenology_hook_post_before' );
}

To incorporate the standard hook, I could just change that to:

function oenology_hook_post_before() {
    do_action( 'body_before' );
    do_action( 'oenology_hook_post_before' );
}

(There are other ways, of course; that's just one.)

The "framework" Themes would be free to include other custom hooks, of course - but that shouldn't preclude them from supporting standard hooks. But ultimately, the sooner that core establishes a set of standard hooks, the sooner the developers of the "framework" Themes can be encouraged to begin to integrate support for those standard hooks in their Themes.

#115 @GaryJ
12 years ago

+1 for Chip's standard hooks idea, but I think they should go as a separate ticket. Frameworks would have no problems implementing an agreed named hooks, in addition to their own hooks - if the framework and standalone themes all used the same hook names, Eric wouldn't be getting so many emails, as there would be much more consistency. As I said though, different ticket to the issue here, which I think can be solved with a named function a la the_content(), which theme authors can drop in where they wish.

#116 @sabreuse
12 years ago

  • Cc sabreuse@… added

#117 @emiluzelac
12 years ago

  • Cc emil@… added

#118 @kovshenin
12 years ago

  • Cc kovshenin@… added

#119 @DrewAPicture
12 years ago

Related: #21506 - Standard Theme Hooks

#121 @mordauk
11 years ago

  • Cc pippin@… added

#122 @emzo
11 years ago

  • Cc wordpress@… added

#123 @lancewillett
11 years ago

Added #23634 specifically for "after comments" hook.

#124 @SergeyBiryukov
11 years ago

#24154 was marked as a duplicate.

#125 @alex-ye
11 years ago

  • Cc nashwan.doaqan@… added

#126 @jdgrimes
11 years ago

  • Cc jdg@… added

#127 @wonderboymusic
10 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to wontfix
  • Status changed from new to closed

In favor of #21506

#128 @tw2113
7 years ago

Since #21506 got closed as "wontfix", is there any reason we couldn't re-open this one and at least get a do_action( "get_template_part_{$slug}_after", $slug, $name ); hook, as proposed by Otto, added to get_template_part()? It's a change that wouldn't break any backwards compatibility, and would actually provide a lot of flexibility and customization for developers outside of filtering the_content

Last edited 7 years ago by tw2113 (previous) (diff)

#129 follow-up: @jdgrimes
7 years ago

I that this idea is partly missing the mark, and at this point, time would be better spent pursuing the idea of content blocks, which would allow plugins to make bits of content available, and users would be able to arrange them around the post as they see fit. Rather than the location being hard-coded by the plugin based on assumptions about what the theme will look like. I think somewhere in the comments up there it was mentioned that maybe not everything belongs under the post in every theme, sometimes it would do better above/beside it or somewhere else non-standard. What we really need here is standard content-block areas that themes could register, like a post metadata content block area. The plugin could then add its content block to that content block area by default, but the theme would decide how that content block area was displayed, under/beside the post or whatever. And a user could also decide to move the content to a different content block area instead. I don't know, but that sounds like the future to me.

I realize that this might not fit every use-case, but I think we need to clarify the particular use-cases that it wouldn't fit and then tailor any further action on this ticket (or something like it) specifically for that smaller subset of uses, rather than as a way to display everything and anything.

Last edited 7 years ago by jdgrimes (previous) (diff)

#130 in reply to: ↑ 129 ; follow-up: @jb510
7 years ago

Replying to jdgrimes:

I that this idea is partly missing the mark, and at this point, time would be better spent pursuing the idea of content blocks, which would allow plugins to make bits of content available, and users would be able to arrange them around the post as they see fit. Rather than the location being hard-coded by the plugin based on assumptions about what the theme will look like...

I think content blocks are one of the best proposals to come along in quite a while, but they have nothing to do with this ticket or what this ticket aims to provide. Content blocks, are for organizing/controlling/editing content that falls within the post_content space.

This ticket, as I understand it, is about adding a universal hook for adding non-content outside the post_content space. I.e. Share buttons, related posts, ads, but so, calls to action, and anything else one might dream up. StudioPress's Genesis theme has an entry_header and entry_footer hook, its more like those, but as you've seen above the idea is to have it be a non-location specific "extras" or "intents". I still don't really see how those get used effectively in practice but love the concept.

The problem is the idea that plugins can use these, without accounting for what fits where... I think we would be better using before/after and letting plugins offer a setting to select which should be used, and with what priority.

#131 in reply to: ↑ 130 @jdgrimes
7 years ago

Replying to jb510:

I think content blocks are one of the best proposals to come along in quite a while, but they have nothing to do with this ticket or what this ticket aims to provide. Content blocks, are for organizing/controlling/editing content that falls within the post_content space.

Note that I'm not referring to the "content blocks" within the editor in recent mockups and prototypes, but the broader idea encompassing shortcodes and widgets that existed before that. See #33473. If I'm understanding that content blocks idea correctly, they were intended to have a broader scope than just the post content. It would also for example include widgets and sidebars, which would basically become another form of content block and content block areas. The whole template could basically be made of of different content areas where content blocks could be added.

Note: See TracTickets for help on using tickets.