Last active
July 24, 2024 19:27
-
-
Save westonruter/456afa3cbf29563ffd590401988f1a23 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Optimize Content Hero Image WordPress Plugin. | |
* | |
* @package OptimizeContentHeroImage | |
* @author Weston Ruter, Google | |
* @license GPL-2.0-or-later | |
* @copyright 2023 Google Inc. | |
* | |
* @wordpress-plugin | |
* Plugin Name: Optimize Content Hero Image | |
* Description: When using a non-standard template system (e.g. Timber), the logic in <code>wp_get_loading_optimization_attributes()</code> may not work properly. This ensures that the first content images are not lazy-loaded and the largest is given <code>fetchpriority=high</code>. See <a href="https://core.trac.wordpress.org/ticket/59331">#59331</a> for how this might be fixed in WordPress Core. | |
* Plugin URI: https://gist.github.com/westonruter/456afa3cbf29563ffd590401988f1a23 | |
* Version: 0.1.1 | |
* Author: Weston Ruter | |
* Author URI: https://weston.ruter.net/ | |
* License: GNU General Public License v2 (or later) | |
* License URI: http://www.gnu.org/licenses/gpl-2.0.html | |
* Update URI: https://gist.github.com/westonruter/456afa3cbf29563ffd590401988f1a23 | |
*/ | |
namespace OptimizeContentHeroImage; | |
use WP_HTML_Tag_Processor; | |
const FILTER_PRIORITY = 100; | |
/** | |
* Optimize content images. | |
* | |
* @param string $content String | |
* @return string Optimized content. | |
*/ | |
function optimize_content_images( string $content ): string { | |
// Ensure only the first post is processed. | |
remove_filter( 'the_content', __NAMESPACE__ . '\optimize_content_images', FILTER_PRIORITY ); | |
$p = new WP_HTML_Tag_Processor( $content ); | |
$tag_counts = []; | |
$hero_candidate_count = 0; | |
$hero_candidates = []; | |
while ( $p->next_tag() ) { | |
$tag_name = $p->get_tag(); | |
if ( ! isset( $tag_counts[ $tag_name ] ) ) { | |
$tag_counts[ $tag_name ] = 1; | |
} else { | |
$tag_counts[ $tag_name ]++; | |
} | |
// Once the second paragraph is encountered, stop optimizing images. | |
if ( 'P' === $tag_name && $tag_counts[ $tag_name ] > 1 ) { | |
break; | |
} | |
if ( $tag_name === 'IMG' ) { | |
// Stop optimizing after the 5th image. | |
if ( $tag_counts[ $tag_name ] > 5 ) { | |
break; | |
} | |
// Prevent lazy-loading. | |
$p->remove_attribute( 'loading' ); | |
// Add fetchpriority=high if hero. | |
$width = (int) $p->get_attribute( 'width' ); | |
$height = (int) $p->get_attribute( 'height' ); | |
$size = $width * $height; | |
if ( $size >= 50000 ) { // Number comes from wp_min_priority_img_pixels in core. | |
$hero_candidate_count++; | |
$bookmark_name = "hero_candidate_{$hero_candidate_count}"; | |
$p->set_bookmark( $bookmark_name ); | |
$hero_candidates[ $bookmark_name ] = $size; | |
} | |
} | |
} | |
// Add fetchpriority=high to the largest hero candidate. | |
if ( count( $hero_candidates ) > 0 ) { | |
arsort( $hero_candidates, SORT_NUMERIC ); | |
$bookmark_name = key( $hero_candidates ); | |
$p->seek( $bookmark_name ); | |
$p->set_attribute( 'fetchpriority', 'high' ); | |
} | |
return $p->get_updated_html(); | |
} | |
add_filter( 'the_content', __NAMESPACE__ . '\optimize_content_images', FILTER_PRIORITY ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment