When a string passed to the esc_url() and esc_url_raw() functions does not include a protocol (https://, http://, etc.), WordPress will prepend http:// to the URL A specific web address of a website or web page on the Internet, such as a website’s URL www.wordpress.org string before further processing and returning it. This is a reasonable fallback behavior, but there is currently no way to override the default protocol with another (such as https:// for social media profiles).
Starting in WordPress 6.9, the esc_url() and esc_url_raw() functions will now prepend https:// to the URL if it does not already contain a scheme and the first item in the $protocols array is 'https'. The current behavior (prepending http://) will continue when any other value is listed first within the $protocols array.
<?php
/*
* Recommended approach for defaulting to 'https' while maintaining
* backward compatibility.
*
* Example: no protocol with $protocols and 'https' first.
*
* Output:
* - WordPress >= 6.9: 'https://profiles.wordpress.org'
* - WordPress < 6.9: 'http://profiles.wordpress.org'
*/
echo esc_url( 'profiles.wordpress.org', array( 'https', 'http' ) );
By including 'https' first and then 'http' in the array:
- WordPress 6.9 would prepend
https:// to an incomplete URL.
- Older WordPress versions would continue to prepend
http://, which remains the default scheme when the $protocols argument is not defined. If the array only contains 'https', esc_url() would return an empty string because http is not included in the list of valid protocols.
Additional examples of output include:
<?php
/*
* Example 1: no protocol included in $url.
*
* Output:
* - WordPress >= 6.9: 'http://profiles.wordpress.org'
* - WordPress < 6.9: 'http://profiles.wordpress.org'
*/
echo esc_url( 'profiles.wordpress.org' );
/*
* Example 2: 'http' protocol included in $url.
*
* Output:
* - WordPress >= 6.9: 'http://profiles.wordpress.org'
* - WordPress < 6.9: 'http://profiles.wordpress.org'
*/
echo esc_url( 'http://profiles.wordpress.org' );
/*
* Example 3: 'https' protocol included in $url.
*
* Output:
* - WordPress >= 6.9: 'https://profiles.wordpress.org'
* - WordPress < 6.9: 'https://profiles.wordpress.org'
*/
echo esc_url( 'https://profiles.wordpress.org' );
/*
* Example 4: no protocol with $protocols and 'http' first.
*
* Output:
* - WordPress >= 6.9: 'http://profiles.wordpress.org'
* - WordPress < 6.9: 'http://profiles.wordpress.org'
*/
echo esc_url( 'profiles.wordpress.org', array( 'http', 'https' ) );
/*
* Example 5: no protocol in $url with $protocols and no 'http'.
*
* Output:
* - WordPress >= 6.9: 'https://profiles.wordpress.org'
* - WordPress < 6.9: ''
*
* Note: if 'http' is not included in the $protocols array,
* the fully escaped URL will not pass the final check that
* a valid, allowed protocol is included.
*/
echo esc_url( 'profiles.wordpress.org', array( 'https' ) );
/*
* Example 6: protocol within $url missing within $protocols.
*
* Output for all:
* - WordPress >= 6.9: ''
* - WordPress < 6.9: ''
*
* Note: if 'http' is not included in the $protocols array,
* the fully escaped URL will not pass the final check that
* a valid, allowed protocol is included.
*/
echo esc_url( 'https://profiles.wordpress.org', array( 'http' ) );
echo esc_url( 'http://profiles.wordpress.org', array( 'https' ) );
echo esc_url( 'mailto:indana@jon.es', array( 'https', 'http' ) );
For more information, refer to #52886.
Props to @desrosj for co-authoring the note, writing the code examples and expanding on details. Props to @jorbin for review.
#6-9, #dev-notes, #dev-notes-6-9