When And How To Escape Core Functions In WPORG Themes

NOTE: This list is far from complete but I guess it never will be complete so I’ll just publish and keep updating.


Which core function should be escaped is a very common problem for theme authors. Sometimes you have to dig deep into core code to find out whether function is already escaped or not. Further more, this might change at any given time for various reasons. I’ll try to keep this list as complete and as updated as possible.

ALSO NOTE: Functions which don’t return anything but echo values (like the_title(), the_content() etc) can not be escaped, and you shouldn’t try to. Only functions that return value should be considered for escaping.

get_bloginfo()

When used with only first parameter, this function must be properly escaped depending on the type of retrieved value, like so:

echo esc_html( get_bloginfo( 'name' ) );
echo esc_url( get_bloginfo( 'url' ) );

Second parameter determines how to filter the value. Default is raw and it needs escaping. Another option is display and, when used, the function does NOT need to be escaped.

echo get_bloginfo( 'name', 'display' );

home_url()

This function must be escaped. The most common usage:

echo esc_url( home_url( '/' ) );

Also read: home_url() vs site_url().

get_site_url()

This function must be escaped. The most common usage:

echo esc_url( get_site_url() );

site_url()

This function is wrapper for get_site_url() (but without support for multisite). It has to be escaped as well.

echo esc_url( site_url() );

Also read: home_url() vs site_url().

get_body_class()

This function does all escaping for you. Even if you add custom body classes through body_class filter hook, you don’t need to escape your classes as this function will cover them as well.

get_background_image()

This function returns URL for the body background image and should be escaped like so:

echo esc_url( get_background_image() );

get_background_color()

This function doesn’t need escaping.

get_header_image()

This function is already escaped with esc_url_raw() and it would seem as it needs no additional escaping. However, esc_url_raw() is escaping it for database usage. If you take a look at header_image() (which is just a wrapper for this function), you’ll see it’s escaped again.

So, this function must be escaped, like so:

echo esc_url( get_header_image() );

get_header_image_tag()

This function returns HTML image element markup or empty string on failure so it shouldn’t be escaped. Even when modifying attributes via get_header_image_tag filter hook, function does all the escaping for you.

get_random_header_image()

This function returns either URL or nothing (return '';). If it’s nothing, then function might actually return (bool) false. To make sure it’ll return empty string, it needs to be escaped.

echo esc_url( get_random_header_image() );

get_custom_header()

This function returns object of various custom_header values and they need appropriate escaping.

// URLs.
echo esc_url( get_custom_header()->url );
echo esc_url( get_custom_header()->thumbnail_url );

// Numbers.
echo absint( get_custom_header()->width );
echo absint( get_custom_header()->height );

get_custom_header_markup()

This function returns markup for a custom header on success and, therefore, should not be escaped.

get_header_video_settings()

This function returns array of various header video settings values. Default width and height values are escaped and in theory they are safe to be used without escaping. However, these values can be changed by plugins via header_video_settings filter which makes these values potentially unsafe. Escape everything!

$settings = get_header_video_settings();

// Numbers.
echo absint( $settings['width'] );
echo absint( $settings['height'] );

// URLs.
echo esc_url( $settings['posterUrl'] );
echo esc_url( $settings['videoUrl'] );

// Translation strings.
echo esc_html__( $settings['l10n']['play'] );
echo esc_html__( $settings['l10n']['pause'] );
// or
esc_html_e( $settings['l10n']['play'] );
esc_html_e( $settings['l10n']['pause'] );

Also, if you are setting custom values via header_video_settings filter, you should escape them as well.

function themeprefix_header_video_settings( $settings ) {
	$settings['width']        = absint( 900 );
	$settings['l10n']['play'] = esc_html__( 'Play', 'textdomain' );

	return $settings;
}
add_filter( 'header_video_settings', 'themeprefix_header_video_settings' );

get_post_class()

As expected, this function needs no escaping (just as get_body_class()) because all necessary escaping is done inside the function. It also covers any custom class that you might add via post_class filter hook.

get_the_title()

This function should be escaped, like so:

echo esc_html( get_the_title() );

Or, if you want to allow HTML tags:

echo wp_kses_post( get_the_title() );

the_title_attribute()

This function can be both, returned and echoed, depending on echo argument you pass to it. Either way, this function is stripping all the tags and escaped for attribute so you don’t have to do any additional escaping.

get_the_content()

This function is expected to return HTML so you don’t escape it. However, just echoing get_the_content() will give different results than the_content(). Proper usage of this function is applying the_content filter hook to it, like so:

$content = get_the_content( esc_html__( 'Read more', 'textdomain' ) );
echo apply_filters( 'the_content', $content );

get_the_excerpt()

Same as with get_the_content() function, a proper use of this function is applying the_excerpt filter hook to it, like so:

$excerpt = get_the_excerpt();
echo apply_filters( 'the_excerpt', $excerpt );

Function the_excerpt() is doing the exact same thing and should be used instead whenever is possible.

get_template_directory_uri()

Quick search through WordPress core code, shows two different treatments. This function needs escaping when it’s used inside of tag attribute.

<img src="<?php echo esc_url( get_template_directory_uri() . '/images/logo.jpg' ); ?>" alt="" >

When used inside wp_enqueue_style() or wp_enqueue_script(), it is not escaped:

wp_enqueue_script( 'theme-customizer', get_template_directory_uri() . '/js/customizer.js', array( 'customize-preview' ), '', true );

However, looking at the function itself, it has filter right before returning values which makes it suspicious – it can be filtered in plugins and we don’t know exactly what’s returned. Rule of thumb in this situation would be better safe than sorry and always escape.

get_the_archive_title()

This function returns get_the_archive_title filter and, therefore, should be escaped. It might appear that esc_html() is enough but if you take a look at the function itself, you’ll notice additional markup for author archive. This markup will be printed on page just as regular text if escaped with esc_html(). The proper escaping would be as following:

echo wp_kses_post( get_the_archive_title() );

get_the_archive_description()

This function returns get_the_archive_description filter and must be escaped. To properly escape all sorts of archive descriptions, we should allow HTML tags.

echo wp_kses_post( get_the_archive_description() );

Leave a comment

Your email address will not be published.
You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.