[wp-trac] [WordPress Trac] #18548: Add a better option for <title> tags
WordPress Trac
wp-trac at lists.automattic.com
Wed Apr 4 00:39:43 UTC 2012
#18548: Add a better option for <title> tags
------------------------------------------------+--------------------------
Reporter: joostdevalk | Owner: joostdevalk
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting
Component: Template | Review
Severity: normal | Version: 3.3
Keywords: has-patch dev-feedback needs-codex | Resolution:
------------------------------------------------+--------------------------
Changes (by chrisbliss18):
* cc: gaarai@… (added)
Comment:
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
[http://wordpress.org/extend/plugins/buddypress/ BuddyPress],
[http://wordpress.org/extend/plugins/pods/ Pods], and
[http://wordpress.org/extend/plugins/wp-e-commerce/ 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.
1. 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
[http://wordpress.org/extend/plugins/nextgen-gallery/ NextGEN Gallery]
which adds new title sections such as Gallery, Slideshow, etc as
appropriate. The next one is
[http://wordpress.org/extend/plugins/anonymizer/ Anonymizer] which uses
the wp_title filter to remove author's names.
1. 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.
1. 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
[http://wordpress.org/extend/plugins/search.php?q=seo 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.
1. 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.
1. 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.
1. The title should stay as an array until it is ready to be assembled.
1. 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.
{{{
!#php
<?php
$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 ([http://www.google.com.hk Chinese], [http://www.google.co.jp/
Japanese], [http://www.google.co.th/ 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 ([http://www.google.com.eg/ Arabic],
[http://www.google.com.sa/ Arabic], [http://www.google.co.il/ 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.
1. The {{{add_theme_support}}} function merges in the passed in arguments
if the {{{title-tag}}} support is added more than once.
1. 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.
1. The {{{_wp_render_title_tag}}} function runs on the {{{wp_head}}}
action.
1. 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.
1. 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.
1. 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.
1. All outside interaction is done at this point. WordPress takes care of
everything else.
1. 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.
1. Locate the appropriate {{{title}}} and {{{title_format}}}.
1. If the {{{title}}} from the arguments contains {{{sprintf}}} variable,
replace it with the content title, and use this as the new content title.
1. 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.
1. 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.
1. Turn the {{{title_format}}} and {{{title}}} arrays into strings by
imploding them using the {{{sep}}} argument.
1. Replace instances of the {{{%%TITLE%%}}} special variable found in the
{{{title_format}}} with the {{{title}}} variable.
1. 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:
{{{
!#php
<?php
add_theme_support( 'title-tag', array( 'sep' => ' → ' ) );
?>
}}}
For code that supplies new content titles:
{{{
!#php
<?php
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:
{{{
!#php
<?php
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:
{{{
!#php
<?php
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>
--
Ticket URL: <http://core.trac.wordpress.org/ticket/18548#comment:87>
WordPress Trac <http://core.trac.wordpress.org/>
WordPress blogging software
More information about the wp-trac
mailing list