I've finally got it working now, as follows:
First I found the original wp_dependencies_unique_hosts()
function from the WordPress code (it's in a file called general-template.php), and I made a copy of it, but giving it a new name: wp_dependencies_unique_urls()
.
I observed that this function is using wp_parse_url()
to grab just the host part of each URL from the list of scripts and styles. In other words, it's dropping the scheme, which is the reason for the problem I'm having.
So I modified the function to include the scheme - here it is in its entirety:
function wp_dependencies_unique_urls() {
global $wp_scripts, $wp_styles;
$unique_urls = array();
foreach ( array( $wp_scripts, $wp_styles ) as $dependencies ) {
if ( $dependencies instanceof WP_Dependencies && ! empty( $dependencies->queue ) ) {
foreach ( $dependencies->queue as $handle ) {
if ( ! isset( $dependencies->registered[ $handle ] ) ) {
continue;
}
$dependency = $dependencies->registered[ $handle ];
$parsed = wp_parse_url( $dependency->src );
if ( ! empty( $parsed['host'] ) && ! in_array( $parsed['host'], $unique_urls ) && $parsed['host'] !== $_SERVER['SERVER_NAME'] ) {
$unique_urls[] = $parsed['scheme'] . '://' . $parsed['host'];
}
}
}
}
return $unique_urls;
}
As you can see, the main thing I've changed is this:
$unique_urls[] = $parsed['scheme'] . '://' . $parsed['host'];
I hope this is the best way to add the scheme to the beginning of each URL.
Next, I modified my original function (from my original question above) so it calls this new function I've created:
function dns_prefetch_to_preconnect( $urls, $relation_type ) {
if ( 'dns-prefetch' === $relation_type ) {
$urls = [];
}
if ( 'preconnect' === $relation_type ) {
$urls = wp_dependencies_unique_urls();
}
return $urls;
}
add_filter( 'wp_resource_hints', 'dns_prefetch_to_preconnect', 0, 2 );
Et voila, it works! I now have valid 'preconnect' links in my page headers, which use the same scheme as the original enqueued scripts and styles - either http or https!
And if I want to, I can combine my two functions into one big function for simplicity:
function dns_prefetch_to_preconnect( $urls, $relation_type ) {
global $wp_scripts, $wp_styles;
$unique_urls = array();
foreach ( array( $wp_scripts, $wp_styles ) as $dependencies ) {
if ( $dependencies instanceof WP_Dependencies && ! empty( $dependencies->queue ) ) {
foreach ( $dependencies->queue as $handle ) {
if ( ! isset( $dependencies->registered[ $handle ] ) ) {
continue;
}
$dependency = $dependencies->registered[ $handle ];
$parsed = wp_parse_url( $dependency->src );
if ( ! empty( $parsed['host'] ) && ! in_array( $parsed['host'], $unique_urls ) && $parsed['host'] !== $_SERVER['SERVER_NAME'] ) {
$unique_urls[] = $parsed['scheme'] . '://' . $parsed['host'];
}
}
}
}
if ( 'dns-prefetch' === $relation_type ) {
$urls = [];
}
if ( 'preconnect' === $relation_type ) {
$urls = $unique_urls;
}
return $urls;
}
add_filter( 'wp_resource_hints', 'dns_prefetch_to_preconnect', 0, 2 );
wp_dependencies_unique_hosts
are just hosts, they aren't URLs and don't have a schema. Have you confirmed it is indeedhttp://
and that this isn't something the browser is adding? There should be no schema at all based on the code in your question – Tom J Nowell♦ Jan 4 '20 at 1:55wp_dependencies_unique_hosts
returned no hosts – Tom J Nowell♦ Jan 4 '20 at 2:43'tomjn.com'
it will prefix it withhttp://
as it doesn't know what the correct schema is, and it can't usehttps://
as the host may not support it.'https://tomjn.com'
however works as expected – Tom J Nowell♦ Jan 4 '20 at 2:46wp_dependencies_unique_hosts
is, indeed, just a list of hosts without any scheme. I agree with your conclusion that WordPress is adding 'http' as the scheme when the scheme isn't already there. – GermanKiwi Jan 6 '20 at 23:03