_e() function displays a translated string; so 1) You're actually echoing a dynamic text; and 2) Yes, you should escape a translated string.
Relevant excerpt taken from the internationalization security guide in the Plugin Handbook:
Escape Internationalized Strings
other code instead. To protect against that, it’s important to
treat internationalized strings like you would any other untrusted input.
If you’re outputting the strings, then they should be escaped.
<?php _e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' ); ?>
<?php esc_html_e( 'The REST API content endpoints were added in WordPress 4.7.', 'your-text-domain' ); ?>
In response to your comment:
example of when I might use
_e() instead of
So based on the excerpt from the internationalization security guide, I believe we should just use
esc_html_e() and avoid using
_e() unless we are 100% certain that a translation is completely clean from malicious code and special characters (apart from the basic ones like dots/
- and spaces).
And one may want to use
_e() because he/she wants HTML code (e.g.
a, etc.) in the translation to be interpreted (e.g.
<b>hey</b> would visually show
hey in bold like so: hey):
// if the translation was '<b>Enviar</b>' (in Spanish), then 'Enviar' would
// visually be in bold
_e( 'Submit' );
// equivalent to echo __( 'Submit' );
// but here, the text would remain as-is ('<b>Enviar</b>')
esc_html_e( 'Submit' );
// equivalent to echo esc_html( __( 'Submit' ) );
But then, instead of using
_e(), one should use
__() and with functions like
wp_kses() which allows us to control the list of allowed HTML tags and attributes (e.g. we can allow/disallow
onclick, etc.). And despite these functions do not guarantee that the output is actually secure, using them is at least better compared to simply echoing the raw HTML:
// what if the translation was 'Enviar <script>some bad JS code</script>' ?
_e( 'Submit' );
// wp_kses_data() by default disallows/removes <script> and </script> tags.
// sample output: 'Enviar some bad JS code' - doesn't look good.. but better
// than the browser executing the bad JS script.
echo wp_kses_data( __( 'Submit' ) );
Nevertheless, if one can ensure that a translation is secure (e.g. by moderating a translation), then using
_e() would not be a problem — and in fact, it's simpler (just one single function call)...
The WordPress core also calls
_e() without escaping the HTML output... e.g.
_e( 'Enter your password to view comments.' ); and that distracted my focus in writing the previous versions of this answer. Nonetheless, I'm not going to comment further on that possibly insecure
And just so you know, I'm not a security expert. :)