Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send preload links via HTTP Link headers in addition to LINK tags #1323

Merged
merged 10 commits into from
Jul 8, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,27 @@ static function ( array $carry, array $link ): array {
);
}

/**
* Adds media features to the links.
*
* @phpstan-param Link $link
* @param array $link Link array.
* @phpstan-return Link
* @return array Link array with media features added.
AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved
*/
private function add_media_features( array $link ): array {
$media_features = array( 'screen' );
if ( null !== $link['minimum_viewport_width'] && $link['minimum_viewport_width'] > 0 ) {
$media_features[] = sprintf( '(min-width: %dpx)', $link['minimum_viewport_width'] );
}
if ( null !== $link['maximum_viewport_width'] && PHP_INT_MAX !== $link['maximum_viewport_width'] ) {
$media_features[] = sprintf( '(max-width: %dpx)', $link['maximum_viewport_width'] );
}
$link['attributes']['media'] = implode( ' and ', $media_features );

return (array) $link;
}
AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved

/**
* Gets the HTML for the link tags.
*
Expand All @@ -145,14 +166,7 @@ public function get_html(): string {
$link_tags = array();

foreach ( $this->get_adjacent_deduplicated_links() as $link ) {
$media_features = array( 'screen' );
if ( null !== $link['minimum_viewport_width'] && $link['minimum_viewport_width'] > 0 ) {
$media_features[] = sprintf( '(min-width: %dpx)', $link['minimum_viewport_width'] );
}
if ( null !== $link['maximum_viewport_width'] && PHP_INT_MAX !== $link['maximum_viewport_width'] ) {
$media_features[] = sprintf( '(max-width: %dpx)', $link['maximum_viewport_width'] );
}
$link['attributes']['media'] = implode( ' and ', $media_features );
$link = $this->add_media_features( (array) $link );
AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved

$link_tag = '<link data-od-added-tag rel="preload"';
foreach ( $link['attributes'] as $name => $value ) {
Expand All @@ -167,32 +181,28 @@ public function get_html(): string {
}

/**
* Gets the HTTP Link header string.
* Constructs the Link HTTP response header.
*
* @return string HTTP Link header.
* @return string|null Link HTTP response header, or null if there are none.
*/
public function get_headers(): string {
public function get_response_header(): ?string {
$link_headers = array();

foreach ( $this->get_adjacent_deduplicated_links() as $link ) {
AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved
$media_features = array( 'screen' );
if ( null !== $link['minimum_viewport_width'] && $link['minimum_viewport_width'] > 0 ) {
$media_features[] = sprintf( '(min-width: %dpx)', $link['minimum_viewport_width'] );
}
if ( null !== $link['maximum_viewport_width'] && PHP_INT_MAX !== $link['maximum_viewport_width'] ) {
$media_features[] = sprintf( '(max-width: %dpx)', $link['maximum_viewport_width'] );
}
$link['attributes']['media'] = implode( ' and ', $media_features );
$link = $this->add_media_features( (array) $link );

$link_header = '<' . esc_url( $link['attributes']['href'] ?? '' ) . '>; rel="preload"';
$link_header = '<' . esc_url_raw( $link['attributes']['href'] ?? '' ) . '>; rel="preload"';
AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved
foreach ( $link['attributes'] as $name => $value ) {
if ( 'href' !== $name ) {
$link_header .= sprintf( '; %s="%s"', $name, esc_attr( $value ) );
$link_header .= sprintf( '; %s="%s"', $name, rawurlencode( $value ) );
}
}

$link_headers[] = $link_header;
}
if ( count( $link_headers ) === 0 ) {
return null;
}

AhmarZaidi marked this conversation as resolved.
Show resolved Hide resolved
return 'Link: ' . implode( ', ', $link_headers );
}
Expand Down
11 changes: 5 additions & 6 deletions plugins/optimization-detective/optimization.php
Original file line number Diff line number Diff line change
Expand Up @@ -164,11 +164,6 @@ function od_optimize_template_output_buffer( string $buffer ): string {

$tag_visitor_registry = new OD_Tag_Visitor_Registry();

// Send any preload links as Link headers.
if ( count( $preload_links ) > 0 && ! headers_sent() ) {
header( $preload_links->get_headers() );
}

/**
* Fires to register tag visitors before walking over the document to perform optimizations.
*
Expand All @@ -194,8 +189,12 @@ function od_optimize_template_output_buffer( string $buffer ): string {
$generator->next();
}

// Inject any preload links at the end of the HEAD.
// Send any preload links in a Link response header and in a LINK tag injected at the end of the HEAD.
if ( count( $preload_links ) > 0 ) {
$response_header_links = $preload_links->get_response_header();
if ( ! is_null( $response_header_links ) && ! headers_sent() ) {
header( $response_header_links, false );
}
$walker->append_head_html( $preload_links->get_html() );
}

Expand Down
Loading