Escaping WordPress Template Functions. To do or not to do?

Reading Time: 7 mins

Sanitization, escaping, and validation have become a regular part of my WordPress theme development within the last year. If those words confuse you, don’t worry, I’ve got another draft in my dashboard waiting to be finished. Eventually. 😉

But for those of you that do have a general idea of what these terms mean, perhaps you’ve faced the same nagging questions I had when it came to escaping WordPress template functions. At first, I was just applying escape functions mechanically, while not truly understanding what it was that I was doing, I knew that it was a best practice. Just like WordPress hooks, over time, my understanding became less fuzzy, but until these nagging questions could be answered, I couldn’t feel confident that I was escaping correctly.

Which WordPress template functions should be escaped? Which functions already have this built into core?

By template functions, I mean functions that are regularly used throughout theme development to call content from the dashboard. Like the_title(), the_permalink(), and the_excerpt() to name a few.

This becomes harder to figure out if, like me,  you hadn’t truly dived into WordPress’ mysterious core files for browsing. Or maybe you have, but found it overwhelming to follow the rabbit hole and chain of functions while simultaneously trying to make sense of how WordPress does just one thing. It doesn’t help if your code editor doesn’t make the task any easier. I’m a huge fan of Sublime Text, but have recently been exploring PHP Storm. I won’t lie to you, I still prefer Sublime for my daily development needs, but PHP Storm has a feature that has made learning about WordPress core so much easier.

You can Shift (PC) or Command (Mac) click on any function, WordPress or not, and it will take you to the file and line where that function is written. So for WordPress core, instead of being overwhelmed by all the files in the wp-admin or wp-includes folder, PHP Storm teleports you instantly!

A power ranger teleporting.

And so, via PHP Storm, I narrowed down which core functions actually needed escaping. I threw together a reference until it’s something I commit to memory, and thought it would be useful to share said reference with a blog post. In this post, I’ll also briefly review what escaping does for us, and how we would know if a template function needs escaping. Let’s get to it!

Briefly, what does escaping do again?

Escaping takes data already stored in the WordPress database, and secures it prior to rendering it on the front-end. Escaping cleans up and removes anything unexpected or harmful depending on what kind of data it is and which escape function is being used. You can find a list of WordPress’ escape functions in the Codex. See? I said it would be brief. 🙂

How do we know if we should escape?

When should we escape a WordPress template function? Honestly the most straightforward rule I’ve been following is to escape everything. Better to be safe than sorry. Many others agree with the sentiment. Not to mention, it’ll help make escaping a regular habit if it’s constantly done during WordPress development.

However, there are two cases where you might not want to escape. The first case is if you want any HTML to come through depending on what you need the content for.

Let’s say I write some content on the dashboard for a page and part of that content, I decide to make bold and change a color using WordPress’ TinyMCE toolbar. This is what it looks like on the dashboard:

The visual tab for the text editor.

 

The text tab for the text editor.

 

Now in a page template, I’ve used PHP to set up a WordPress loop and tried three different ways to get the text editor content. The first way is using the_content() which converts line breaks into paragraphs and allows the HTML to do what it needs to do. The second way echos out get_the_content() instead without escaping, and while it no longer converts paragraphs, it still allows any HTML to output what it needs.

The third way, I echoed out get_the_content() again except I escaped it. There are still no paragraphs, however, the HTML is being displayed on the front-end instead of being interpreted by the browser. Notice how the strong and span tags used to bold the text and change it’s color are now visible on the front-end in my screenshot below.

What each of the three ways for getting the content look like on the front-end of a site.

Therefore whenever you use a template function, be aware of it’s purpose in your project before deciding whether to escape it.

The second case to reconsider escaping is if the function already escapes in WordPress core. If you escape a function that already escapes, you’re just escaping the same thing twice.

And this is where we move onto the reference I mentioned earlier in the post. Continue reading for a list of commonly used template functions, where they’re defined in WordPress core and whether they need escaping.

A handy reference for escaping WordPress template functions.

The three most common escape functions I use are for escaping text content, urls and HTML attributes ( for things like classes or IDs ). The difference between the esc_something and esc_something_e functions are that the latter allows for translation. The latter also already echo’s the data whereas with the esc_something, we have to add the echo in.

I always go the translation route for text escaping by default. The only time I do not set up for translation is if I’m pulling dynamic content from the dashboard – in other words text that isn’t static. It would be hard to translate text that’s constantly going to change and depends on the user. Any content that is part of the theme such as buttons, screen reader text, or headings that aren’t going to change, I will escape with translation.

Even if you don’t plan on ever translating your theme into multiple languages, there’s no harm in setting it up. Should you decide change your mind in the future, the code work is already done.

Another two tips! We only want to translate text content, not text used for HTML attributes like classes, IDs or data attributes. We can escape them, yes, but not translate.

As for accessibility, screen reader text should always be set up for translation and escaping.

Back on topic! Which escape function to use for each type of data? If it’s a title or some sort of content where we’re only expecting text, then use either esc_html() or esc_html_e.

If it’s a url, then use esc_url(). And if it’s an HTML attribute, use esc_attr().

And finally, which WordPress template functions need escaping that core doesn’t already do the job? The handy reference is below. If you see something not quite right, feel free to give me a shout in the comments and I’ll make corrections.

I did a quick run through a default WordPress theme just to grab what I thought were the most common template functions. A lot of the functions call to other functions and I didn’t always specify that below. However I provided the file where the starting function can be found so that you’re free to follow the chain if you’d like.

*As I mentioned earlier, keep in mind what you need a function for before you escape it. If the table below says “Yes” for “Can I escape?”, it doesn’t necessarily mean you have to – it means that you have the option to and can make that decision on a case by case basis.

Function File Location Can I Escape?
get_the_permalink() and get_permalink()

 wp-includes/link-template.php

This returns the data without escaping.

Yes
the_permalink()

 wp-includes/link-template.php

This applies esc_url  when it returns.

 No
home_url() and get_home_url()

wp-includes/link-template.php

This returns the data without escaping.

Yes
site_url() and get_site_url()

wp-includes/link-template.php

This returns the data without escaping.

Yes
blog_info() and get_bloginfo()

wp-includes/general-template.php

This returns the data without escaping.

Yes
the_title() and get_the_title()

 wp-includes/post-template.php

This returns the data without escaping.

 Yes
the_content() and get_the_content()

 wp-includes/post-template.php

This returns the data without escaping.

 Yes
the_excerpt() and get_the_excerpt()

wp-includes/post-template.php

This returns the data without escaping.

Yes
get_post_meta()

wp-includes/post.php

This returns the data without escaping.

Yes
the_category()

wp-includes/category-template.php

This doesn’t escape in it’s own function, but performs some escaping and cleanup in get_the_category_list() which it calls to.

No
get_the_category()

wp-includes/category-template.php

This calls to get_the_terms() and doesn’t escape in either function when it returns.

 Yes
edit_post_link()

wp-includes/link-template.php

This does escape when it returns the url.

No
the_archive_title()

wp-includes/general-template.php

Calls to get_the_archive_title() in this function and escapes in neither one.

Yes
the_archive_description()

wp-includes/general-template.php

Calls to to get_the_archive_description() which then calls term_description() and there’s a bit of a rabbit hole. Seems like it would be safe to escape here just in case.

 Yes – just in case.

As you can see, in most cases above, escaping WordPress template functions is a necessity. Every WordPress theme is different, and should you use other WordPress template functions that you’re not sure about, feel free to check core files. The rule of thumb is to always escape, but there may be the occasional case where you’ll need to reconsider.

If you’re not using PHP Storm, and prefer Sublime Text ( which is free until you choose to pay for a license to support the product ) – there is a package you can download that does something similar called Sublime Code Intel. I’ve also heard good things about Visual Studio Code and a “peek” function. I’ve yet to try either of those so if they’re awesome, feel free to gush about their greatness in the comments. I hope this has helped you just as much as it’s helped me. I feel a lot better escaping WordPress template functions now that I’ve taken a peek under the hood. Now about that draft I need to finish, among all the other drafts…

Until next time!

 

 

Leave a Reply