data-hero for Amp Optimizer
-
I don’t know if it would make a difference, but I’m trying to reduce my LCP times. I notice the Amp Optimizer documentation has a data-hero option for hero images. It’s also supposed to autodetect hero images and add rel=preload to the image src. Is there any way to add data-hero to hero images, or have it autodetected on the first image?
The page I need help with: [log in to see the link]
-
Yes, hero image prerendering should greatly improve LCP.
The hero image optimization there isn’t yet in the lastest release (2.0.10). It is available however in the develop branch (2.1-alpha). If you are willing to test a prerelease build, you can find it at https://github.com/ampproject/amp-wp/wiki/Development-Builds
Note there is one issue I’ve identified related to this: https://github.com/ampproject/amp-wp/issues/5824
However, if you are manually adding
data-hero
to the desired image then this won’t be an issue for you, as it’s only related to automatic detection.A fellow photographer’s site is using 2.1-alpha as well.
I think I might be running into the bug you mentioned or something else. It seems to add data-hero to an image way down the page but it skips my first image and some other main images on the page. I also notice this in the code
AMP optimization could not be completed due to the following: - CannotPreloadImage: Not preloading the hero image because of the presence of a "srcset" attribute, which can currently only be preloaded by Chromium-based browsers (see https://web.dev/preload-responsive-images/). <amp-img width="900" height="600" src="https://www.ryansmithphotography.com/wp-content/uploads/2021/01/holding-hands-un…>
Is there a way to add data hero to a wordpress block image, or would I have to do that with just html code in a block? You can check it out on the page I mentioned before I’m running the alpha now.
I also notice if I try to edit a page I get the following error, however creating a new page works.
TypeError: Cannot read property 'type' of null at v (https://www.ryansmithphotography.com/wp-content/plugins/amp/assets/js/amp-block-editor.js?ver=401ab3f2d960ecfe6233b84afa6650f8:13:5950) at https://www.ryansmithphotography.com/wp-includes/js/dist/hooks.min.js?ver=84b89ab09cbfb4469f02183611cc0939:2:5031 at Qt (https://www.ryansmithphotography.com/wp-includes/js/dist/blocks.min.js?ver=f4636ab86bbcd1d9adb613a053f522e7:3:114677) at https://www.ryansmithphotography.com/wp-includes/js/dist/block-editor.min.js?ver=ee2642fa39827fa8f0de00446089caf1:12:277174 at we (https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:84:293) at zj (https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:226:496) at Th (https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:152:223) at tj (https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:152:152) at Te (https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:146:151) at https://www.ryansmithphotography.com/wp-includes/js/dist/vendor/react-dom.min.js?ver=16.13.1:61:68
- This reply was modified 3 years, 9 months ago by rsmith4321.
I think I might be running into the bug you mentioned or something else. It seems to add data-hero to an image way down the page but it skips my first image and some other main images on the page.
Yes, most likely this is the same issue.
I also notice this in the code
This is normal. And actually, the preload link is going to be eliminated entirely from the optimizer because it is not reliable to detect which image should be preloaded regardless of srcset/sizes: https://github.com/ampproject/amp-toolbox/pull/1132, https://github.com/ampproject/amp-toolbox-php/issues/55
So you can ignore that.
Is there a way to add data hero to a wordpress block image, or would I have to do that with just html code in a block? You can check it out on the page I mentioned before I’m running the alpha now.
This will be automatically handled by https://github.com/ampproject/amp-wp/issues/5824 as well. However, in the meantime you can manually insert
data-hero
with plugin code like this:add_filter( 'render_block', function( $block_content, $block ) { static $added = false; if ( $added || 'core/image' !== $block['blockName'] ) { return $block_content; } $block_content = preg_replace( '/(?<=<img\s)/', 'data-hero ', $block_content, 1, $count ); if ( 0 !== $count ) { $added = true; } return $block_content; }, 10, 2 );
I also notice if I try to edit a page I get the following error, however creating a new page works.
Could you please try with the “development build” as opposed to the “production build”? This will show the error stack trace without minification.
We just merged a PR which should fix the JS error you encountered in the block editor. If you update to the latest 2.1-alpha build the issue should be resolved.
Great, I just tried it and I can edit pages now. I had to deactivate the alpha before because of this issue, but I think I will leave it running now. If you want to check it out you can it’s live now at https://www.ryansmithphotography.com. It still adds the data-hero to an image way down the page instead of the first image. I’m going to try the manual code you gave me and see if I can get that working.
Yeah, the issue with the incorrect
data-hero
placement is not yet resolved. Manually adding it will be your best bet for now, and it ensures you only the intended image(s) get pre-rendered.I see you also have a custom logo. So you should also add the
data-hero
attribute as well:add_filter( 'get_custom_logo_image_attributes', function ( $atts ) { $atts['data-hero'] = ''; return $atts; } );
You can have up to 2 images marked with
data-hero
on the page. Anything after that will be ignored for prerendering.Please let me know when you’ve added the
data-hero
attribute. I’m eager to see the improvement.I added the above code just as is. I didn’t know if I was supposed to change the ‘blockName’ to something else? But it did seem to add the data-hero to the first image on my page. I did a test on Pagespeed insights and it lowered my lcp by .5s on the mobile test. I’m not sure how it’s doing that but that is great!
I tried the code for the logo that doesn’t seem to be working for me.
- This reply was modified 3 years, 9 months ago by rsmith4321.
- This reply was modified 3 years, 9 months ago by rsmith4321.
I added the above code just as is. I didn’t know if I was supposed to change the ‘blockName’ to something else?
No, the
blockName
should be left ascore/image
since it’s an Image block that you were targeting with the filter.I tried the code for the logo that doesn’t seem to be working for me.
Do you know how your logo is being added to the page? I assumed your template was using
the_custom_logo()
.It’s added in the customizer under the Header section for my Generatepress theme. But I don’t know exactly how it’s added. I have a feeling if I get my logo and my first image preloaded and everything else ignored it will improve my LCP time.
I will give you the code below for my header.php file in my theme.
<?php /** * Header elements. * * @package GeneratePress */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! function_exists( 'generate_construct_header' ) ) { add_action( 'generate_header', 'generate_construct_header' ); /** * Build the header. * * @since 1.3.42 */ function generate_construct_header() { ?> <header id="masthead" <?php generate_do_element_classes( 'header' ); ?>> <div <?php generate_do_element_classes( 'inside_header' ); ?>> <?php /** * generate_before_header_content hook. * * @since 0.1 */ do_action( 'generate_before_header_content' ); if ( ! generate_is_using_flexbox() ) { // Add our main header items. generate_header_items(); } /** * generate_after_header_content hook. * * @since 0.1 * * @hooked generate_add_navigation_float_right - 5 */ do_action( 'generate_after_header_content' ); ?> </div> </header> <?php } } if ( ! function_exists( 'generate_header_items' ) ) { /** * Build the header contents. * Wrapping this into a function allows us to customize the order. * * @since 1.2.9.7 */ function generate_header_items() { $order = apply_filters( 'generate_header_items_order', array( 'header-widget', 'site-branding', 'logo', ) ); foreach ( $order as $item ) { if ( 'header-widget' === $item ) { generate_construct_header_widget(); } if ( 'site-branding' === $item ) { generate_construct_site_title(); } if ( 'logo' === $item ) { generate_construct_logo(); } } } } if ( ! function_exists( 'generate_construct_logo' ) ) { /** * Build the logo * * @since 1.3.28 */ function generate_construct_logo() { $logo_url = ( function_exists( 'the_custom_logo' ) && get_theme_mod( 'custom_logo' ) ) ? wp_get_attachment_image_src( get_theme_mod( 'custom_logo' ), 'full' ) : false; $logo_url = ( $logo_url ) ? $logo_url[0] : generate_get_option( 'logo' ); $logo_url = esc_url( apply_filters( 'generate_logo', $logo_url ) ); $retina_logo_url = esc_url( apply_filters( 'generate_retina_logo', generate_get_option( 'retina_logo' ) ) ); // If we don't have a logo, bail. if ( empty( $logo_url ) ) { return; } /** * generate_before_logo hook. * * @since 0.1 */ do_action( 'generate_before_logo' ); $attr = apply_filters( 'generate_logo_attributes', array( 'class' => 'header-image is-logo-image', 'alt' => esc_attr( apply_filters( 'generate_logo_title', get_bloginfo( 'name', 'display' ) ) ), 'src' => $logo_url, 'title' => esc_attr( apply_filters( 'generate_logo_title', get_bloginfo( 'name', 'display' ) ) ), ) ); if ( '' !== $retina_logo_url ) { $attr['srcset'] = $logo_url . ' 1x, ' . $retina_logo_url . ' 2x'; // Add dimensions to image if retina is set. This fixes a container width bug in Firefox. if ( function_exists( 'the_custom_logo' ) && get_theme_mod( 'custom_logo' ) ) { $data = wp_get_attachment_metadata( get_theme_mod( 'custom_logo' ) ); if ( ! empty( $data ) ) { $attr['width'] = $data['width']; $attr['height'] = $data['height']; } } } elseif ( generate_is_using_flexbox() ) { // Add this to flexbox version only until we can verify it won't conflict with existing installs. if ( function_exists( 'the_custom_logo' ) && get_theme_mod( 'custom_logo' ) ) { $data = wp_get_attachment_metadata( get_theme_mod( 'custom_logo' ) ); if ( ! empty( $data ) ) { $attr['width'] = $data['width']; $attr['height'] = $data['height']; } } } $attr = array_map( 'esc_attr', $attr ); $html_attr = ''; foreach ( $attr as $name => $value ) { $html_attr .= " $name=" . '"' . $value . '"'; } // Print our HTML. echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped 'generate_logo_output', sprintf( '<div class="site-logo"> <a href="%1$s" title="%2$s" rel="home"> <img %3$s /> </a> </div>', esc_url( apply_filters( 'generate_logo_href', home_url( '/' ) ) ), esc_attr( apply_filters( 'generate_logo_title', get_bloginfo( 'name', 'display' ) ) ), $html_attr ), $logo_url, $html_attr ); /** * generate_after_logo hook. * * @since 0.1 */ do_action( 'generate_after_logo' ); } } if ( ! function_exists( 'generate_construct_site_title' ) ) { /** * Build the site title and tagline. * * @since 1.3.28 */ function generate_construct_site_title() { $generate_settings = wp_parse_args( get_option( 'generate_settings', array() ), generate_get_defaults() ); // Get the title and tagline. $title = get_bloginfo( 'title' ); $tagline = get_bloginfo( 'description' ); // If the disable title checkbox is checked, or the title field is empty, return true. $disable_title = ( '1' == $generate_settings['hide_title'] || '' == $title ) ? true : false; // phpcs:ignore // If the disable tagline checkbox is checked, or the tagline field is empty, return true. $disable_tagline = ( '1' == $generate_settings['hide_tagline'] || '' == $tagline ) ? true : false; // phpcs:ignore $schema_type = generate_get_schema_type(); // Build our site title. $site_title = apply_filters( 'generate_site_title_output', sprintf( '<%1$s class="main-title"%4$s> <a href="%2$s" rel="home"> %3$s </a> </%1$s>', ( is_front_page() && is_home() ) ? 'h1' : 'p', esc_url( apply_filters( 'generate_site_title_href', home_url( '/' ) ) ), get_bloginfo( 'name' ), 'microdata' === generate_get_schema_type() ? ' itemprop="headline"' : '' ) ); // Build our tagline. $site_tagline = apply_filters( 'generate_site_description_output', sprintf( '<p class="site-description"%2$s> %1$s </p>', html_entity_decode( get_bloginfo( 'description', 'display' ) ), // phpcs:ignore 'microdata' === generate_get_schema_type() ? ' itemprop="description"' : '' ) ); // Site title and tagline. if ( false === $disable_title || false === $disable_tagline ) { if ( generate_needs_site_branding_container() ) { echo '<div class="site-branding-container">'; generate_construct_logo(); } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- outputting site title and tagline. False positive. echo apply_filters( 'generate_site_branding_output', sprintf( '<div class="site-branding"> %1$s %2$s </div>', ( ! $disable_title ) ? $site_title : '', ( ! $disable_tagline ) ? $site_tagline : '' ) ); if ( generate_needs_site_branding_container() ) { echo '</div>'; } } } } add_filter( 'generate_header_items_order', 'generate_reorder_inline_site_branding' ); /** * Remove the logo from it's usual position. * * @since 2.3 * @param array $order Order of the header items. */ function generate_reorder_inline_site_branding( $order ) { if ( ! generate_get_option( 'inline_logo_site_branding' ) || ! generate_has_logo_site_branding() ) { return $order; } return array( 'header-widget', 'site-branding', ); } if ( ! function_exists( 'generate_construct_header_widget' ) ) { /** * Build the header widget. * * @since 1.3.28 */ function generate_construct_header_widget() { if ( is_active_sidebar( 'header' ) ) : ?> <div class="header-widget"> <?php dynamic_sidebar( 'header' ); ?> </div> <?php endif; } } add_action( 'generate_before_header_content', 'generate_do_site_logo', 5 ); /** * Add the site logo to our header. * Only added if we aren't using floats to preserve backwards compatibility. * * @since 3.0.0 */ function generate_do_site_logo() { if ( ! generate_is_using_flexbox() || generate_needs_site_branding_container() ) { return; } generate_construct_logo(); } add_action( 'generate_before_header_content', 'generate_do_site_branding' ); /** * Add the site branding to our header. * Only added if we aren't using floats to preserve backwards compatibility. * * @since 3.0.0 */ function generate_do_site_branding() { if ( ! generate_is_using_flexbox() ) { return; } generate_construct_site_title(); } add_action( 'generate_after_header_content', 'generate_do_header_widget' ); /** * Add the header widget to our header. * Only used when grid isn't using floats to preserve backwards compatibility. * * @since 3.0.0 */ function generate_do_header_widget() { if ( ! generate_is_using_flexbox() ) { return; } generate_construct_header_widget(); } if ( ! function_exists( 'generate_top_bar' ) ) { add_action( 'generate_before_header', 'generate_top_bar', 5 ); /** * Build our top bar. * * @since 1.3.45 */ function generate_top_bar() { if ( ! is_active_sidebar( 'top-bar' ) ) { return; } $inside_top_bar_class = ''; if ( 'contained' === generate_get_option( 'top_bar_inner_width' ) ) { $inside_top_bar_class = ' grid-container grid-parent'; if ( generate_is_using_flexbox() ) { $inside_top_bar_class = ' grid-container'; } } ?> <div <?php generate_do_element_classes( 'top_bar' ); ?>> <div class="inside-top-bar<?php echo $inside_top_bar_class; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- False positive. ?>"> <?php dynamic_sidebar( 'top-bar' ); ?> </div> </div> <?php } } if ( ! function_exists( 'generate_pingback_header' ) ) { add_action( 'wp_head', 'generate_pingback_header' ); /** * Add a pingback url auto-discovery header for singularly identifiable articles. * * @since 1.3.42 */ function generate_pingback_header() { if ( is_singular() && pings_open() ) { printf( '<link rel="pingback" href="%s">' . "\n", esc_url( get_bloginfo( 'pingback_url' ) ) ); } } } if ( ! function_exists( 'generate_add_viewport' ) ) { add_action( 'wp_head', 'generate_add_viewport' ); /** * Add viewport to wp_head. * * @since 1.1.0 */ function generate_add_viewport() { echo apply_filters( 'generate_meta_viewport', '<meta name="viewport" content="width=device-width, initial-scale=1">' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped } } add_action( 'generate_before_header', 'generate_do_skip_to_content_link', 2 ); /** * Add skip to content link before the header. * * @since 2.0 */ function generate_do_skip_to_content_link() { printf( '<a class="screen-reader-text skip-link" href="#content" title="%1$s">%2$s</a>', esc_attr__( 'Skip to content', 'generatepress' ), esc_html__( 'Skip to content', 'generatepress' ) ); }
- This reply was modified 3 years, 9 months ago by rsmith4321.
I’m not familiar with Generatepress, but from the code you provided it appears you can just use the
generate_logo_attributes
filter instead ofget_custom_logo_image_attributes
. So I believe this will work:add_filter( 'generate_logo_attributes', function ( $atts ) { $atts['data-hero'] = ''; return $atts; } );
Great, that all seems to be working correctly now. One other thing, I notice featured images in blog posts still do not have data-hero added, but I think that is what you are working on already. But if you want to see an example you can here https://www.ryansmithphotography.com/blog/2021/01/16/maternity-portraits-caledonia-golf-2021/
- This reply was modified 3 years, 9 months ago by rsmith4321.
Nice, I’m seeing your homepage with a PSI score of 92 now for mobile and 99 for desktop.
For the featured image, what is the code your theme template is using to render onto the page?
The PSI LCP mobile speed is frustrating because it appears to be just the size of my main image and the limited bandwidth of the mobile test. I have a srcset on the image and it’s a webp, so I just don’t know what else Google can expect. Here is the featured image code.
<?php /** * Featured image elements. * * @package GeneratePress */ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } if ( ! function_exists( 'generate_post_image' ) ) { add_action( 'generate_after_entry_header', 'generate_post_image' ); /** * Prints the Post Image to post excerpts */ function generate_post_image() { // If there's no featured image, return. if ( ! has_post_thumbnail() ) { return; } // If we're not on any single post/page or the 404 template, we must be showing excerpts. if ( ! is_singular() && ! is_404() ) { $attrs = array(); if ( 'microdata' === generate_get_schema_type() ) { $attrs = array( 'itemprop' => 'image', ); } echo apply_filters( // phpcs:ignore 'generate_featured_image_output', sprintf( '<div class="post-image"> %3$s <a href="%1$s"> %2$s </a> </div>', esc_url( get_permalink() ), get_the_post_thumbnail( get_the_ID(), apply_filters( 'generate_page_header_default_size', 'full' ), $attrs ), apply_filters( 'generate_inside_featured_image_output', '' ) ) ); } } } if ( ! function_exists( 'generate_featured_page_header_area' ) ) { /** * Build the page header. * * @since 1.0.7 * * @param string $class The featured image container class. */ function generate_featured_page_header_area( $class ) { // Don't run the function unless we're on a page it applies to. if ( ! is_singular() ) { return; } // Don't run the function unless we have a post thumbnail. if ( ! has_post_thumbnail() ) { return; } $attrs = array(); if ( 'microdata' === generate_get_schema_type() ) { $attrs = array( 'itemprop' => 'image', ); } ?> <div class="featured-image <?php echo esc_attr( $class ); ?> grid-container grid-parent"> <?php the_post_thumbnail( apply_filters( 'generate_page_header_default_size', 'full' ), $attrs ); ?> </div> <?php } } if ( ! function_exists( 'generate_featured_page_header' ) ) { add_action( 'generate_after_header', 'generate_featured_page_header', 10 ); /** * Add page header above content. * * @since 1.0.2 */ function generate_featured_page_header() { if ( function_exists( 'generate_page_header' ) ) { return; } if ( is_page() ) { generate_featured_page_header_area( 'page-header-image' ); } } } if ( ! function_exists( 'generate_featured_page_header_inside_single' ) ) { add_action( 'generate_before_content', 'generate_featured_page_header_inside_single', 10 ); /** * Add post header inside content. * Only add to single post. * * @since 1.0.7 */ function generate_featured_page_header_inside_single() { if ( function_exists( 'generate_page_header' ) ) { return; } if ( is_single() ) { generate_featured_page_header_area( 'page-header-image-single' ); } } }
- The topic ‘data-hero for Amp Optimizer’ is closed to new replies.