WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 2 months ago

#18548 new enhancement

Add a better option for <title> tags

Reported by: joostdevalk Owned by: joostdevalk
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 3.3
Component: Themes Keywords: has-patch dev-feedback
Focuses: template Cc:

Description

Right now, title tags in themes are created by using wp_title and than adding on custom code, usually bloginfo('name'), sometimes other code. Because there's basically no way for a plugin to control the entire content of a title tag, all major SEO plugins resort to output buffering.

A better way would be to output the <title> tag during the run of wp_head, based on whether the current theme has added theme_support. See attached patch for the proposed implementation. This patch also fixes the requested array filter in #17877.

Attachments (5)

title-tag.diff (7.6 KB) - added by joostdevalk 3 years ago.
Patch to add title tag functionality
title-tag.2.diff (5.5 KB) - added by joostdevalk 3 years ago.
Alternate version with new template tag
18548.diff (9.0 KB) - added by nacin 3 years ago.
title-tag-3.diff (8.3 KB) - added by joostdevalk 3 years ago.
Update on Nacin's patch with better handling of date archive titles
title-template-system.diff (14.9 KB) - added by chrisbliss18 2 years ago.
Updated to modify twentyeleven and twentyten

Download all attachments as: .zip

Change History (99)

joostdevalk3 years ago

Patch to add title tag functionality

comment:1 scribu3 years ago

  • Cc scribu added

comment:2 mikeschinkel3 years ago

  • Cc mikeschinkel@… added

+1 to the idea and at first glance at the patch. (I would use false instead of null for 'pre_wp_title_tag' hook, but otherwise looks good though I didn't look deeply at the default options after 'pre_wp_title_tag'.) This would save me a lot of headaches related to title tags (ironically title tags came up as an issue on a conference call this very day.)

comment:3 jaredatch3 years ago

  • Cc jared@… added

comment:4 joostdevalk3 years ago

@mikeschinkel i use null because than a plugin can set to false and decide to output its own title tag.

comment:5 follow-up: nathanrice3 years ago

I agree that something needs to be done with this. wp_title is old, ugly, and rather inadequate (as proved by the mess of code used to generate the <title> tag in twentyten/twentyeleven.

However, injecting the <title></title> on wp_head seems like the wrong solution.

I would rather see a new function altogether. Something like wp_doctitle(). To me, wp_title() always seemed too generic.

The new function could be available to theme developers. It could use the (vastly superior, IMO) $args array, instead of separate parameters, set defaults, output <title></title> tags, do the logic for outputting the title based on what is being browsed, etc. And of course, be fully filterable (early and late).

Last edited 3 years ago by nathanrice (previous) (diff)

comment:6 in reply to: ↑ 5 joostdevalk3 years ago

Replying to nathanrice:

I'm fine with that too, it'd be a rather small fix to this patch actually, this solution was the first one Nacin and I came up with when discussing in chat.

comment:7 DH-Shredder3 years ago

This is less crucial, but you may want to take a look at line 207 in wp-includes/default-filters.php -- looks like the whitespace/indenting is a bit mismatched to the previous/following lines.

comment:8 nacin3 years ago

I have been working with joost on this patch and I really, really like the approach.

I think injecting <title> is the perfect solution here. The <head> is one of the messiest aspects of WordPress templating and moving toward theme support and wp_head hooks is a really elegant solution.

The null and false return values that the patch supports is really, really clever, though I'd suggest that it should be more explicit showing false !==. That said, I'm not sure we'd even want to support a plugin from bypassing a <title> tag removal with false. Just my take.

comment:9 follow-up: ozh3 years ago

As a not-theme designer, I think removing the <title> entirely from hardcoded structure is a bit too extreme. Clueless people forking twentyeleven or using it as an example are bound to forget it.

I don't see how having <title><?php one_simple_filtered_function(); ?></title> is less performant.

comment:10 Jayjdk3 years ago

  • Cc kontakt@… added

comment:11 markoheijnen3 years ago

  • Cc marko@… added

The thing what I miss is backward compatibility. Since all the themes still will use wp_title() it now will send twice the <title></title> tag.

comment:12 follow-up: jane3 years ago

Personally I wish the user could set the format of the title tag in Settings, just like permalinks. Maybe that's just me; I dislike that it is controlled by the theme since it seems like more of a global/browser thing than a design thing.

comment:13 in reply to: ↑ 12 ; follow-up: joostdevalk3 years ago

Replying to markoheijnen:

The thing what I miss is backward compatibility. Since all the themes still will use wp_title() it now will send twice the <title></title> tag.

Not true, you have to declare theme support for this in your theme for it to work first. 100% backwards compatible, that's the main reason for choosing this solution.

Replying to jane:

Personally I wish the user could set the format of the title tag in Settings, just like permalinks. Maybe that's just me; I dislike that it is controlled by the theme since it seems like more of a global/browser thing than a design thing.

I agree Jane, this is perfect groundwork for that next step though.

comment:14 in reply to: ↑ 9 joostdevalk3 years ago

Replying to ozh:

As a not-theme designer, I think removing the <title> entirely from hardcoded structure is a bit too extreme. Clueless people forking twentyeleven or using it as an example are bound to forget it.

I don't see how having <title><?php one_simple_filtered_function(); ?></title> is less performant.

The issue I have with that is not about performance, it's the fact that theme designers think they have something to do with the page title when they don't: it's content.

comment:15 in reply to: ↑ 13 jkudish3 years ago

Replying to joostdevalk:

Replying to jane:

Personally I wish the user could set the format of the title tag in Settings, just like permalinks. Maybe that's just me; I dislike that it is controlled by the theme since it seems like more of a global/browser thing than a design thing.

I agree Jane, this is perfect groundwork for that next step though.

+1 to this!

comment:16 scribu3 years ago

I agree with Joost. <title><?php one_simple_filtered_function(); ?></title> wouldn't solve anything.

People would just start adding stuff before/after it again, since it's the most obvious way to do it.

comment:17 markoheijnen3 years ago

Ah you are right about that.

Would love to see how Jane proposed it. That it gives you some default way to create the title or you can create custom way of creating the title.

comment:18 joostdevalk3 years ago

Let me make it clear why the add_theme_support is there in the first place: that's backwards compatibility only. If we didn't do it that way loads of sites using old themes would end up with two titles.

comment:19 ldebrouwer3 years ago

  • Cc info@… added

I have nothing to add to the above except +1

comment:20 follow-up: ldebrouwer3 years ago

Maybe you should add an option $echo to the function _wp_render_title_tag() that defaults to true. Setting it to false would allow devs to call the function and to let it return the value without the title tags. Obviously the filter 'wp_title_tag_array' allows for further manipulation of the title but maybe some devs would like to be able to use the page title elsewhere on the page as well ( without having to mimic the base functionality ).

I know that maybe the function name doesn't make too much sense anymore in that case but if we were to seperate the actual 'rendering' from the 'wrapping' in title tags that issue would be solved as well.

comment:21 in reply to: ↑ 20 ; follow-up: joostdevalk3 years ago

Replying to ldebrouwer:

No. One of the reasons wp_title can't be patched now is because it's used in plugins for other (wrong) uses. If we prevent that from happening stuff can't break because people use things wrong. That's why, in fact, I tend to agree with nacin that we probably shouldn't even allow the removal of the title altogether...

comment:22 in reply to: ↑ 21 ldebrouwer3 years ago

Replying to joostdevalk:

Ah, right. Good and very valid point.

comment:23 nacin3 years ago

The idea is that _wp_render_title_tag() is an internal function to WP only. If anything, I'd be willing to include a doing_action() call in there just so it needs to be called on wp_head and can't be abused. So -1 to an echo parameter.

We should also force the add_theme_support to be done befoe or on init, to prevent it from being added in header.php or template_redirect to ensure it is accessible from the backend for future compatibility.

comment:24 navjotjsingh3 years ago

  • Cc navjotjsingh@… added

comment:25 greenshady3 years ago

+1 to this idea.

I tend to lean toward using a function within the theme between <title> tags. Using add_theme_support() and having WP automatically put the title in there is great for backwards compatibility until you look at child themes.

If a user overwrote header.php within their child theme but their parent theme updated to use the new functionality, the user would have two <title> tags. If we just create a replacement function for wp_title(), this won't be a problem. The user will still use old functionality if they overwrote header.php in their child theme, but at least they'd only have a single <title> tag.

comment:26 follow-up: scribu3 years ago

So what? The second title tag, from the parent theme, will simply be ignored by the browser.

comment:27 in reply to: ↑ 26 greenshady3 years ago

Replying to scribu:

So what? The second title tag, from the parent theme, will simply be ignored by the browser.

So, some of us care about these type of things and don't want a bazillion questions from theme users. That's what.

comment:28 follow-up: scribu3 years ago

Again, if there's no perceivable change (besides not passing the W3C validator), what's the problem, exactly?

comment:29 scribu3 years ago

Also, we could do a check to handle the edge case you mentioned. Nevermind, that wouldn't work.

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

comment:30 johnbillion3 years ago

  • Cc johnbillion@… added

comment:31 in reply to: ↑ 28 ; follow-up: greenshady3 years ago

Replying to scribu:

Again, if there's no perceivable change (besides not passing the W3C validator), what's the problem, exactly?

The problem has already been described. You already understand what the problem is and don't need further explanation. Either you accept it as a legitimate issue or you don't.

I've merely provided this as constructive feedback on this ticket. Feel free to ignore it or use it.

comment:32 in reply to: ↑ 31 mikeschinkel3 years ago

Replying to greenshady:

Either you accept it as a legitimate issue or you don't.

I agree that it is a legitimate issue; generating two <title> tags is not a good practice.

comment:33 follow-up: mikeschinkel3 years ago

Replying to joostdevalk:

That's why, in fact, I tend to agree with nacin that we probably shouldn't even allow the removal of the title altogether...

There's a lot of code in your patch, and while I agree with the need to at least call 'wp_title' I'd like to see a bypass of the rest of the code for those pages that don't need all of your new code to run.

Maybe pass the results returned by the 'pre_wp_title_tag' hook through the 'wp_title_tag' hook instead of just echoing the results and instead of not having a 'pre_wp_title_tag' hook.

comment:34 in reply to: ↑ 33 joostdevalk3 years ago

Replying to mikeschinkel:

Replying to joostdevalk:

That's why, in fact, I tend to agree with nacin that we probably shouldn't even allow the removal of the title altogether...

There's a lot of code in your patch, and while I agree with the need to at least call 'wp_title' .

We're not going to use wp_title or any of its filters. The reason for that is there have been several attempts at doing that and they all break because of how wp_title is used in plugins. A patch to do that by Nacin a while back actually had to be reverted because of it. So you can rule that one out.

I do understand what greenshady is saying, we'll have to give that another thought. If we opt for a template tag I would opt for one that outputs the <title> tag, so the only way of changing the title is still by applying filters to the content and giving plugins access to the entirety of the title tag content as well as allowing us to change title structures from the backend as Jane suggested.

joostdevalk3 years ago

Alternate version with new template tag

comment:35 joostdevalk3 years ago

As you can see I've also coded out an alternate version, which creates a new template tag and indeed uses the standard $args way of adding options. This might be easier to handle... I'm fine with both versions myself.

Last edited 3 years ago by joostdevalk (previous) (diff)

comment:36 scribu3 years ago

wp_title_tag() looks like the best approach.

Easier to switch to and avoids the inherent problems with wp_title().

The only drawback is that you can't automatically detect wether a theme is using wp_title() or wp_title_tag(). We could add a theme support flag for that later, though.

nacin3 years ago

comment:37 nacin3 years ago

wp_title_tag() does indeed solve one problem by including <title> tags in its output.

Unfortunately, it's inherently less flexible, so it's not really going to convince anyone to use it. It also requires a function call, so it's not backwards compatible out of the box. And, since it doesn't require support registrations, it's not forwards compatible either, with stuff we may (and want to) do in the admin.

When talking with Joost I proposed a way to handle the issues raised here very elegantly. Essentially, we could prevent our new title tag from being rendered if wp_title() has already been called. At the time, we dismissed it as silly for anyone to do this, as they'd instantly see the mistake. However, greenshady brings up an excellent point about child themes. So let's move forward with the idea.

The attached patch:

  • Requires that add_theme_support('title-tag') is fired on the after_setup_theme or init hooks, or in the body of functions.php. By doing this, it requires that support can be discerned in the admin for a possible future feature. This is enforced using doing_action(), which was proposed in #14994. (This patch is designed to work without applying that patch, however.) I really like this, and I think that add_theme_support() should have this kind of enforcement for all kinds of theme support.
  • Prevents a title tag from being rendered if wp_title() has already been called, by checking to see if the wp_title hook has already been fired.
  • Requires that _wp_render_title_tag() is only called internally on the wp_head hook. This enforces it as an internal hook callback rather than the potential it gets used as a title tag.
  • Adds a new return value for add_theme_support() of WP_Error.
  • Removes the false return from the pre_wp_title_tag hook. The only way to bail is to provide a title to be printed. Continues to treat pre_wp_title_tag as a short-circuit filter that bails immediately, in line with many other pre hooks in WordPress.

Remember, requires #14994 for most of this.

joostdevalk3 years ago

Update on Nacin's patch with better handling of date archive titles

comment:38 joostdevalk3 years ago

I like that last approach, just updated the patch a bit to handle titles for date archives better as the original code for that in wp_title was goofy.

comment:39 husobj3 years ago

  • Cc ben@… added

comment:40 GaryJ3 years ago

  • Cc gary@… added

comment:41 ramoonus3 years ago

  • Cc ramoonus@… added

comment:42 follow-up: F J Kaiser3 years ago

  • Cc 24-7@… added

I really don't understand why this "patch" is needed. I can't imagine a real reason for not using the filter that already comes with wp_title();. Pushing stuff like this into core is like gasoline for the discussions about "WordPress is bloat ware". Imho the structure inside the function is good, but general-template.php is the wrong place. This should be part of Twenty Eleven to teach people how to do it right. I think this will bring up much more confusion than help.

Anyway, if this really makes it's way into core, here are the things I want to mention to improve the internal structure of _wp_render_title_tag();:

  • Use an associative array for $title as it's easier to understand how to overwrite parts for non-tech savy users (a.k.a. the majority).
  • Using the wrong hooks is imo not a real Error. Switch to _doing_it_wrong();. Using the wrong hook happens to the best devs all the time and using that function is much more polite (From the doc block of _doing_it_wrong();: Marks something as beeing incorrectly called).
  • I'm not a big fan of different coding styles - if you want to call it like this - inside a single function. From title-tag-3.diff: $title = implode( " $sep ", $title ); vs. echo '<title>' . $pre . "<title>\n"; doesn't help much to make core more readable and easier to understand.
  • The same goes for if ( null !== $pre = apply_filters( 'pre_wp_title_tag', null ) ) {. Having the filter attached to $pre one line earlier makes it much easier to read.
  • I'd rename the pre_wp_title_tag filter to wp_title_tag_walker. Imo it's nothing else.
  • About input $args and $defaults: We got the wonderful function named wp_parse_args(); in core - which is imo used not often enough. Why not use this and make an easy to read/understand array of default values at the beginning and then parse it with the data received via add_theme_support();?

Just my 2 cents (I still think this function shouldn't be added just because plugins/themes are missusing the wp_title(); filter.

comment:43 in reply to: ↑ 42 ; follow-up: ramoonus3 years ago

Replying to F J Kaiser:

Just my 2 cents (I still think this function shouldn't be added just because plugins/themes are missusing the wp_title(); filter.

if people mis-use it .. they have a reason to do so

comment:44 in reply to: ↑ 43 ; follow-up: F J Kaiser3 years ago

Replying to ramoonus:

if people mis-use it .. they have a reason to do so

The most wide spread reason to do so is "not knowing it better".

comment:45 in reply to: ↑ 44 ; follow-up: joostdevalk3 years ago

Replying to F J Kaiser:

Replying to ramoonus:

if people mis-use it .. they have a reason to do so

The most wide spread reason to do so is "not knowing it better".

The issue is, we can't from one release to another suddenly change the way we do things. Twenty Eleven is as it is right now, we'll change that if this patch goes in, but hundreds of people will have copied it and we'll need to make sure it stays working without ANY work on their side. We do however also want to make it better for people who have a need for that, hence, this patch.

Last edited 3 years ago by joostdevalk (previous) (diff)

comment:46 DrewAPicture3 years ago

  • Cc xoodrew@… added

comment:47 in reply to: ↑ 45 F J Kaiser3 years ago

Replying to joostdevalk:

The issue is, we can't from one release to another suddenly change the way we do things.

Haven't we already had twentyten_filter_wp_title();? Correct me if I'm wrong.

Leaving this aside: What will then happen when we got Twenty Twelve? Will we then remove this "feature" from core again?

As you're already brought add_theme_support(); in your patch, why not add wp_render_title_tag(); into the functions.php file of Twenty Eleven encapsuled into something like if ( current_theme_supports( 'title_tag', array( $args ) ) ) { add_filter( ...etc... ); } so child themes could use it adding a single call to theme support to gain the advantage. This wouldn't break anything, leaves core unbloated & we could finally move a better title tag into Twenty Tweleve that is activated by default.

comment:48 l3rady3 years ago

  • Cc l3rady added

comment:49 F J Kaiser3 years ago

Possibly related: 17877 & 12370

comment:50 aaroncampbell3 years ago

  • Cc aaroncampbell added

comment:51 aaroncampbell3 years ago

I think that title-tag-3.diff is missing the default-filters.php changes. I think you still need to attach _wp_render_title_tag() to wp_head so it's called somehow:

add_action( 'wp_head', '_wp_render_title_tag', 1 );

comment:52 azizur3 years ago

  • Cc azizur added

comment:53 sirzooro3 years ago

  • Cc sirzooro added

comment:54 follow-up: jamalorg3 years ago

  • Cc jmlworld@… added

I'm not sure why we'd add another function into the already bloated core when wp_title() can exactly do what we need if we use it the correct way. I see the whole purpose of introducing this new function is to hard-code <title></title> tag into the WordPress core, which defeats the "separation of design & content" rule.

Jane's suggestion of introducing an option to set the format of the <title> tag in Settings would stop people abusing the wp_title() tag. The lack of standard option to modify the structure of the title tag was the first motive of developers abusing the tag.

Teaching people how to add template tags the correct way would be a better idea. Updating the codex and removing themes and plugins abusing the system would also encourage theme/plugin developers to correct their mistakes.

<title> tag is not content, it's design. The content inside it is the content and adding <title><?php title_tag_function(); ?></title> in the theme's header.php is the correct practice, in my opinion.

WordPress was intended to be simple and flexible, and hardcoding things in the wp_head() will result developers creating their own correct_wp_head() because they have an excuse.

comment:55 in reply to: ↑ 54 ; follow-up: aaroncampbell3 years ago

Replying to jamalorg:

The short answer is: backwards compatibility.

Basically if we change wp_title to do the things that themes are already doing OUTSIDE wp_title, then we'll break all those themes. Adding this new functionality will allow us to encourage themes to switch to this and eventually deprecate wp_title.

comment:56 in reply to: ↑ 55 ; follow-up: jamalorg3 years ago

Replying to aaroncampbell:

Basically if we change wp_title to do the things that themes are already doing OUTSIDE wp_title, then we'll break all those themes. Adding this new functionality will allow us to encourage themes to switch to this and eventually deprecate wp_title.

Well. Introducing a new filterable template tag, probably without args, would do no harm. I didn't get the idea of hard-coding <title></title> tags inside the function. This is annoying approach.

Last edited 3 years ago by jamalorg (previous) (diff)

comment:57 in reply to: ↑ 56 joostdevalk3 years ago

Replying to jamalorg:

Well. Introducing a new filterable template tag, probably without args, would do no harm. I didn't get the idea of hard-coding <title></title> tags inside the function. This is annoying approach.

The reason for doing that is that otherwise the simplest thing to do for theme coders would be to add something within the <title></title> and not using the filters, the way they do now. To prevent that, we output the <title> completely outside of the theme and force everyone to use the filters, thus making sure each and every plugin has access to it.

comment:58 follow-up: F J Kaiser3 years ago

I still don't get why this is really needed. Teaching devs is what codex is for and not the core itself. And if you really want to teach people directly through template tags, use _doing_it_wrong(); and extend the wp_title(); function.

This is the first function I see in core that is a "parallel" function. Normally core has wrapper functions for such stuff. Example: function wp_title_tag() { echo '<title>'.wp_title( null, false ).'</title>'; }. If you want to add fancy stuff in there: fine. But actually doubling most part of the original function makes imo no sense.

@joostdevalk: You still didn't answer any of my above concerns or discuss any of the suggestions I made or alternatives I offered. This gives me the feeling that it's just about "boxing" this through.

comment:59 in reply to: ↑ 58 joostdevalk3 years ago

Replying to F J Kaiser:

I still don't get why this is really needed. Teaching devs is what codex is for and not the core itself. And if you really want to teach people directly through template tags, use _doing_it_wrong(); and extend the wp_title(); function.

This is the first function I see in core that is a "parallel" function. Normally core has wrapper functions for such stuff. Example: function wp_title_tag() { echo '<title>'.wp_title( null, false ).'</title>'; }. If you want to add fancy stuff in there: fine. But actually doubling most part of the original function makes imo no sense.

@joostdevalk: You still didn't answer any of my above concerns or discuss any of the suggestions I made or alternatives I offered. This gives me the feeling that it's just about "boxing" this through.

Sorry you feel that way but I think you're not getting our points. The goal is to:

  • have a new, better way of doing titles, without messing without causing issues with all themes that are currently out there. This absolutely, 100%, rules out changing the way wp_title() works. You might think that we should train devs better, but our real concern are users, not devs, who end up with wonky titles on their blogs because their theme is old and they don't know how to change it. So backwards compatibility is paramount.
  • second, learning from our earlier mistakes, we do not want themes to be able to change what's in the title in any other way than plugins can, so we need to make the entire contents of the title tag filterable through 1 filter. The only way of making 100% sure of that is outputting the <title> tags through the code. We can't do that within wp_title, you'll understand why because of the point above.
  • finally, we will probably, if this fix goes in, end up deprecating wp_title.

Make sense now? Any concerns I left unanswered?

comment:60 follow-up: chipbennett3 years ago

  • Cc chip@… added

I'm clearly missing something. I don't see any need for a new function at all. The wp_title() function and wp_title filter are fully functional. If the problem is developer education, then the solution is not to introduce new code into core, but rather to educate developers.

If there is to be a best-practice implementation of wp_title()/wp_title, then let's revise the Theme Review Guidelines, and enforce that implementation for repository-hosted Themes. It would be a simple matter to require that Themes not modify wp_title() directly in the template, but only through the wp_title filter.

But what is currently proposed appears to me to be nothing more than 200 lines of code to accomplish something that can be done without adding a single line of code.

As for the assertion that the doctitle content is content rather than presentation: I say that it's just the opposite. The doctitle is presentation, rather than generation, of content. Thus, it logically may be controlled by the Theme - even if that control needs to be standardized, such that the Theme plays nicely with Plugins.

comment:61 in reply to: ↑ 60 johnbillion3 years ago

Replying to chipbennett:

But what is currently proposed appears to me to be nothing more than 200 lines of code to accomplish something that can be done without adding a single line of code.

+1. IMHO this is addressing a problem that doesn't really exist (namely that themes have more control over the <title> than plugins do). If a theme contains nothing more than wp_title('') in the <title> tag then plugins have complete control over the title. Most 'SEO' plugins ask users to ensure this is the case, and so be it.

All this change will accomplish is that SEO plugins will need to ask users to ensure their theme doesn't contain a <title> tag at all, rather than asking them to ensure it only contains wp_title(''). I don't believe that achieves anything.

Last edited 3 years ago by johnbillion (previous) (diff)

comment:62 follow-ups: greenshady3 years ago

The big issue with just keeping wp_title() is how to handle is_front_page(). Currently, wp_title() does not output anything for the front page. This has left it up to theme devs to add in something to display on the front page, which makes it tough for plugins to filter since there's no hook.

Changing the function to output something for the front page would obviously introduce backwards-compatibility issues.

comment:63 in reply to: ↑ 62 chipbennett3 years ago

Replying to greenshady:

The big issue with just keeping wp_title() is how to handle is_front_page(). Currently, wp_title() does not output anything for the front page. This has left it up to theme devs to add in something to display on the front page, which makes it tough for plugins to filter since there's no hook.

Changing the function to output something for the front page would obviously introduce backwards-compatibility issues.

What's wrong with Themes using the wp_title filter to add content when is_front_page()?

But, regardless: either Themes/Plugins can filter wp_title to add is_front_page() content, or the wp_title() function can be modified to accommodate is_front_page() - neither of which requires this patch.

comment:64 scribu3 years ago

Themes/Plugins can filter wp_title to add is_front_page() content

Yes, themes could do that all along, except they don't.

or wp_title() function can be modified to accommodate is_front_page()

Just going to paste what greenshady said right before your comment:

Changing the function to output something for the front page would obviously introduce backwards-compatibility issues.

comment:65 emiluzelac3 years ago

  • Cc emil@… added

comment:66 in reply to: ↑ 62 emiluzelac3 years ago

Replying to greenshady:

The big issue with just keeping wp_title() is how to handle is_front_page(). Currently, wp_title() does not output anything for the front page. This has left it up to theme devs to add in something to display on the front page, which makes it tough for plugins to filter since there's no hook.

Changing the function to output something for the front page would obviously introduce backwards-compatibility issues.

Please explain this for me if you could. Never mind here.

Thanks!

Last edited 3 years ago by emiluzelac (previous) (diff)

comment:67 scribu3 years ago

Replying to johnbillion:

All this change will accomplish is that SEO plugins will need to ask users to ensure their theme doesn't contain a <title> tag at all, rather than asking them to ensure it only contains wp_title(''). I don't believe that achieves anything.

Actually, you're right; a theme could signal that it uses wp_title() correctly with add_theme_supports( 'enhanced_wp_title' ), which could then be leveraged by SEO plugins and by Core to add some output for is_front_page() etc.

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

comment:68 nacin3 years ago

Actually, you're right; a theme could signal that it uses wp_title() correctly with add_theme_supports()

And at that point, it'd be easier to remove all markup from their purview. Then they need to do things in one location, rather than two. Simplifies everything and makes it difficult to screw up.

comment:69 scribu3 years ago

Agreed.

comment:70 chipbennett3 years ago

Replying to scribu:

Themes/Plugins can filter wp_title to add is_front_page() content

Yes, themes could do that all along, except they don't.

So, is it really preferable to introduce 200 lines of code, a new template tag, and a new add_theme_support() call, instead of simply educating Theme developers on the best practice for modifying doctitle content?

How is it going to be any easier to educate Theme developers to use a new template tag (plus add a new add_theme_support() call), instead of just educating Theme developers to filter wp_title instead of passing a string directly to wp_title()?

Personally, as a member of the team that will largely be tasked with the education/enforcement of whatever implementation method is ultimately chosen, I think getting Theme developers to use existing code is going to be much easier than trying to get them to use a new template tag.

The past of least resistance (and fastest adoption) is going to be to say, "move your wp_title()-filtering code out of header.php, wrap it in a function in functions.php, and hook it into add_filter( 'wp_title', 'themename_filter_wp_title' )".

comment:71 scribu3 years ago

There won't be any new template tag. There will just be an add_theme_supports() call.

See nacin's comment: http://core.trac.wordpress.org/ticket/18548#comment:68

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

comment:72 follow-up: greenshady3 years ago

Replying to scribu:

Actually, you're right; a theme could signal that it uses wp_title() correctly with add_theme_supports( 'enhanced_wp_title' ), which could then be leveraged by SEO plugins and by Core to add some output for is_front_page() etc.

I like this idea. A lot.

It greatly simplifies everything and keeps us from having extra code added.

comment:73 follow-up: nacin3 years ago

So, is it really preferable to introduce 200 lines of code, a new template tag, and a new add_theme_support() call, instead of simply educating Theme developers on the best practice for modifying doctitle content?

Yes. This isn't a new template tag.

The 200 lines of code are copy-pasted from the current wp_title(), and improved for context and performance. In many cases these are backwards incompatible changes, mostly outlined in previous comments.

wp_title() will be deprecated in a future release, probably when core supports a UI for title tag manipulation. (See comments from jane above.)

The past of least resistance (and fastest adoption) is going to be to say, "move your wp_title()-filtering code out of header.php, wrap it in a function in functions.php, and hook it into add_filter( 'wp_title', 'themename_filter_wp_title' )".

I disagree on both counts. This path is more work, without a doubt. Some of them might not even know what a filter is or how it works.

The new instructions would be: No more template tag, no more wp_title(), no more messy code in between your <title> tags. Just use add_theme_support('title-tag'); and you're done. It's pretty much idiot proof, and that's the idea.

comment:74 follow-up: nacin3 years ago

I would be willing to punt this to 3.4 and spearhead a UI for title tag manipulation. Then the user benefits will be obvious for developers.

comment:75 follow-up: jane3 years ago

Past freeze. Punt implies it was in 3.3, though, but it's still in awaiting review. Agree to 3.4 target.

comment:76 in reply to: ↑ 75 nacin3 years ago

Replying to jane:

Past freeze. Punt implies it was in 3.3, though, but it's still in awaiting review. Agree to 3.4 target.

Indeed. By punt I meant mark.

I still want to continue the discussion here uninterrupted on the cost-benefit analysis.

comment:77 in reply to: ↑ 74 emiluzelac3 years ago

Replying to nacin:

I would be willing to punt this to 3.4 and spearhead a UI for title tag manipulation. Then the user benefits will be obvious for developers.

Add UI for meta description as well and we can wrap this up once and for all. If someone wants to use plugin they're more than welcome :)

comment:78 follow-up: chipbennett3 years ago

Replying to nacin:

The past of least resistance (and fastest adoption) is going to be to say, "move your wp_title()-filtering code out of header.php, wrap it in a function in functions.php, and hook it into add_filter( 'wp_title', 'themename_filter_wp_title' )".

I disagree on both counts. This path is more work, without a doubt. Some of them might not even know what a filter is or how it works.

Most are already aware of filters at this point. The rest would benefit greatly from learning what a filter is and how to use it. All are capable of learning.

The new instructions would be: No more template tag, no more wp_title(), no more messy code in between your <title> tags. Just use add_theme_support('title-tag'); and you're done. It's pretty much idiot proof, and that's the idea.

By all means, correct me if my inference here is incorrect, but IMHO this sounds like an effort to discourage - if not prevent (as I suspect Plugin developers would prefer) - Theme developers from modifying the doctitle content.

For Theme developers that currently modify the output of wp_title(), I think I can safely assume that many would still want to modify the doctitle content, even using this new method. So, to say, "No more template tag, no more wp_title(), no more messy code in between your <title> tags. Just use add_theme_support('title-tag'); and you're done" won't be sufficient, because they're left without instructions for modifying the doctitle content.

And even when wp_title() is deprecated, I still don't see the benefit of introducing a separate filter to use. If Theme developers are using the wp_title filter properly by the time wp_title() is deprecated, then that filter would (should) remain sufficient for whatever the new implementation is.

comment:79 in reply to: ↑ 78 ; follow-up: nacin3 years ago

Replying to chipbennett:

By all means, correct me if my inference here is incorrect, but IMHO this sounds like an effort to discourage - if not prevent (as I suspect Plugin developers would prefer) - Theme developers from modifying the doctitle content.

Correct.

They would be able to pass defaults through the add_theme_support() call, and I imagine these default settings would be akin to what power they're normally given in wp_title(). Additionally, there would be filters in this new callback, though I'd hesitate to suggest a theme should use it.

Point is, themes shouldn't be dealing with the content of a title tag. It's exactly that: content. Not presentation.

The biggest problem right now is a theme can optionally take absolute control over what appears in the title by avoiding wp_title() all together. We'd rather force our own <title> tag to ensure that a user or plugin can equally make modifications. It's not that a theme would lose all power, it's that they would be on equal footing. It's the same idea as wp_title('') but wp_title() is crap, our own default themes even want something better, we can't change it without breaking old themes, and we will need the add_theme_support() registration in order to show a user interface in the admin.

comment:80 in reply to: ↑ 73 cais3 years ago

Replying to nacin:

The new instructions would be: No more template tag, no more wp_title(), no more messy code in between your <title> tags. Just use add_theme_support('title-tag'); and you're done. It's pretty much idiot proof, and that's the idea.

If the intent is to really make it that simple then I am all for it ... making things easier for the end-user, AFAIK, has always been the ultimate goal.

Although this may not directly affect the end-user at this time, or maybe even for a few versions, the end result will be easier modification of the output by plugins and themes which would serve at a minimum as an indirect benefit by default.

comment:81 pross3 years ago

  • Cc pross@… added

comment:82 in reply to: ↑ 79 chipbennett3 years ago

Replying to nacin:

Replying to chipbennett:

By all means, correct me if my inference here is incorrect, but IMHO this sounds like an effort to discourage - if not prevent (as I suspect Plugin developers would prefer) - Theme developers from modifying the doctitle content.

Correct.

They would be able to pass defaults through the add_theme_support() call, and I imagine these default settings would be akin to what power they're normally given in wp_title().

It would be instructive to see an example of this written up in code-form; I ran through the ticket, patches, and comments so quickly that I'm not exactly sure what the current state of everything is.

Additionally, there would be filters in this new callback, though I'd hesitate to suggest a theme should use it.

Point is, themes shouldn't be dealing with the content of a title tag. It's exactly that: content. Not presentation.

I disagree; an argument could easily be made that the doctitle content is simply presentation. It is not new/unique content; rather, it's simply presentation of already generated/defined content.

I think the best solution is for this presentation to be defined in core, both through more robust doctitle markup in core, and through a UX for user configuration. That way, neither Theme nor Plugin needs to modify the doctitle content.

So, I understand where you're going with the add_theme_support(). Though, why not just make it assumed? There was certainly no add_theme_support() added for the Admin Bar, which required wp_footer() to be present.

(I guess what I'm saying is that I'd like to see better-defined, more-consistently defined "WordPress standard" practices, implemented more consistently. Too many such features are handled differently from each other.)

The biggest problem right now is a theme can optionally take absolute control over what appears in the title by avoiding wp_title() all together. We'd rather force our own <title> tag to ensure that a user or plugin can equally make modifications.

In the short-term, that is equally (and more easily) achievable by changing the Theme Review Guidelines with respect to wp_title(), to require that if modified, it must be modified via filter.

It's not that a theme would lose all power, it's that they would be on equal footing.

I'm with you 100% on this.

It's the same idea as wp_title('') but wp_title() is crap, our own default themes even want something better, we can't change it without breaking old themes, and we will need the add_theme_support() registration in order to show a user interface in the admin.

I think you could convince me, if the UX and more-robust core doctitle markup were implemented simultaneously (along with wp_title() deprecation), so that Theme developers both only needed to make one change to Theme code, and would benefit from a significantly reduced need to filter the doctitle content in the first place.

comment:83 in reply to: ↑ 72 nofearinc3 years ago

Replying to greenshady:

Replying to scribu:

Actually, you're right; a theme could signal that it uses wp_title() correctly with add_theme_supports( 'enhanced_wp_title' ), which could then be leveraged by SEO plugins and by Core to add some output for is_front_page() etc.

I like this idea. A lot.

It greatly simplifies everything and keeps us from having extra code added.

Looks like the easiest and most elegant approach to me. No extra tags or complications, just introducing another hookable theme support.

comment:84 scribu3 years ago

That's not quite true. Keeping wp_title() around will result in some gnarly code, both in Core and in plugins, due to the fact that wp_title() itself sucks and is hard to extend.

comment:85 hd-J3 years ago

  • Cc jeremy@… added

comment:86 sabreuse3 years ago

  • Cc sabreuse@… added

comment:87 chrisbliss182 years ago

  • Cc gaarai@… added

First, let me say that I do like to talk a lot. I apologize for that. I always want to put reason behind code. If you don't care to understand my approach to how I created my patch, just try out the patch and go from there.

I decided to create a new patch that is current with trunk while also implementing a new approach that I think solves some problems. The patch is merely a suggestion. I think the names and some of the methodology definitely needs some tweaking.

After thinking about the problem of titles for a while, I've come to the conclusion that there are four interested parties when it comes to title modification:

  1. Title Setters - This is code that needs to set the original title of the content. Good examples are BuddyPress, Pods, and WP e-Commerce. These are plugins that create new content types and need to filter the title in order to set the actual title of the content.
  2. Title Modifiers - This is code that needs to augment or change the title. I only know of a couple examples off the top of my head, but I'm sure there would be more if I dug around. The first example is NextGEN Gallery which adds new title sections such as Gallery, Slideshow, etc as appropriate. The next one is Anonymizer which uses the wp_title filter to remove author's names.
  3. SEO Plugins - These plugins set the final title that is displayed. Sometimes the title needs to be completely replaced and sometimes it needs to modify the existing title in order to set up the final title format.
  4. Themes - Themes are stuck in an odd spot. If they simply call wp_title, the titles look ugly. If they then use the wp_title filter, plugin authors quickly get frustrated that themers are making their job hard. It's a no-win situation.

After looking through the ways different parties are using the current wp_title filter, I see some key problems with the current system:

  • Relying on a single filter for all needs is far too simple and leads to issues. This can be seen by the fact that most every wp_title filter that I've seen uses a priority a 10. The ones that don't use the default priority seem to have no pattern to their choices. I've seen 0, 1, 9, 11, 90, 99, and 100 used. It is clear that some want to be early and some want to be late with only a few realizing that they are not the only filter in town.
  • Many developers completely ignore the sep or seplocation variables. Some seem to do this because they feel them to be unnecessary or unwanted. This makes for quite a mess when more than one filter is involved.
  • There is no way to know when the title is "done". If a filter already finished the title by adding the site name or some other modification, a later filter has no way of knowing this. A number of plugin authors have suggested writing compatibility checks that look for their plugin in order to take a back seat when the plugin is present. This sounds good, but a quick search on the plugin repo shows 972 "seo" plugins. Of course, only some of these are in the wp_title filter game, but I'd rather not have to go through the latest version of every one of those plugins on any schedule in order to ensure proper compatibility. This clearly is not the solution.
  • Since the title generated by the wp_title function isn't exactly the same as just the content title (as it may or may not have a separator on it), it cannot be reliably used for title modification when more complex changes need to be made. This results in a large amount of duplication as plugins reimplement the entire stack of if statements to determine the title of the specific page being viewed.

From all of this, I decided that the new title system needed to have some specific approaches:

  1. A theme should be able to simple add theme support for a title-specific feature and let WordPress take it from there. However, arguments can be passed to the add_theme_support function call in order to modify the default values that WordPress uses. This is already covered in the patch supplied by Joost and will be the same approach I take in my patch.
  2. WordPress is fully responsible for assembling the final title. This will prevent issues with titles being a hodgepodge of multiple attempts to assemble a full title. It will also remove any need for most people working with titles to care anything about the separator or the directionality of the title.
  3. Since the parties above can be divided into those that want to set the content title and those that want to set the final title, there should be two processes/steps for generating the title: one for the content title and one for the final title.
  4. The title should stay as an array until it is ready to be assembled.
  5. A sort of templating system should be used to ensure maximum flexibility while still allowing WordPress to reliably assemble the final title.

The power of my approach comes from the format of the arguments added by the theme support system. The defaults as found in my patch should give an idea.

$defaults = array(
    'sep'                     => ' - ',
    'direction'               => 'auto', // auto, rtl, ltr
    // %%TITLE%% is a special variable but can still be overridden if desired.
    'title_format'            => array( '%%TITLE%%', '%%PAGING%%', '%%BLOGNAME%%' ),
    'title_format-home'       => array( '%%BLOGNAME%%', '%%PAGING%%', '%%DESCRIPTION%%' ),
    'title'                   => '',
    'title-archive'           => __( 'Archive' ),
    /* translators: 1: author name */
    'title-author-archive'    => __( 'Author Archive for %1$s' ),
    /* translators: 1: date description */
    'title-date-archive'      => __( 'Archive for %1$s' ),
    /* translators: 1: post type archive title */
    'title-post-type-archive' => __( 'Archive for %1$s' ),
    /* translators: 1: search phrase */
    'title-search'            => __( 'Search Results for "%1$s"' ),
    /* translators: 1: taxonomy name */
    'title-taxonomy-archive'  => __( 'Archive for %1$s' ),
    'title-404'               => __( 'Page not found' ),
    'variables'               => array(
        /* translators: 1: page number */
        'PAGING'      => __( 'Page %1$d' ),
        'BLOGNAME'    => get_bloginfo( 'name' ),
        'DESCRIPTION' => get_bloginfo( 'description' ),
    ),
);

The sep and direction (new name for seplocation) are a bit different from before.

The sep now has optional spaces. The spaces are only present if you actually supply spaces around the separator. This is because not all languages use spaces. Specifically, the Chinese, Japanese, and Thai written languages and the original Korean written language don't have any spaces. If you do some searches on a search engine using one of these languages (Chinese, Japanese, Thai), you will see plenty of titles that have separators but don't have any spaces. Thus, it makes not sense to force spaces. Titles have spaces around the separator if they are desired.

It seems that many people thought that seplocation is unnecessary. I assume that they base this off of the SEO principal that if you add the site's title to the title tag, it needs to go at the right. However, this is true just because English is a left-to-right language. There are a number of languages that are right-to-left: Arabic, Hebrew, N'Ko, Syriac, Thaana, and other less well-known languages. If you search on a search engine using one of these languages (Arabic, Arabic, Hebrew), you will notice that the directionality of many of the titles are flipped. I have to imagine that the SEO principal of title directionality should flip for the right-to-left languages. Even if this isn't the case, given that it makes sense for people searching to see the content title first, it should definitely be an option that doesn't require significant effort (such as implementing a custom title solution) to change.

The direction entry defaults to 'auto'. When this is set to auto, the code uses is_rtl to determine the language directionality and sets direction of the title accordingly. The direction can also be manually set by using 'ltr' or 'rtl'.

The title_format entries are used to supply the format used by the final title (the use of the underscore helps to prevent name collisions with the title}} entries). The {{{title entries are for the content title (this could be changed to content_title, but I left it as title for simplicity). The variables entries are used to provide drop in replacements in any of the template_format entries. This allows someone to modify a template without having to recreate additional code, such as the paging code.

Notice the title_format-home entry. This sets a format to be used for just the home view. The same system can be used for the title entries as the title-post-type-archive entry shows. The code generates a string or array of "views" that the current patch represents. This basically creates a template hierarchy system that allows for great specificity with title and title_format entries.

title_format entries can make use of the variables entries while the title entries can optionally use a sprintf variable which represents the generated content title (if the active title entry for a page doesn't have this variable and the generated content title isn't empty, the generated content title is used as-is and the title entry is ignored).

The process flow works like this:

  1. The theme calls add_theme_support('title-tag') and optionally passes in an argument array.
  2. The add_theme_support function merges in the passed in arguments if the title-tag support is added more than once.
  3. The _custom_theme_features_just_in_time function runs. If the theme has title-tag support, it runs the jit add_theme_support call and adds a wp_head action (priority of 0 in order to add the title early in the action stack) to call the title rendering function.
  4. The _wp_render_title_tag function runs on the wp_head action.
  5. Run the pre_wp_title_tag filter. If a title is returned, print it in title tags and exit the function. This allows SEO plugins and other similar code to sidestep the entire title generating process and supply their own title.
  6. Pull in the arugments from the theme supports system and filter them with the title_tag_options_filter filter. Yes, code can use add_theme_support calls to modify the arguments, but this has a number of problems. The primary issue is that only a theme should call this as other code should be checking first to see if the title-tag is supported by the theme, and since there aren't any standards on when add_theme_support should be called by a theme, it would quickly present problems of some plugins running the check before the theme has a chance to run the function. So, a filter is the logical choice that allows maximum flexibility without introducing implementation complexity.
  7. Run the title_tag_filter filter. This allows code to supply the content title and would be used by plugins such as BuddyPress, Pods, and WP e-Commerce.
  8. All outside interaction is done at this point. WordPress takes care of everything else.
  9. The typical stack of ifs is run in order to decide what page is being looked at. As before, a relevant content title is generated (some date archives, time archives, the 404 page, and other page possibilities that aren't covered don't receive a content title). However, my patch also creates a $view variable that stores a string or array that represents the view of the current page. For instance, a non-static page home view is 'home' and a category archive is array('category-taxonomy-archive', 'taxonomy-archive', 'archive'). The view is important as it is used to find the appropriate title}} and {{{title_format to use to generate the final title.
  10. Locate the appropriate title and title_format.
  11. If the title from the arguments contains sprintf variable, replace it with the content title, and use this as the new content title.
  12. If the direction is 'rtl', the title and title_format arrays are reversed. Yes, both of them can be arrays. Making the title support an array structure allows for plugins such as NextGEN Gallery to easily augment the title with the addition of a "Gallery" title section. It also allows for building the classic multi-part date archive titles.
  13. Loop through the title_format array and replace any found variables from the arguments. While doing this, remove any now-empty array entries. This prevents from having duplicated separators.
  14. Turn the title_format and title arrays into strings by imploding them using the sep argument.
  15. Replace instances of the %%TITLE%% special variable found in the title_format with the title variable.
  16. Print the title tag and contents.

There is definitely room for improvement. I need to implement some more robust date archive titles as well as creating a time archive section. Some efficiency and naming improvements should also be made.

This patch is primarily to help push the conversation forward in the hopes of having a final solution soon.

For themes to implement the solution from the patch, simply remove the wp_title function call and title tag from the theme and add code such as the following to the functions.php file:

add_theme_support( 'title-tag', array( 'sep' => ' &rarr; ' ) );

For code that supplies new content titles:

function example_supply_title( $title ) {
    // Run conditional to determin if a new title needs to be supplied
    return 'New title';
}
add_action( 'title_tag_filter', 'example_supply_title' );

Notice how the format of the title remains. Only the content title is replaced.

For code that wants to replace all the titles:

function example_replace_all_titles( $title ) { 
    // Code to load desired new title
    return 'New title';
}
add_action( 'pre_wp_title_tag', 'example_replace_all_titles' );

For code that wants to filter the arguments:

function example_modify_title_arguments( $arguments ) {
    // Any necessary conditional code in case the modifications aren't static
    $arguments['sep'] = ' | ';
    $arguments['variables']['EX_CUSTOM'] = 'Custom';
    $arguments['title_format-singular'] = array( '%%TITLE%%', '%%PAGING%%', '%%EX_CUSTOM%%' );
    
    return $arguments;
}
add_filter( 'title_tag_options_filter', 'example_modify_title_arguments' );

</longpost>

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

chrisbliss182 years ago

Updated to modify twentyeleven and twentyten

comment:88 johnbillion2 years ago

Thanks for the thorough explanation of your patch Chris. I really like this approach. The original patch by Yoast didn't make it a lot easier for plugins to avoid stepping on each other's toes. Using an associative array solves this (I use a similar system for breadcrumb components in my theme framework).

The only major problem I can see with the patch is that the pre_wp_title_tag filter is ripe for abuse. By allowing plugins to hook into this filter we actually undo all the other hard work that allows the separate title components to be filtered.

If one single plugin on your site decides to use the pre_wp_title_tag filter then we're back at square one and all our hard work is for nothing. The main title_tag_filter filter hasn't run at this point, so changes to the content title made by another plugin is not going to be taken into account. I'd like to recommend removing the pre_wp_title_tag filter.

comment:89 Sam_a2 years ago

+1 for an alternative to wp_title().

comment:90 BenjaminRMueller21 months ago

  • Cc BenjaminRMueller added

comment:91 kovshenin18 months ago

  • Cc kovshenin added

comment:92 goto1015 months ago

  • Cc dromsey@… added

comment:93 jpswade7 months ago

  • Cc jpswade@… added

comment:94 nacin2 months ago

  • Component changed from Template to Themes
  • Focuses template added
  • Keywords needs-codex removed

I feel like rather than this being something the theme declares, there should be an intuitive (and simplistic) title tag builder in General Settings. Why should the theme be specifying separators and such? That's more content than anything.

Note: See TracTickets for help on using tickets.