wppaste
WordPress

set_url_scheme( string $url, string|null $scheme = null ): string

Since
3.4.0, 4.4.0
Source
wp-includes/link-template.php:3922

Rewrites an absolute URL to use a specific scheme, http, https, or relative, falling back to the current is_ssl() state when no valid scheme is given. It underlies functions such as home_url(), content_url(), and admin_url(), so passing an unexpected value here can ripple through generated links. Every call passes through the 'set_url_scheme' filter, so a plugin can rewrite the final URL after WordPress has already normalized it.

Sets the scheme for a URL.

Compatibility

WordPress
since 4.4.0
PHP
7.4–8.6-dev
  • 6.7.7
  • 6.8.8
  • 6.9.7
  • 7.0.4
  • 7.1.0

Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.

Parameters

$urlstring
Absolute URL that includes a scheme
$schemestring|nulloptional
Scheme to give $url. Currently 'http', 'https', 'login', 'login_post', 'admin', 'relative', 'rest', 'rpc', or null. Default null.Default: null

Return value

string
URL with chosen scheme.

Code examples

Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.

Force a post permalink to use https regardless of the current request

Take the permalink of the seeded "Hello world!" post and rewrite its scheme explicitly.

$permalink = get_permalink( 1 );
$https_link = set_url_scheme( $permalink, 'https' );

printf( 'Original: %s', esc_html( $permalink ) );
echo '<br>';
printf( 'Forced https: %s', esc_html( $https_link ) );

The 'https' scheme is applied literally here; passing an unrecognized value would fall back to whatever is_ssl() reports for the current request.

Convert an absolute URL to a scheme-relative URL

Strip the scheme from a hardcoded absolute URL so it works over both http and https.

$asset_url = 'https://example.org/wp-content/uploads/2024/01/banner.jpg';
$relative = set_url_scheme( $asset_url, 'relative' );

printf( 'Scheme-relative URL: %s', esc_html( $relative ) );

Common problems and fixes · 3

Why does set_url_scheme() ignore the scheme I passed in?

Only 'http', 'https', and 'relative' survive as the literal $scheme used to rewrite the URL. Any other value, including 'rest' from the docblock's list of accepted inputs, falls through the elseif chain and gets replaced with 'https' or 'http' based on is_ssl().

Why do my admin or login URLs come back as https when the site isn't forcing SSL sitewide?

For the 'admin', 'login', 'login_post', and 'rpc' schemes, the function checks force_ssl_admin() in addition to is_ssl(). If that setting or constant is on, the URL is rewritten to https even though the current request is plain http.

Why did my double-slash protocol-relative URL turn into an http:// URL?

Before applying the requested scheme, the function prepends 'http:' to any URL starting with '//' so the regex that swaps the scheme has something to match. That intermediate 'http:' is then overwritten by whatever scheme you actually requested.

Alternatives and related functions

home_url
When you need the site's home URL with a scheme applied rather than rewriting an arbitrary existing URL string.
admin_url
When you need a URL inside wp-admin and want WordPress to pick the admin scheme (including force_ssl_admin() handling) for you.
content_url
When you need a URL under wp-content and want the site's default scheme applied automatically.
is_ssl
When you only need to know whether the current request is over https, without rewriting any URL.

Performance profile

How much work a call to set_url_scheme() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.

Cost class
Trivial

Touches nothing outside its own arguments.

Scaling
Constant

No loop in the body: the same number of instructions runs whatever you pass in.

Instructions
27–57

Executed per call on PHP 8.5, depending on the branch taken. The body compiles to 81.

Plugin surface
1 hook

Third-party callbacks on 'set_url_scheme' run inside this call, and their cost is not bounded by anything here.

Called by
45

45 places in core call this, so the cost is paid more often than your own code shows.

What it touches

  • hookthird-party callbacksapply_filters()called directly

What one call costs · 9 distinct outcomes

One number would be a lie: the work depends on which branch runs. These are every distinct cost set_url_scheme() can have, taken from its control-flow graph on PHP 8.5.

WhenInstructionsCalls it makes
$scheme !== "relative"27–43is_ssl(), apply_filters()
$scheme !== "admin" && $scheme !== "login" && $scheme !== "login_post" && $scheme !== "rpc" && $scheme !== "relative"31–37apply_filters()
$scheme === "relative"31–50is_ssl(), ltrim(), apply_filters()
!is_ssl() && $scheme !== "relative"32–41is_ssl(), force_ssl_admin(), apply_filters()
$scheme !== "admin" && $scheme !== "login" && $scheme !== "login_post" && $scheme !== "rpc" && $scheme === "relative"35–44ltrim(), apply_filters()
!is_ssl() && $scheme === "relative"36–48is_ssl(), force_ssl_admin(), ltrim(), apply_filters()
$scheme === "relative" && $url !== ""41–57is_ssl(), ltrim(), ltrim(), apply_filters()
$scheme !== "admin" && $scheme !== "login" && $scheme !== "login_post" && $scheme !== "rpc" && $scheme === "relative" && $url !== ""45–51ltrim(), ltrim(), apply_filters()
!is_ssl() && $scheme === "relative" && $url !== ""46–55is_ssl(), force_ssl_admin(), ltrim(), ltrim(), apply_filters()

Across PHP versions

PHPCompiledExecutedBranchesNotes
8.6-dev8127–5716
8.58127–5716
8.48127–571611 fewer instructions than PHP 8.3
8.39235–6516
8.29235–6516
8.19235–6516
7.49235–6516

An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.

Hooks and filters fired · 1

One hook fires while set_url_scheme() runs, in this order:

  1. apply_filters( set_url_scheme )filterline 3957 (+35 into the body)

    Filters the resulting URL after setting the scheme.

Uses · 4

Used by · 45

Show all 45

Source code

function set_url_scheme( $url, $scheme = null ) {	$orig_scheme = $scheme; 	if ( ! $scheme ) {		$scheme = is_ssl() ? 'https' : 'http';	} elseif ( 'admin' === $scheme || 'login' === $scheme || 'login_post' === $scheme || 'rpc' === $scheme ) {		$scheme = is_ssl() || force_ssl_admin() ? 'https' : 'http';	} elseif ( 'http' !== $scheme && 'https' !== $scheme && 'relative' !== $scheme ) {		$scheme = is_ssl() ? 'https' : 'http';	} 	$url = trim( $url );	if ( str_starts_with( $url, '//' ) ) {		$url = 'http:' . $url;	} 	if ( 'relative' === $scheme ) {		$url = ltrim( preg_replace( '#^\w+://[^/]*#', '', $url ) );		if ( '' !== $url && '/' === $url[0] ) {			$url = '/' . ltrim( $url, "/ \t\n\r\0\x0B" );		}	} else {		$url = preg_replace( '#^\w+://#', $scheme . '://', $url );	} 	/**	 * Filters the resulting URL after setting the scheme.	 *	 * @since 3.4.0	 *	 * @param string      $url         The complete URL including scheme and path.	 * @param string      $scheme      Scheme applied to the URL. One of 'http', 'https', or 'relative'.	 * @param string|null $orig_scheme Scheme requested for the URL. One of 'http', 'https', 'login',	 *                                 'login_post', 'admin', 'relative', 'rest', 'rpc', or null.	 */	return apply_filters( 'set_url_scheme', $url, $scheme, $orig_scheme );}

Changelog

Introduced in 3.4.0. Unchanged from 6.7.7 through 7.1.0.

  1. 6.7.7
  2. 6.8.8
  3. 6.9.7
  4. 7.0.4
  5. 7.1.0

Signature, return type and hooks compared across 5 parsed releases.

4.4.0
The 'rest' scheme was added.from the docblock
3.4.0
Introduced.from the docblock

About this page

Parsed data
Generated from the wordpress-develop 6.7.7 tag, from src/wp-includes/link-template.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it.
Corrections
Something wrong on this page? Report it and it gets fixed in the next regeneration.