PluginProbe
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder / trunk
aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder vtrunk
2.12.0 2.11.1 2.11.0 2.10.0 2.9.0 2.7.4 2.7.5 2.7.6 2.7.7 2.8.0 2.8.1 2.9.1 trunk 1.0 1.0-beta1 1.0-beta2 1.0-beta3 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 All 78 releases
ablocks / includes / performance / lcp-preload.php

lcp-preload.php in aBlocks – Gutenberg Blocks, User Dashboard Builder, Popup Builder, Form Builder & Animation Builder trunk, at includes/performance/lcp-preload.php

94 lines 2.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace ABlocks\Performance;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit;
6 }
7
8 use ABlocks\Helper;
9
10 /**
11 * Performance Suite — preload the likely LCP image.
12 *
13 * PageSpeed's "LCP request discovery" audit wants the largest above-the-fold
14 * image to be discoverable as early as possible. This scans a singular post's
15 * content for the first aBlocks image and emits a high-priority
16 * `<link rel="preload" as="image">` (with a responsive imagesrcset) in the
17 * <head>, so the browser starts fetching it before it parses the body.
18 *
19 * Opt-in via `perf_preload_lcp`. Scoped to singular views for v1.
20 */
21 class LcpPreload {
22
23 public static function init() {
24 if ( is_admin() ) {
25 return;
26 }
27 $enabled = (bool) apply_filters(
28 'ablocks/perf/perf_preload_lcp',
29 (bool) Helper::get_settings( 'perf_preload_lcp', true )
30 );
31 if ( ! $enabled ) {
32 return;
33 }
34 $self = new self();
35 add_action( 'wp_head', [ $self, 'print_preload' ], 2 );
36 }
37
38 public function print_preload() {
39 if ( ! is_singular() ) {
40 return;
41 }
42 $post = get_post();
43 if ( ! $post || false === strpos( (string) $post->post_content, 'wp:ablocks/image' ) ) {
44 return;
45 }
46
47 $image = $this->first_image_block( parse_blocks( $post->post_content ) );
48 if ( ! $image ) {
49 return;
50 }
51
52 $href = esc_url( $image['url'] );
53 $attrs = 'rel="preload" as="image" fetchpriority="high" href="' . $href . '"';
54
55 if ( ! empty( $image['id'] ) ) {
56 $srcset = wp_get_attachment_image_srcset( (int) $image['id'], 'full' );
57 if ( $srcset ) {
58 $sizes = wp_get_attachment_image_sizes( (int) $image['id'], 'full' );
59 $attrs .= ' imagesrcset="' . esc_attr( $srcset ) . '"';
60 if ( $sizes ) {
61 $attrs .= ' imagesizes="' . esc_attr( $sizes ) . '"';
62 }
63 }
64 }
65
66 echo "<link {$attrs}>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
67 }
68
69 /**
70 * Depth-first search for the first aBlocks image block that carries a URL.
71 * Returns [ 'url' => …, 'id' => … ] or null.
72 */
73 private function first_image_block( $blocks ) {
74 foreach ( $blocks as $block ) {
75 if ( ! empty( $block['blockName'] ) && 'ablocks/image' === $block['blockName'] ) {
76 $url = $block['attrs']['imgUrl'] ?? '';
77 if ( $url && 0 !== strpos( $url, 'ablocks_dc:' ) ) {
78 return [
79 'url' => $url,
80 'id' => $block['attrs']['imgId'] ?? 0,
81 ];
82 }
83 }
84 if ( ! empty( $block['innerBlocks'] ) ) {
85 $found = $this->first_image_block( $block['innerBlocks'] );
86 if ( $found ) {
87 return $found;
88 }
89 }
90 }
91 return null;
92 }
93 }
94