esc_url, esc_url_raw or sanitize_url?

This might be a more useful demonstration:

<a href="<?php echo esc_url( $url ); ?>>I'm printing a URL to the frontend</a>
$url = sanitize_url( $_GET['user_inputted_data'] );
update_post_meta( $post_id, 'that_url', $url );

esc_url is an escaping function, sanitize_url is a sanitising function.

  • Sanitising functions clean incoming data, e.g. removing letters from phone numbers, stripping trailing space etc. This is the soap that cleans your data on the way into your site. Always sanitise user inputs and data from 3rd party/external sources such as forms and file imports.
  • Escaping functions escape data on output. Why trust that the variable contains a URL when you can force it to be a URL and guarantee it. esc_url here makes everything into a URL, even if it is not. There’s no sneaking in a script tag or other malicious HTML. Escaping functions are like cookie cutters, they enforce and guarantee their output will fit a particular shape or constraint. E.g. esc_html always returns plaintext, even if you pass it HTML it will escape the < and > so they’re human readable plaintext.

You would never sanitise on output, just as you would never escape on input.

Now it seems that esc_url_raw under the hood executes sanitize_url which in turn under the hood executes esc_url, in the end applying the clean_url_filter via the db context.

Indeed if you look at esc_attr and esc_html they both do the same thing, but that doesn’t mean they’re interchangeable. For one they have their own filters, so they might not be the same. It’s also self-documenting. It’s also a reminder that sometimes you should use other functions for attributes when you know more about their data type, e.g. esc_url for URLs, intval for integers, etc.

But what about esc_url_raw? Do not use this to escape output. It’s stated quite clearly on the official WP developer docs sites entry for this function. If you are trying to echo/print a URL in HTML, use esc_url.

What About esc_url_raw?

In 99% of situations you will never need to use this, and on the frontend when outputting URLs it should never be used.

The primary reason you would want to use this is for database queries according to the official documentation:

The esc_url_raw() function is similar to esc_url() (and actually uses it), but unlike esc_url() it does not replace entities for display. The resulting URL is safe to use in database queries, redirects and HTTP requests.

This function is not safe to use for displaying the URL, use esc_url() instead.

Lets run through your examples:

HTTP redirect, executed in PHP

Use esc_url_raw as the docs suggest.

page load, triggered via via js via window.location = <escaped_link_if_clicked>

While you should esc_url, the important part is that this is inside javascript, so you actually have an additional step to do:

window.location = <?php echo wp_json_encode( esc_url( $url ) ); ?>

Valid URLs can contain quotes, wp_json_encode can safely escape those for use inside javascript.

anchor tag link whose href value holds the escaped URL.

Always esc_url, never esc_url_raw.