In a talk at the WordCamp Spain online 2021 Adriá Cobo asked me one interesting question about these 2 functions (e() and esc_html_()):
If everything that is printed must be escaped, what is the point of _e()? Is it a legacy code?
In this post, I try to answer this question.
The _e( string $text, string $domain = ‘default’ ) function displays translated text. Its parameters are:
- $text: Text to translate.
- $domain: Text domain. Unique identifier for retrieving translated strings.
It was introduced in the 1.2.0 version.
The esc_html_e( string $text, string $domain = ‘default’ ) function displays translated text that has been escaped for safe use in HTML output. It has the same parameters that the _e() function.
It was introduced in the 2.8.0 version with other escape functions.
First, I want to talk about the use of these functions. As you can see, both functions have the same parameters, and both display the translated text, but the esc_html_e() function escapes the translated text. This is the main difference. Why we should use the escaped version? Mainly because translations are done by third parties, both professionals and volunteers, who may introduce different layout problems (a new HTML tag, an unclosed tag) or security problems (the execution of a script). We cannot rely on the work of third parties, as they can accidentally or intentionally introduce problems through the translations: treat internationalized strings like you would any other untrusted input. More about this on the internationalization security guide in the Plugin Handbook.
So why do we have an unescaped function?
I think the main cause is due to historical reasons, because the e() function was released on May 22, 2004 and the esc_html_e() function was released on June 11, 2009, so all the code wrote between these 2 dates use the unsecure function. One possible solution could be to set a deprecation date, so after a certain date, this function would not work. But this would surely bring a lot of broken themes and plugins. Even, WordPress core uses 246 times the _e() function, while the esc_html_e() function is only used 31 times.
In resume, always use the escaped functions, and be advised that the unsecured functions will be here with us a long time, maybe forever.
All this stuff applies to other translation functions:
- __() ⇾ esc_html__()
- _e() ⇾ esc_html_e()
- _x() ⇾ esc_html_x()
- __() ⇾ esc_attr__()
- _e() ⇾ esc_attr_e()
- x() ⇾ esc_attr_x()
More info: