[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' => ' &rarr; ' ) );
 ?>
 }}}

 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