Skip to content

The apostrophe after the tag

Parked in .
Filing burrs off the rough edge of a machined metal part

There is a WordPress bug small enough to hide in a single character.

Get this markup in the editor by writing out the HTML with the “Edit as HTML” inline block tool:

<strong>He</strong>'s here.

You can also type it in the visual editor with the keyboard shortcuts and inline block tools. It will look OK in the editor, with a purely vertical apostrophe that’s not curled one way or the other.

But on the published post the world sees, the apostrophe curls the wrong way — away from the ‘e’ it belongs to and out toward the ‘s’.

You wanted a contraction. The apostrophe belongs to the word ‘he’. Unpatched, WordPress renders it as an opening single quotation mark instead. Here is the before, exactly as a stock install curls it:

He‘s here.

That little curl points the wrong way. It should be &#8217;, the right single quotation mark — the character English uses as a typographic apostrophe in contractions and possessives. Here is the after, the way a corrected wptexturize() renders the very same markup:

He’s here.
Garage workbench with HTML markup and a curled metal apostrophe-shaped shaving beside an out-of-focus laptop.
Generated editorial photo for “The apostrophe after the tag.”

Both lines above are typed straight into the page by hand, so they hold still as a reference no matter what runs after them. The whole bug lives in the gap between them: one word, the same markup, a single character apart.

This is not the block editor inventing punctuation. It is older than that. The culprit is wptexturize(), WordPress’s long-running output filter that turns straight quotes, dashes, ellipses, and a few other plain-text marks into nicer typography on the rendered page.1

Most of the time, that is what people expect from WordPress. You type plain punctuation. WordPress dresses it up. The trouble starts when the word is split by HTML.

Historical Aside: Texturize is WordPress co-founder Matt Mullenweg’s baby. Matt has blogged about how he was inspired by Dean Allen’s obsession with web typography at his Textism blog and in the Textpattern CMS. Matt built Texturize for WordPress so it could have Textpattern-like typographic polish out of the box.

Back when pasting from Word into a web interface was a disaster, Dean created Textile in 2002 and built it into his Textpattern CMS the following year. Textile was a Markdown precursor. At the time, Markdown’s creator, John Gruber had written SmartyPants to cope with curly quotes, em/en-dashes, and ellipses by automatically transforming them into the proper HTML character entities. That’s closer to what Texturize does.

SmartyPants began life as a Movable Type plugin; Alex King’s JS-Quicktags, meanwhile, became an important part of WordPress core. Together, JS-Quicktags and Texturize made it possible to write semantically correct code and typographically (mostly) correct text in a non-clunky way on the web — in WordPress.

The word got cut in half

wptexturize() does not look at rendered text the way a reader does. It works through the HTML string. To avoid changing things inside tags, it splits the string around markup.

So this:

<strong>He</strong>'s here.

starts to look more like this internally:

<strong> | He | </strong> | 's here.

The final piece starts with 's. Since the filter can no longer see the e in He, it treats the straight quote as if it begins a quotation. The visible word says He's. The string pieces say: tag, text, tag, quote at the beginning of a new run.

That is the whole bug: the word context fell through the tag boundary.

Dan wrote about this years ago in Apostrophes and Quotation Marks after stumbling over it in Gutenberg. He opened an issue about it in the Gutenberg repo (Gutenberg #42345), not realizing the block editor is not the culprit.

A closing inline tag followed immediately by a straight apostrophe confuses the old Texturize text filter in WordPress core. There has been an open Trac ticket about it since 2011.

The whole family of failures

It is not only contractions that fall apart. Any straight quote that lands right after a closing inline tag can take the wrong curl — single and double closing quotes, possessives, quoted names, and quotes that bump into a block tag, an ellipsis, or non-English punctuation.

DescriptionSource ASCII and HTML TexturizedShould be
Possessive after a tag<strong>He</strong>'sHe‘sHe’s
Contraction split by a tagrock</strong>'n'rollrock‘n’rollrock’n’roll
Closing single quote after a link'<a>quoted</a>'.‘quoted‘.‘quoted’.
Closing double quote after a link"<a>quoted</a>".“quoted“.“quoted”.
Possessive after a quoted name<em>"John"</em>'s“John”‘s“John”’s
Closing quote before a block tag"<a>else</a>"</p>“else““else”
Closing quote before an ellipsis"<a>link</a>"...“link“…“link”…
Closing quote before CJK punctuation"<em>引用</em>"。“引用“。“引用”。

Closing-tag elisions ride along with the same rule: <strong>l</strong>'homme and <strong>O</strong>'Neill now curl to a proper apostrophe — they are possessive-shaped, a closing tag then an apostrophe then a letter. The genuine cousins stay out of scope, because the apostrophe is not after a closing tag: an opening quote right after CJK text; an apostrophe that sits inside the tag, d<em>'</em>accord; and the mirror case where an opening tag splits a contraction, I<strong>'ve</strong>. Those are a different boundary problem (noted on another Trac ticket, #43810) but not fixed by the same rule.

Why this belongs upstream

Dirtbag could try to be clever here. We could disable wptexturize() entirely:

add_filter( 'run_wptexturize', '__return_false' );

That would be too much for a theme and even a plugin. It would change more than apostrophes: quotes, dashes, ellipses, primes, and old WordPress behaviour people may rely on. A theme should not make that decision for a site.

Dirtbag could also patch the rendered content after the fact, flipping &#8216; to &#8217; after certain inline closing tags. That is less blunt, but still a theme pretending to be a typography engine.

The right place is WordPress core. As I mentioned earlier, there is already an old ticket for the broader bug: Core Trac #18549, “wp_texturize incorrectly curls closing quotes after inline HTML end tags.” The ticket has a long history, patches, duplicate reports, and the correct diagnosis: wptexturize() loses quote context around inline HTML.

So now we’ve finally caught up with that old issue, and the LLMs are good enough to sort out such a thorny logic puzzle. The fix is now proposed upstream as a pull request against wordpress-develop, adding the closing-tag context guard and the tests below.

The useful test

The smallest issue revival comment is not another essay-length comment. It is a test.

/**
 * @ticket 18549
 */
public function test_apostrophe_after_inline_formatting_tag() {
    $this->assertSame(
        '<strong>He</strong>&#8217;s here.',
        wptexturize( "<strong>He</strong>'s here." )
    );
}

Then add the neighboring cases:

<em>It</em>'s fine.
<a href="#">Dan</a>'s truck
<strong>rock</strong>'n'roll

And do not overcorrect these:

<strong>Note:</strong> 'quoted text'
<strong>He said</strong> 'go'

That distinction matters. When a closing inline tag is immediately followed by an apostrophe and a letter or number, and the visible text before the tag ended with a letter or number, it is probably a contraction or possessive. When there is a space after the tag, normal opening-quote behaviour should still be possible.

The Dirtbag lesson

This is the same kind of bug as our floated-title problem: one default, one tiny inherited behaviour, one layout or text result that looks supernatural until the small rule is visible.

A theme like Dirtbag is supposed to stay close to WordPress. That is the bargain. Use core blocks. Use plain HTML. Avoid clever replacements. But staying close also means you get close enough to see the burrs.

This apostrophe is one of them. Not dramatic. Not a crisis. Just a small wrong curl after a tag.

Small wrong things are still wrong.

  1. The true culprits behind the persistent difficulty of getting human-typed writing into semantically valid and typographically correct, modern character encoding are the limitations and dominance of the English-language keyboard, and the historic priority given to compression and simplification from telegraph to teletype.

    Unless Linotype machines count — specifically built for typographic versatility — there have been no English keyboards with left and right angled single and double quotation marks, ellipses, em dashes. 5-bit USTTY and its precursors in the early 1900s (all based on BaudotMurray), and 7-bit ASCII (1963) solidified typewriter typography for the digital age. ↩︎

Respond from your own site

If your site supports Webmention, link to this page’s URL (it’s a permalink) and send it along. If not, a comment still counts. The old web still has many doors, pockets, and passageways.

Comments

Leave a Reply

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