esc_url( string $url, string[] $protocols = null, string $_context = ‘display’ ): string

Checks and cleans a URL.

Description

A number of characters are removed from the URL. If the URL is for displaying (the default behavior) ampersands are also replaced. The ‘clean_url’ filter is applied to the returned cleaned URL.

Parameters

$urlstringrequired
The URL to be cleaned.
$protocolsstring[]optional
An array of acceptable protocols.
Defaults to return value of wp_allowed_protocols() .

Default:null

$_contextstringoptional
Private. Use sanitize_url() for database usage.

Default:'display'

Return

string The cleaned URL after the 'clean_url' filter is applied.
An empty string is returned if $url specifies a protocol other than those in $protocols, or if $url contains an empty string.

More Information

Always use esc_url when escaping URLs (in text nodes, attribute nodes or anywhere else). For sanitizing, sanitize_url() should be used instead. Rejects URLs that do not have one of the provided whitelisted protocols (defaulting to http, https, ftp, ftps, mailto, news, irc, gopher, nntp, feed, and telnet), eliminates invalid characters and removes dangerous characters. This function encodes characters as HTML entities: use it when generating an (X)HTML or XML document. Encodes ampersands (&) and single quotes (‘) as numeric entity references (&#038, &#039).

If the URL appears to be an absolute link that does not contain a scheme, prepends http://. Please note that relative urls (/my-url/parameter2/), as well as anchors (#myanchor) and parameter items (?myparam=yes) are also allowed and filtered as a special case, without prepending the default protocol to the filtered url.

Replaces the deprecated clean_url() .

Source

function esc_url( $url, $protocols = null, $_context = 'display' ) {
	$original_url = $url;

	if ( '' === $url ) {
		return $url;
	}

	$url = str_replace( ' ', '%20', ltrim( $url ) );
	$url = preg_replace( '|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url );

	if ( '' === $url ) {
		return $url;
	}

	if ( 0 !== stripos( $url, 'mailto:' ) ) {
		$strip = array( '%0d', '%0a', '%0D', '%0A' );
		$url   = _deep_replace( $strip, $url );
	}

	$url = str_replace( ';//', '://', $url );
	/*
	 * If the URL doesn't appear to contain a scheme, we presume
	 * it needs http:// prepended (unless it's a relative link
	 * starting with /, # or ?, or a PHP file).
	 */
	if ( ! str_contains( $url, ':' ) && ! in_array( $url[0], array( '/', '#', '?' ), true ) &&
		! preg_match( '/^[a-z0-9-]+?\.php/i', $url )
	) {
		$url = 'http://' . $url;
	}

	// Replace ampersands and single quotes only when displaying.
	if ( 'display' === $_context ) {
		$url = wp_kses_normalize_entities( $url );
		$url = str_replace( '&', '&', $url );
		$url = str_replace( "'", ''', $url );
	}

	if ( str_contains( $url, '[' ) || str_contains( $url, ']' ) ) {

		$parsed = wp_parse_url( $url );
		$front  = '';

		if ( isset( $parsed['scheme'] ) ) {
			$front .= $parsed['scheme'] . '://';
		} elseif ( '/' === $url[0] ) {
			$front .= '//';
		}

		if ( isset( $parsed['user'] ) ) {
			$front .= $parsed['user'];
		}

		if ( isset( $parsed['pass'] ) ) {
			$front .= ':' . $parsed['pass'];
		}

		if ( isset( $parsed['user'] ) || isset( $parsed['pass'] ) ) {
			$front .= '@';
		}

		if ( isset( $parsed['host'] ) ) {
			$front .= $parsed['host'];
		}

		if ( isset( $parsed['port'] ) ) {
			$front .= ':' . $parsed['port'];
		}

		$end_dirty = str_replace( $front, '', $url );
		$end_clean = str_replace( array( '[', ']' ), array( '%5B', '%5D' ), $end_dirty );
		$url       = str_replace( $end_dirty, $end_clean, $url );

	}

	if ( '/' === $url[0] ) {
		$good_protocol_url = $url;
	} else {
		if ( ! is_array( $protocols ) ) {
			$protocols = wp_allowed_protocols();
		}
		$good_protocol_url = wp_kses_bad_protocol( $url, $protocols );
		if ( strtolower( $good_protocol_url ) !== strtolower( $url ) ) {
			return '';
		}
	}

	/**
	 * Filters a string cleaned and escaped for output as a URL.
	 *
	 * @since 2.3.0
	 *
	 * @param string $good_protocol_url The cleaned URL to be returned.
	 * @param string $original_url      The URL prior to cleaning.
	 * @param string $_context          If 'display', replace ampersands and single quotes only.
	 */
	return apply_filters( 'clean_url', $good_protocol_url, $original_url, $_context );
}

Hooks

apply_filters( ‘clean_url’, string $good_protocol_url, string $original_url, string $_context )

Filters a string cleaned and escaped for output as a URL.

Changelog

VersionDescription
2.8.0Introduced.

User Contributed Notes

  1. Skip to note 5 content

    If the URI protocol is not one of the allowed protocols, the result of esc_url() is an empty string. The list of default protocols allowed by WordPress can be extended with the following code:

    <?php
    /**
     * Extend list of allowed protocols.
     *
     * @param array $protocols List of default protocols allowed by WordPress.
     *
     * @return array $protocols Updated list including new protocols.
     */
    function wporg_extend_allowed_protocols( $protocols ){
    	$protocols[] = 'skype';
    	$protocols[] = 'spotify';
    	$protocols[] = 'macappstores';
    	return $protocols;
    }
    add_filter( 'kses_allowed_protocols' , 'wporg_extend_allowed_protocols' );
    ?>
  2. Skip to note 6 content

    Escaping the “img” tag’s “src” attribute is also something that this function should be used for:

    <img src="<?php echo esc_url( $image_url ); ?>" alt="..." />

    It should also be used for the “form” tag “action” attribute:

    <form action="<?php echo esc_url( $form_submit_url ); ?>">

You must log in before being able to contribute a note or feedback.