WordPress provides a nice little function for displaying the title of the current post: the_title(). This function gets used all over the place: in the site header, at the top of single posts and pages, in the loop, in the footer, etc. It is probably one of the most commonly used functions by theme developers, and sometimes plugin developers, depending on the plugin. What many developers don’t realize, however, is that there is actually a time that this function should not be used for retrieving and showing a post title, and that is in attributes.

I run into snippets like this a lot:

1
<a href="<?php the_permalink(); ?>" title="<?php the_title(); ?>">Permalink to <?php the_title(); ?></a>

In general this is fine and displays perfectly fine most of the time. The problem is simple: when outputting the title of a post in an attribute, you should always use the_title_attribute(). The reason comes down to escaping.

Let’s look at the source for the two functions.

the_title()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Display or retrieve the current post title with optional content.
 *
 * @since 0.71
 *
 * @param string $before Optional. Content to prepend to the title.
 * @param string $after Optional. Content to append to the title.
 * @param bool $echo Optional, default to true.Whether to display or return.
 * @return null|string Null on no title. String if $echo parameter is false.
 */
function the_title($before = '', $after = '', $echo = true) {
        $title = get_the_title();
        if ( strlen($title) == 0 )
                return;
        $title = $before . $title . $after;
        if ( $echo )
                echo $title;
        else
                return $title;
}

This one doesn’t show us what we need, since it just calls get_the_title(), so let’s also look at the source for that function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/**
 * Retrieve post title.
 *
 * If the post is protected and the visitor is not an admin, then "Protected"
 * will be displayed before the post title. If the post is private, then
 * "Private" will be located before the post title.
 *
 * @since 0.71
 *
 * @param mixed $post Optional. Post ID or object.
 * @return string
 */
function get_the_title( $post = 0 ) {
        $post = get_post( $post );
        $title = isset( $post->post_title ) ? $post->post_title : '';
        $id = isset( $post->ID ) ? $post->ID : 0;
        if ( ! is_admin() ) {
                if ( ! empty( $post->post_password ) ) {
                        $protected_title_format = apply_filters( 'protected_title_format', __( 'Protected: %s' ) );
                        $title = sprintf( $protected_title_format, $title );
                } else if ( isset( $post->post_status ) && 'private' == $post->post_status ) {
                        $private_title_format = apply_filters( 'private_title_format', __( 'Private: %s' ) );
                        $title = sprintf( $private_title_format, $title );
                }
        }
        return apply_filters( 'the_title', $title, $id );
}

This function is pretty simple, it retrieves the post object using get_post() and then, after passing it through a filter called the_title, returns $post->post_title.

The important part of this function (to properly illustrate this issue) is the applied filter: apply_filters( ‘the_title’, $title, $id );

This filter can be used by developers to modify the output of the title, perhaps to add extra HTML markup.

the_title_attribute()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * Sanitize the current title when retrieving or displaying.
 *
 * Works like {@link the_title()}, except the parameters can be in a string or
 * an array. See the function for what can be override in the $args parameter.
 *
 * The title before it is displayed will have the tags stripped and {@link
 * esc_attr()} before it is passed to the user or displayed. The default
 * as with {@link the_title()}, is to display the title.
 *
 * @since 2.3.0
 *
 * @param string|array $args Optional. Override the defaults.
 * @return string|null Null on failure or display. String when echo is false.
 */
function the_title_attribute( $args = '' ) {
        $title = get_the_title();
        if ( strlen($title) == 0 )
                return;
        $defaults = array('before' => '', 'after' =>  '', 'echo' => true);
        $r = wp_parse_args($args, $defaults);
        extract( $r, EXTR_SKIP );
        $title = $before . $title . $after;
        $title = esc_attr(strip_tags($title));
        if ( $echo )
                echo $title;
        else
                return $title;
}

This function also uses get_the_title() to retrieve the title of the post, but the final data that is returned is different from the_title(), primarily in that it is escaped. What does this mean? It means that it is safe to use inside of element attributes. It also strips all tags.

Let’s look at an example.

Assume your $post->post_title is this:

<span class="title">This is a title with span tags</span>

When outputted with the_title(), this will remain completely unchanged and will display as:

<span class="title">This is a title with span tags</span>

But when you output this title through the_title_attribute(), you get this:

This is a title with span tags

Notice that the span tags have been removed.

What if your title had quotation marks in it? Such as:

This is a title with "quotation" marks

With the_title(), the title will be outputted as:

This is a title with "quotation" marks

With the_title_attribute(), the title will be outputted as:

This is a title with &quot;quotation&quot; marks

Notice how the quotation marks have been converted to entities?. This is called escaping and it ensures that attributes, such as title=”the title here”, don’t end up getting closed too early.

If we use the_title() inside of an attribute and the title has quotation marks, we will end up with broken markup.

<span title="<?php the_title(); ?>"><?php the_title(); ?></span>

Results in:

<span title="This is a title with "quotation" marks">This is a title with "quotation" marks</span>

Notice that the title attribute gets closed with the first ” around the word quotation. This results in completely broken markup that might look something like this:

Screen Shot 2013-07-11 at 10.23.18 AM

In order to not break the markup, you should always use the_title_attribute() when showing the title of a post inside of an attribute. It’s a very appropriately named function.

<span title="<?php the_title_attribute(); ?>"><?php the_title(); ?></span>

The usage of the_title() in attribute tags has actually caused my huge headaches with Easy Digital Downloads. We use the the_title filter to add Schema.org micro data to products, which is excellent because the data is used by search engines to enhance search result entries with product data (price, rating, etc). The problem is that we get at least one support ticket every week from a user that has broken HTML markup (like that pictured above). The problem is prevalent enough that we are being forced to add an option to disable our schema.org micro data.

If you care about better compatibility with plugins, and simply doing the right thing, you should update any theme or plugin that uses the_title() incorrectly. Note, WordPress core itself has a similar problem as well, so it’s not just themes and plugins.

  1. Norcross

    Agreed on usage (I do it a lot) but one beef is that there is no way to get it outside of the loop. I end up having to use my own function to mimic the_title_attribute in those cases.

  2. Randy

    Ugh, I can’t even think how many times I have done this wrong. My only argument is that I wasn’t thinking I needed to go back across 80+ sites and fix this until I read your article!

    • Pippin

      It’s very easy to do wrong, especially as the problem is only noticeable when you have a plugin or theme that modify the post titles via the the_title filter.

  3. Chuck Reynolds

    yup.. have run into this a bit. it’d be nice to be able to use it outside the loop

    • Pippin

      Thanks for the headsup.

  4. Drew Jaynes

    It’s interesting that you advocate using the_title_attribute() to denote the title attribute of an element that’s outputting the_title(). Isn’t that just a little redundant?

    I only ask because Andrew Nacin recently made a case for removing usage of the_title_attribute() in just such instances in the default themes.

    • Pippin

      Drew, I’m not advocating for or against the usage of title attributes, I’m only advocating for the correct usage of `the_title_attribute()` inside of attributes, title or otherwise. For example, if you have an HTML element that has `data-name=”The title”`, you need to use `the_title_attribute()`, not `the_title()`.

    • Drew Jaynes

      Well of course you’d use the_title_attribute() in those other instances, and kudos for clarifying it for people who weren’t. I’m only half-yanking your chain, anyway.

      By the way, only two levels for threaded comments? Doesn’t leave a lot of room for discussion.

  5. Andrew

    Thanks Pippin, good read. Wish I had seen this earlier

  6. Amirol

    It seems that WP 3.6 will remove the_title_attribute() from anchors. So is that mean we cannot use it anymore?

    • Pippin

      Where do you see that in 3.6?

  7. Jonathan

    Hey Pippin,

    I was trying to read this post in Feedly and it looks like something in the translation from this site to Feedly messed w/ the code blocks, showing all the underlying HTML tags. It looks like a L soup :)

    Great post, thanks for sharing.

    Jonathan

    • Pippin

      Could you show me a screenshot?

  8. Alexis

    Thanks Pippin ! I think I’ll spread the good word, cause It’s been week I’ve been looking for the famous answer to “why is my code broken ?” 😀

    Thanks. EDD is really great, this kind of issue should not make people run away.

  9. Skip

    I bought a premium theme and the author made this exact mistake which is disappointing. Even more so because he only did it in the link code for the main post title. The post thumbnail he uses the_title_attribute so it seems like lazy coding or maybe misunderstanding. Have been trying to resolve an issue it’s causing for a while. Now I know. Thank you!

Your email address will not be published. Required fields are marked *

Error: Please enter a valid email address

Error: Invalid email