最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - Change dns-prefetch to preconnect with correct protocol

programmeradmin2浏览0评论

I have this function in my functions.php file:

function dns_prefetch_to_preconnect( $urls, $relation_type ) {
    if ( 'dns-prefetch' === $relation_type ) {
        $urls = [];
    }

    if ( 'preconnect' === $relation_type ) {
        $urls = wp_dependencies_unique_hosts();
    }

    return $urls;
}
add_filter( 'wp_resource_hints', 'dns_prefetch_to_preconnect', 0, 2 );

It takes the URLs defined in wp_dependencies_unique_hosts() – which WordPress by default assigns to the dns-prefetch link tag – and reassigns them to the preconnect link tag. The function was provided to me here:

Change dns-prefetch to preconnect for external enqueued resources

However, this function isn't working entirely correctly. It adds the preconnect URLs using http instead of https.

Example: when I'm not using the above function, WordPress adds this link to my header:

<link rel='dns-prefetch' href='//fonts.googleapis' />

And when I enable the above function, it replaces that link with this link:

<link rel='preconnect' href='' />

The problem, of course, is that it should be https, not http.

Can someone help me modify my function so that it gives me https links?

I have this function in my functions.php file:

function dns_prefetch_to_preconnect( $urls, $relation_type ) {
    if ( 'dns-prefetch' === $relation_type ) {
        $urls = [];
    }

    if ( 'preconnect' === $relation_type ) {
        $urls = wp_dependencies_unique_hosts();
    }

    return $urls;
}
add_filter( 'wp_resource_hints', 'dns_prefetch_to_preconnect', 0, 2 );

It takes the URLs defined in wp_dependencies_unique_hosts() – which WordPress by default assigns to the dns-prefetch link tag – and reassigns them to the preconnect link tag. The function was provided to me here:

Change dns-prefetch to preconnect for external enqueued resources

However, this function isn't working entirely correctly. It adds the preconnect URLs using http instead of https.

Example: when I'm not using the above function, WordPress adds this link to my header:

<link rel='dns-prefetch' href='//fonts.googleapis' />

And when I enable the above function, it replaces that link with this link:

<link rel='preconnect' href='http://fonts.googleapis' />

The problem, of course, is that it should be https, not http.

Can someone help me modify my function so that it gives me https links?

Share Improve this question edited Jan 4, 2020 at 17:40 GermanKiwi asked Jan 4, 2020 at 0:08 GermanKiwiGermanKiwi 5511 bronze badges 4
  • My understanding is that the hosts returned by wp_dependencies_unique_hosts are just hosts, they aren't URLs and don't have a schema. Have you confirmed it is indeed http:// 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 Commented Jan 4, 2020 at 1:55
  • I tried your code and all that happened was the dns prefetch tags dissapeared, wp_dependencies_unique_hosts returned no hosts – Tom J Nowell Commented Jan 4, 2020 at 2:43
  • Indeed I believe my suspicion is correct, if you pass a naked domain such as 'tomjn' it will prefix it with http:// as it doesn't know what the correct schema is, and it can't use https:// as the host may not support it. 'https://tomjn' however works as expected – Tom J Nowell Commented Jan 4, 2020 at 2:46
  • Yes, you're quite right - wp_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 Commented Jan 6, 2020 at 23:03
Add a comment  | 

2 Answers 2

Reset to default 1

The problem is not that the function you're using adds http:, the problem is it adds no URL schema at all!

As a result, WP needs to add a URL schema to turn the host into a URL, and so it uses http://. It has no way of knowing what the original was, or if the host supports HTTPS, so http:// is the safe bet.

If however you passed the array with URL schema added, it would be passed through without issue.

Something like this may do the trick:

$hosts = wp_dependencies_unique_hosts();
$urls = array_map( function( $host ) {
    return set_url_scheme( $host, 'https' );
}, $hosts );

In the longrun though, it would be better to get the actual URLs and distill the host URL out of them, rather than relying on wp_dependencies_unique_hosts if you wanted to preserve the mixture of http and https

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 );
发布评论

评论列表(0)

  1. 暂无评论