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

Add storage for URL metrics to optimize image loading #878

Merged
Show file tree
Hide file tree
Changes from 58 commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
68a01be
Add initial REST API endpoint for storing page metrics
westonruter Nov 2, 2023
b4e29d6
Include url in PageMetrics and further define schema
westonruter Nov 2, 2023
ffcae75
Validate that the provided URL is for this site
westonruter Nov 2, 2023
1634fb9
Ensure both tagName and index are required
westonruter Nov 3, 2023
534eba2
Add initial storage locking to protect against flooding
westonruter Nov 3, 2023
ba30471
Update metrics storage locking
westonruter Nov 3, 2023
4e0d7de
Move storage helper functions into storage.php
westonruter Nov 3, 2023
ea6e28d
Add post type for page metrics storage
westonruter Nov 3, 2023
b7396c8
WIP
westonruter Nov 7, 2023
9d71951
Merge remote-tracking branch 'origin/feature/image-loading-optimizati…
westonruter Nov 7, 2023
0e5b79f
Fix storage and improve naming
westonruter Nov 7, 2023
739a53e
Use ILO consistently as the prefix
westonruter Nov 7, 2023
e4d1578
Segment page metrics by breakpoint and constrain sample size
westonruter Nov 7, 2023
2b1a15b
Improve function ordering
westonruter Nov 7, 2023
f516af8
Add ilo_get_page_metric_ttl
westonruter Nov 8, 2023
2f80461
Move lock functions into separate file
westonruter Nov 8, 2023
82f1d60
Reorganize functions into files
westonruter Nov 8, 2023
d2455e9
Use PHP 7 const
westonruter Nov 8, 2023
79bafac
Improve static analysis
westonruter Nov 8, 2023
c016494
Split out detection logic into separate include
westonruter Nov 8, 2023
7331ecb
Remove unused helper.php
westonruter Nov 8, 2023
5be9b99
Improve logging
westonruter Nov 8, 2023
a65d0be
Restore version constant
westonruter Nov 9, 2023
a17c9a2
Remove redundant plugin short-circuit
westonruter Nov 9, 2023
7f6cc2b
Remove superflous include file
westonruter Nov 9, 2023
7d5b2f5
Improve page metrics route
westonruter Nov 9, 2023
fb8837b
Update composer lockfile
westonruter Nov 9, 2023
80c6827
Pass object to detect() instead of positional args
westonruter Nov 9, 2023
f6208c2
Add description to ilo_get_page_metrics_breakpoint_sample_size and re…
westonruter Nov 9, 2023
fcf9acd
Add initial function to get normalized current URL
westonruter Nov 9, 2023
224ea51
Add function for normalizing query vars and getting current URL
westonruter Nov 10, 2023
dd9b375
Use current() instead of array_shift()
westonruter Nov 10, 2023
f9a1493
Use query vars instead of URL for computing slug; add HMAC
westonruter Nov 10, 2023
5dc6828
Use nonce instead of hmac
westonruter Nov 10, 2023
e0f2b68
Prevent collecting page metrics when sample size is full for all brea…
westonruter Nov 10, 2023
a6b7760
Fix function prefix in tests and self-assignment
westonruter Nov 13, 2023
f7aa73b
Fix filter for ilo_get_page_metric_freshness_ttl; reduce TTL from mon…
westonruter Nov 13, 2023
8eb0dbe
Add client-side and server-side checks for whether page metrics neede…
westonruter Nov 14, 2023
8c6b559
Remove unused ilo_get_current_url()
westonruter Nov 14, 2023
7e4064a
Improve testability of ilo_get_needed_minimum_viewport_widths()
westonruter Nov 14, 2023
a1f1aaa
Opt for sessionStorage for storage lock for aborting
westonruter Nov 14, 2023
53c5ef7
Merge branch 'feature/image-loading-optimization' of https://github.c…
westonruter Nov 14, 2023
acf17f9
Ensure grouped page metrics are sorted by timestamp before unshifting
westonruter Nov 14, 2023
6cd8198
Use microtime(true) instead of time()
westonruter Nov 14, 2023
9d6707c
Reduce code duplication with helper function
westonruter Nov 14, 2023
99ef299
Prevent optimizing search results and add ilo_can_optimize_response f…
westonruter Nov 14, 2023
8cb2dcf
Add TODO for ilo_get_normalized_query_vars
westonruter Nov 14, 2023
a4ffbae
Reference JSON Schema for defintion of function arg array shape
westonruter Nov 14, 2023
ec6e177
Add array type declarations
westonruter Nov 14, 2023
817d682
Add PHP type declarations
westonruter Nov 14, 2023
caaef87
Fix placement of ilo_breakpoint_max_widths filter
westonruter Nov 15, 2023
eadec55
Use 3rd person singular for function phpdoc
westonruter Nov 15, 2023
02dbb35
Use 3rd person singular in phpdoc for additional functions
westonruter Nov 15, 2023
06d7fad
Account for isStorageLocked with storageLockTTL of 0
westonruter Nov 15, 2023
da0b420
Ensure storage lock TTL is at least zero and add filter example
westonruter Nov 15, 2023
19ce752
Add since and access private tags
westonruter Nov 15, 2023
19a2c3b
Use IMAGE_LOADING_OPTIMIZATION_VERSION constant for script ver arg
westonruter Nov 15, 2023
f566663
Move error emitting to ilo_parse_stored_page_metrics()
westonruter Nov 15, 2023
b228934
Elaborate on return value phpdoc for ilo_get_page_metric_storage_lock…
westonruter Nov 15, 2023
95d9406
Remove overkill PHP 7.1+ type declaration comments
westonruter Nov 15, 2023
9876aa4
Rename 'page metrics' to 'URL metrics'
westonruter Nov 15, 2023
82b6210
Remove unnecessary curly braces
westonruter Nov 15, 2023
1168a5a
Rename filter to ilo_url_metric_storage_lock_ttl
westonruter Nov 15, 2023
698d89f
Follow AIP-136
westonruter Nov 15, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions admin/server-timing.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function perflab_add_server_timing_page() {
* @since 2.6.0
*/
function perflab_load_server_timing_page() {
if ( ! has_filter( 'template_include', 'image_loading_optimization_buffer_output' ) ) {
if ( ! has_filter( 'template_include', 'ilo_buffer_output' ) ) {
/*
* This settings section technically includes a field, however it is directly rendered as part of the section
* callback due to requiring custom markup.
Expand Down Expand Up @@ -95,7 +95,7 @@ static function () {
);
?>
</p>
<?php if ( ! perflab_server_timing_use_output_buffer() && ! has_filter( 'template_include', 'image_loading_optimization_buffer_output' ) ) : ?>
<?php if ( ! perflab_server_timing_use_output_buffer() && ! has_filter( 'template_include', 'ilo_buffer_output' ) ) : ?>
<p>
<?php
echo wp_kses(
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
},
"require": {
"composer/installers": "~1.0",
"php": ">=7|^8"
"php": ">=7|^8",
"ext-json": "*"
},
"scripts": {
"phpstan": "phpstan analyze --ansi --memory-limit=2048M",
Expand Down
73 changes: 39 additions & 34 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

69 changes: 69 additions & 0 deletions modules/images/image-loading-optimization/detection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php
/**
* Detection for image loading optimization.
*
* @package performance-lab
* @since n.e.x.t
*/

felixarntz marked this conversation as resolved.
Show resolved Hide resolved
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}

/**
* Prints the script for detecting loaded images and the LCP element.
*
* @since n.e.x.t
* @access private
*/
function ilo_print_detection_script() /*: void (in PHP 7.1) */ {
if ( ! ilo_can_optimize_response() ) {
return;
}

$query_vars = ilo_get_normalized_query_vars();
$slug = ilo_get_page_metrics_slug( $query_vars );
$microtime = microtime( true );

// Abort if we already have all the sample size we need for all breakpoints.
$needed_minimum_viewport_widths = ilo_get_needed_minimum_viewport_widths_now_for_slug( $slug );
if ( ! ilo_needs_page_metric_for_breakpoint( $needed_minimum_viewport_widths ) ) {
return;
}

/**
* Filters the time window between serve time and run time in which loading detection is allowed to run.
*
* Allow this amount of milliseconds between when the page was first generated (and perhaps cached) and when the
* detect function on the page is allowed to perform its detection logic and submit the request to store the results.
* This avoids situations in which there is missing detection metrics in which case a site with page caching which
* also has a lot of traffic could result in a cache stampede.
*
* @since n.e.x.t
* @todo The value should probably be something like the 99th percentile of Time To Last Byte (TTLB) for WordPress sites in CrUX.
*
* @param int $detection_time_window Detection time window in milliseconds.
*/
$detection_time_window = apply_filters( 'perflab_image_loading_detection_time_window', 5000 );

$detect_args = array(
'serveTime' => $microtime * 1000, // In milliseconds for comparison with `Date.now()` in JavaScript.
'detectionTimeWindow' => $detection_time_window,
'isDebug' => WP_DEBUG,
'restApiEndpoint' => rest_url( ILO_REST_API_NAMESPACE . ILO_PAGE_METRICS_ROUTE ),
'restApiNonce' => wp_create_nonce( 'wp_rest' ),
'pageMetricsSlug' => $slug,
'pageMetricsNonce' => ilo_get_page_metrics_storage_nonce( $slug ),
'neededMinimumViewportWidths' => $needed_minimum_viewport_widths,
'storageLockTTL' => ilo_get_page_metric_storage_lock_ttl(),
);
wp_print_inline_script_tag(
sprintf(
'import detect from %s; detect( %s );',
wp_json_encode( add_query_arg( 'ver', IMAGE_LOADING_OPTIMIZATION_VERSION, plugin_dir_url( __FILE__ ) . 'detection/detect.js' ) ),
wp_json_encode( $detect_args )
),
array( 'type' => 'module' )
);
}
add_action( 'wp_print_footer_scripts', 'ilo_print_detection_script' );
Loading