I know it's best practise to escape all output. However I run into issues when people use special characters in their content. e.g. &, –, etc.

Note I'm using Timber, so for example if a post title uses an & in the text, and I echo and escape the title as follows:

{{ post.title|e() }}

(Not using Twig this would be<?php echo esc_html($post->title); ?>)

The page displays the htmlentity code (i.e. &amp;) and it is not converted to an ampersand in the browser. However if I echo without escaping it displays correctly.

I thought perhaps Timber or Twig or WordPress were auto-escaping, and perhaps my content was double escaped, but if I add a script to the title to test the output e.g. "<script>alert('hello');</script>" This script will run if I don't escape.

My question is how can I keep output safe but still render special characters in the browser that the user would expect to see from their content? And isn't this how it should be working by default (i.e. browser rendering escaped ampersand correctly)?

  • Why should it be autoescaped - it would be horrible - you couldn't echo formatted HTML then. But Twig/Timber is off-topic in here, since it has nothing to do with WordPress. (BTW, I really wouldn't recommend using Timber and Twig in WordPress themes). Commented May 2, 2018 at 8:44
  • @KrzysiekDróżdż I wouldn't expect it, but I was expecting (maybe incorrectly) ampersands to be rendered in the browser when htmlencoded.
    – benedict_w
    Commented May 2, 2018 at 8:58
  • Say you have this content: < &lt;, if it didn't encode ampersands then the result would be &lt; &lt;, which the browser would display as < <, which is not what you entered. By encoding to &lt; &amp;lt; it will be displayed as < &lt;, which is correct. Commented May 2, 2018 at 9:19
  • But if the user enter a plain & and it is escaped in the output, shouldn't the browser render the escaped ampersand as & and not as &amp; Sorry if I'm going round in circles!
    – benedict_w
    Commented May 2, 2018 at 9:36
  • No because the act of escaping is converting & to &amp;. That's what escaping is for. Commented May 12, 2018 at 10:21

1 Answer 1


If I put <script>alert('hello');</script> in the title of a WordPress page with the default theme the script runs. This is expected behaviour. HTML is typically allowed in titles in WordPress. The standard WordPress function, the_title(), does not escape the title.

If you don't want to allow script tags then you need to sanitize the input to strip out any unwanted tags when the post is saved. WordPress already does for users that don't have the unfiltered_html capability. It does it by using the wp_kses_post() function (note that this function is too slow to use for escaping on the front-end).

If you only want to remove HTML tags, but not encode any other characters, then you should use the strip_tags() function. It looks like you use this in Twig with striptags:

{{ some_html|striptags }}
  • I want my output to be safe so have been using escaping (esc_html, esc_attr, etc.) as I understand to be best practice. I'm not expecting HTML tags in the content, so I'm happy for them to be encoded by these functions, but I want special characters a user might use e.g. ampersands to be displayed as the user would expect (i.e, as an ampersand not an htmlentity &amp;). Perhaps this is my misunderstanding of what should happen. Is striptags then considered a safe alternative?
    – benedict_w
    Commented May 2, 2018 at 8:59
  • I think you're being slightly overzealous. esc_html() is used so that a value can't break the parent tag. esc_attr() is to ensure a vavlue doesn't break out of the attribute tag in the HTML. esc_textarea() ensures a value doesn't break the textarea tag. These aren't entirely about security issues. They're mainly about making sure values can't undermine the structural integrity of the page. You also need to consider where the data is coming from. You're using a CMS that allows certain users to enter HTML into the title. You need to allow for that. Commented May 2, 2018 at 9:13
  • And just look at the documentation: timber.github.io/docs/reference/timber-post/#title {{ post.title }} is the equivalent to the_title(), and the standard way in WordPress for outputting the title is the_title(), unescaped. Commented May 2, 2018 at 9:14
  • Perhaps my issues then is similar to descibed here: stackoverflow.com/questions/20551286/twig-do-not-escape
    – benedict_w
    Commented May 2, 2018 at 9:40
  • What issues? You’re not having any issues. You’re trying to do something you don’t need to do and you’re doing it the wrong way regardless. I explained all this in my answer... Commented May 2, 2018 at 11:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.