From 0c88edf1230e6d9ec3384f954d96e000d6a76d1c Mon Sep 17 00:00:00 2001 From: Aditya Dhade Date: Fri, 22 Aug 2025 00:40:01 +0530 Subject: [PATCH 01/16] Show notice when enabling authenticated speculative loading without persistent object cache --- plugins/speculation-rules/settings.php | 66 ++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 4 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 9cdba8fc7e..1ee45fed7b 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -163,7 +163,7 @@ function plsr_register_setting(): void { 'enum' => array_keys( plsr_get_eagerness_labels() ), ), 'authentication' => array( - 'description' => __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + 'description' => __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), 'type' => 'string', 'enum' => array_keys( plsr_get_authentication_labels() ), ), @@ -211,7 +211,11 @@ static function (): void { ), 'authentication' => array( 'title' => __( 'User Authentication Status', 'speculation-rules' ), - 'description' => __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + 'description' => sprintf( + /* translators: %s: URL to persistent object cache documentation */ + __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' + ), ), ); foreach ( $fields as $slug => $args ) { @@ -262,14 +266,38 @@ function plsr_render_settings_field( array $args ): void { return; // @codeCoverageIgnore } - $value = $option[ $args['field'] ]; + $value = $option[ $args['field'] ]; + $has_object_cache = wp_using_ext_object_cache(); + $authenticated_options = array( 'logged_out_and_admins', 'any' ); + $show_warning = 'authentication' === $args['field'] && ! $has_object_cache && in_array( $value, $authenticated_options, true ); ?> + + +
> +

+ + %s', + 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching', + esc_html__( 'persistent object cache', 'speculation-rules' ) + ) + ); + ?> +

+
+ +
$label ) : ?>

- + array( + 'href' => array(), + 'target' => array(), + ), + ) + ); + ?>

+ + + + Date: Fri, 22 Aug 2025 16:56:25 +0530 Subject: [PATCH 02/16] Use safer JSON encoding flags for inline JavaScript Co-authored-by: Weston Ruter --- plugins/speculation-rules/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 1ee45fed7b..c540dff87c 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -328,7 +328,7 @@ class="plsr-auth-radio" ( function () { const authRadios = document.querySelectorAll( '.plsr-auth-radio' ); const warningDiv = document.getElementById( 'plsr-auth-warning' ); - const authenticatedOptions = ; + const authenticatedOptions = ; if ( ! authRadios.length || ! warningDiv ) { return; From 33eee8ecfb996c8cebc8b2da4f54a166137fd3bf Mon Sep 17 00:00:00 2001 From: Aditya Dhade Date: Fri, 22 Aug 2025 18:31:25 +0530 Subject: [PATCH 03/16] Make notice persistent to eliminate layout shifts --- plugins/speculation-rules/settings.php | 100 ++++++++++++++----------- 1 file changed, 57 insertions(+), 43 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index c540dff87c..3a2e36684e 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -267,37 +267,17 @@ function plsr_render_settings_field( array $args ): void { } $value = $option[ $args['field'] ]; - $has_object_cache = wp_using_ext_object_cache(); $authenticated_options = array( 'logged_out_and_admins', 'any' ); - $show_warning = 'authentication' === $args['field'] && ! $has_object_cache && in_array( $value, $authenticated_options, true ); + $show_notice = 'authentication' === $args['field'] && ! wp_using_ext_object_cache(); + $show_warning = $show_notice && in_array( $value, $authenticated_options, true ); ?> - - -
> -

- - %s', - 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching', - esc_html__( 'persistent object cache', 'speculation-rules' ) - ) - ); - ?> -

-
- -
$label ) : ?>

+ + +
+

+ > + persistent object cache before enabling this feature for logged-in users.', 'speculation-rules' ), + 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' + ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), + ), + ) + ); + ?> +

+
+
- - - - + 'module' ) + ); + } } /** From 6969eaeddc6ec24b45cd6a06400593ccdd6b48b9 Mon Sep 17 00:00:00 2001 From: Aditya Dhade Date: Fri, 22 Aug 2025 18:56:34 +0530 Subject: [PATCH 04/16] Add helper function to eliminate duplicate translation strings --- plugins/speculation-rules/settings.php | 40 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 3a2e36684e..4f7d22c035 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -56,6 +56,30 @@ function plsr_get_authentication_labels(): array { ); } +/** + * Returns translated description strings for settings fields. + * + * @since n.e.x.t + * + * @param string $field The field name to get description for. + * @param bool $strip_tags Whether to strip HTML tags from the description. + * @return string The translated description string. + */ +function plsr_get_field_description( string $field, bool $strip_tags = false ): string { + $descriptions = array( + 'mode' => __( 'Prerendering will lead to faster load times than prefetching. However, in case of interactive content, prefetching may be a safer choice.', 'speculation-rules' ), + 'eagerness' => __( 'The eagerness setting defines the heuristics based on which the loading is triggered. "Eager" will have the minimum delay to start speculative loads, "Conservative" increases the chance that only URLs the user actually navigates to are loaded.', 'speculation-rules' ), + 'authentication' => sprintf( + /* translators: %s: URL to persistent object cache documentation */ + __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' + ), + ); + $description = $descriptions[ $field ] ?? ''; + + return $strip_tags ? wp_strip_all_tags( $description ) : $description; +} + /** * Returns the default setting value for Speculative Loading configuration. * @@ -153,17 +177,17 @@ function plsr_register_setting(): void { 'type' => 'object', 'properties' => array( 'mode' => array( - 'description' => __( 'Whether to prefetch or prerender URLs.', 'speculation-rules' ), + 'description' => plsr_get_field_description( 'mode', true ), 'type' => 'string', 'enum' => array_keys( plsr_get_mode_labels() ), ), 'eagerness' => array( - 'description' => __( 'The eagerness setting defines the heuristics based on which the loading is triggered. "Eager" will have the minimum delay to start speculative loads, "Conservative" increases the chance that only URLs the user actually navigates to are loaded.', 'speculation-rules' ), + 'description' => plsr_get_field_description( 'eagerness', true ), 'type' => 'string', 'enum' => array_keys( plsr_get_eagerness_labels() ), ), 'authentication' => array( - 'description' => __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + 'description' => plsr_get_field_description( 'authentication', true ), 'type' => 'string', 'enum' => array_keys( plsr_get_authentication_labels() ), ), @@ -203,19 +227,15 @@ static function (): void { $fields = array( 'mode' => array( 'title' => __( 'Speculation Mode', 'speculation-rules' ), - 'description' => __( 'Prerendering will lead to faster load times than prefetching. However, in case of interactive content, prefetching may be a safer choice.', 'speculation-rules' ), + 'description' => plsr_get_field_description( 'mode' ), ), 'eagerness' => array( 'title' => __( 'Eagerness', 'speculation-rules' ), - 'description' => __( 'The eagerness setting defines the heuristics based on which the loading is triggered. "Eager" will have the minimum delay to start speculative loads, "Conservative" increases the chance that only URLs the user actually navigates to are loaded.', 'speculation-rules' ), + 'description' => plsr_get_field_description( 'eagerness' ), ), 'authentication' => array( 'title' => __( 'User Authentication Status', 'speculation-rules' ), - 'description' => sprintf( - /* translators: %s: URL to persistent object cache documentation */ - __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), - 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' - ), + 'description' => plsr_get_field_description( 'authentication' ), ), ); foreach ( $fields as $slug => $args ) { From befe097153aebf301a982b3ee63c527b3814c55f Mon Sep 17 00:00:00 2001 From: Aditya Dhade <76063440+b1ink0@users.noreply.github.com> Date: Fri, 22 Aug 2025 20:52:30 +0530 Subject: [PATCH 05/16] Add missed ` @access` annotation Co-authored-by: Weston Ruter --- plugins/speculation-rules/settings.php | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 4f7d22c035..f3bd6fc94a 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -60,6 +60,7 @@ function plsr_get_authentication_labels(): array { * Returns translated description strings for settings fields. * * @since n.e.x.t + * @access private * * @param string $field The field name to get description for. * @param bool $strip_tags Whether to strip HTML tags from the description. From d285b72448105e5a8d8484e2995aaaac049e5513 Mon Sep 17 00:00:00 2001 From: Aditya Dhade <76063440+b1ink0@users.noreply.github.com> Date: Fri, 22 Aug 2025 21:05:28 +0530 Subject: [PATCH 06/16] Instead of adding custom class, use a direct selector Co-authored-by: Weston Ruter --- plugins/speculation-rules/settings.php | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index f3bd6fc94a..ff859c7cba 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -288,9 +288,8 @@ function plsr_render_settings_field( array $args ): void { } $value = $option[ $args['field'] ]; - $authenticated_options = array( 'logged_out_and_admins', 'any' ); $show_notice = 'authentication' === $args['field'] && ! wp_using_ext_object_cache(); - $show_warning = $show_notice && in_array( $value, $authenticated_options, true ); + $show_warning = $show_notice && 'logged_out' !== $value; ?>
@@ -298,7 +297,6 @@ function plsr_render_settings_field( array $args ): void {

@@ -348,31 +348,28 @@ function plsr_render_settings_field( array $args ): void { 0; - if ( isAuthOption ) { - noticeDiv.classList.remove( "notice-info" ); - noticeDiv.classList.add( "notice-warning" ); - noticeLabel.hidden = false; - } else { - noticeDiv.classList.remove( "notice-warning" ); - noticeDiv.classList.add( "notice-info" ); - noticeLabel.hidden = true; - } - } ); + if ( isAuthOption ) { + noticeDiv.classList.remove( "notice-info" ); + noticeDiv.classList.add( "notice-warning" ); + noticeLabel.hidden = false; + } else { + noticeDiv.classList.remove( "notice-warning" ); + noticeDiv.classList.add( "notice-info" ); + noticeLabel.hidden = true; + } } ); - }', - wp_json_encode( $authenticated_options, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) - ), + } ); + }', array( 'type' => 'module' ) ); } From 3ced5041b9ce9f08c987b5e7808fc8a00fb644d0 Mon Sep 17 00:00:00 2001 From: Aditya Dhade Date: Fri, 22 Aug 2025 21:17:05 +0530 Subject: [PATCH 08/16] Remove warning text and reorder notice above description --- plugins/speculation-rules/settings.php | 34 ++++++++++++-------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index f7907c4adf..ceeae9b12f 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -307,24 +307,9 @@ function plsr_render_settings_field( array $args ): void {

-

- array( - 'href' => array(), - 'target' => array(), - ), - ) - ); - ?> -

-

- >

+ +

+ array( + 'href' => array(), + 'target' => array(), + ), + ) + ); + ?> +

Date: Fri, 22 Aug 2025 09:00:48 -0700 Subject: [PATCH 09/16] Use nowdoc --- plugins/speculation-rules/settings.php | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index ceeae9b12f..dfe8ef824b 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -346,10 +346,12 @@ function plsr_render_settings_field( array $args ): void { . + // phpcs:ignore Squiz.PHP.Heredoc.NotAllowed + $js = <<<'JS' + const authRadios = document.querySelectorAll( "input[name='plsr_speculation_rules[authentication]']" ); const noticeDiv = document.getElementById( "plsr-auth-notice" ); - + if ( authRadios.length && noticeDiv ) { authRadios.forEach( function ( radio, index ) { radio.addEventListener( "change", function ( e ) { @@ -365,9 +367,10 @@ function plsr_render_settings_field( array $args ): void { } } ); } ); - }', - array( 'type' => 'module' ) - ); + } +JS; + // 👆 This can only be indented two tabs when minimum PHP version is increased to 7.3+. + wp_print_inline_script_tag( $js, array( 'type' => 'module' ) ); } } From b2dade9a9f8fb08151ec5b75e6f720cb074d2a3d Mon Sep 17 00:00:00 2001 From: Aditya Dhade <76063440+b1ink0@users.noreply.github.com> Date: Fri, 22 Aug 2025 21:42:27 +0530 Subject: [PATCH 10/16] Escape notice class attribute Co-authored-by: Weston Ruter --- plugins/speculation-rules/settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index dfe8ef824b..4127601081 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -308,7 +308,7 @@ function plsr_render_settings_field( array $args ): void { -
+

Date: Fri, 22 Aug 2025 09:13:16 -0700 Subject: [PATCH 11/16] Improve conciseness of JS --- plugins/speculation-rules/settings.php | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 4127601081..1d09638126 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -349,27 +349,19 @@ function plsr_render_settings_field( array $args ): void { // TODO: Unsure why this is not allowed in PHPCS since not mentioned in WP coding standards and heredocs/nowdocs are use in core: . // phpcs:ignore Squiz.PHP.Heredoc.NotAllowed $js = <<<'JS' - const authRadios = document.querySelectorAll( "input[name='plsr_speculation_rules[authentication]']" ); + const authRadios = /** @type {NodeListOf} */ ( document.querySelectorAll( "input[name='plsr_speculation_rules[authentication]']" ) ); const noticeDiv = document.getElementById( "plsr-auth-notice" ); - if ( authRadios.length && noticeDiv ) { - authRadios.forEach( function ( radio, index ) { - radio.addEventListener( "change", function ( e ) { - // Index 0 is logged_out, any other index is authenticated option. - const isAuthOption = index > 0; - - if ( isAuthOption ) { - noticeDiv.classList.remove( "notice-info" ); - noticeDiv.classList.add( "notice-warning" ); - } else { - noticeDiv.classList.remove( "notice-warning" ); - noticeDiv.classList.add( "notice-info" ); - } + for ( const authRadio of authRadios ) { + authRadio.addEventListener( "change", () => { + const isLoggedOut = ( authRadio.value === "logged_out" ); + noticeDiv.classList.toggle( "notice-info", isLoggedOut ) + noticeDiv.classList.toggle( "notice-warning", ! isLoggedOut ) } ); - } ); + } } JS; - // 👆 This can only be indented two tabs when minimum PHP version is increased to 7.3+. + // 👆 This 'JS;' line can only be indented two tabs when minimum PHP version is increased to 7.3+. wp_print_inline_script_tag( $js, array( 'type' => 'module' ) ); } } From 7399ad2eec8c3b1cc886cb65932969aa7a7597cf Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 22 Aug 2025 10:27:22 -0700 Subject: [PATCH 12/16] Add PCP appeal comment --- plugins/speculation-rules/settings.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 1d09638126..5ddba51805 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -346,8 +346,7 @@ function plsr_render_settings_field( array $args ): void { . - // phpcs:ignore Squiz.PHP.Heredoc.NotAllowed + // phpcs:ignore Squiz.PHP.Heredoc.NotAllowed -- Part of the PCP ruleset. Appealed in . $js = <<<'JS' const authRadios = /** @type {NodeListOf} */ ( document.querySelectorAll( "input[name='plsr_speculation_rules[authentication]']" ) ); const noticeDiv = document.getElementById( "plsr-auth-notice" ); From 6bcf9f1fbf9fb0dec79d298883c4bfee0f86f538 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 22 Aug 2025 15:36:42 -0700 Subject: [PATCH 13/16] Improve test coverage and move tag stripping to output --- plugins/speculation-rules/settings.php | 15 ++++++--------- .../tests/test-speculation-rules-settings.php | 14 ++++++++++++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index 5ddba51805..a5b5d9a4ab 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -62,11 +62,10 @@ function plsr_get_authentication_labels(): array { * @since n.e.x.t * @access private * - * @param string $field The field name to get description for. - * @param bool $strip_tags Whether to strip HTML tags from the description. + * @param 'mode'|'eagerness'|'authentication' $field The field name to get description for. * @return string The translated description string. */ -function plsr_get_field_description( string $field, bool $strip_tags = false ): string { +function plsr_get_field_description( string $field ): string { $descriptions = array( 'mode' => __( 'Prerendering will lead to faster load times than prefetching. However, in case of interactive content, prefetching may be a safer choice.', 'speculation-rules' ), 'eagerness' => __( 'The eagerness setting defines the heuristics based on which the loading is triggered. "Eager" will have the minimum delay to start speculative loads, "Conservative" increases the chance that only URLs the user actually navigates to are loaded.', 'speculation-rules' ), @@ -76,9 +75,7 @@ function plsr_get_field_description( string $field, bool $strip_tags = false ): 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' ), ); - $description = $descriptions[ $field ] ?? ''; - - return $strip_tags ? wp_strip_all_tags( $description ) : $description; + return $descriptions[ $field ] ?? ''; } /** @@ -178,17 +175,17 @@ function plsr_register_setting(): void { 'type' => 'object', 'properties' => array( 'mode' => array( - 'description' => plsr_get_field_description( 'mode', true ), + 'description' => wp_strip_all_tags( plsr_get_field_description( 'mode' ) ), 'type' => 'string', 'enum' => array_keys( plsr_get_mode_labels() ), ), 'eagerness' => array( - 'description' => plsr_get_field_description( 'eagerness', true ), + 'description' => wp_strip_all_tags( plsr_get_field_description( 'eagerness' ) ), 'type' => 'string', 'enum' => array_keys( plsr_get_eagerness_labels() ), ), 'authentication' => array( - 'description' => plsr_get_field_description( 'authentication', true ), + 'description' => wp_strip_all_tags( plsr_get_field_description( 'authentication' ) ), 'type' => 'string', 'enum' => array_keys( plsr_get_authentication_labels() ), ), diff --git a/plugins/speculation-rules/tests/test-speculation-rules-settings.php b/plugins/speculation-rules/tests/test-speculation-rules-settings.php index a4eb3876a0..3da5e1fcde 100644 --- a/plugins/speculation-rules/tests/test-speculation-rules-settings.php +++ b/plugins/speculation-rules/tests/test-speculation-rules-settings.php @@ -13,6 +13,7 @@ class Test_Speculation_Rules_Settings extends WP_UnitTestCase { * @covers ::plsr_get_eagerness_labels * @covers ::plsr_get_authentication_labels * @covers ::plsr_get_setting_default + * @covers ::plsr_get_field_description */ public function test_plsr_register_setting(): void { unregister_setting( 'reading', 'plsr_speculation_rules' ); @@ -22,6 +23,13 @@ public function test_plsr_register_setting(): void { plsr_register_setting(); $settings = get_registered_settings(); $this->assertArrayHasKey( 'plsr_speculation_rules', $settings ); + foreach ( array( 'mode', 'eagerness', 'authentication' ) as $key ) { + $this->assertTrue( isset( $settings['plsr_speculation_rules']['show_in_rest']['schema']['properties'][ $key ]['description'] ) ); + $description = $settings['plsr_speculation_rules']['show_in_rest']['schema']['properties'][ $key ]['description']; + $this->assertIsString( $description ); + $this->assertGreaterThan( 0, strlen( $description ) ); + $this->assertStringNotContainsString( '<', $description ); + } $settings = plsr_get_setting_default(); $this->assertArrayHasKey( 'mode', $settings ); @@ -31,6 +39,12 @@ public function test_plsr_register_setting(): void { // Test default settings applied correctly. $default_settings = plsr_get_setting_default(); $this->assertEquals( $default_settings, get_option( 'plsr_speculation_rules' ) ); + + foreach ( array( 'mode', 'eagerness', 'authentication' ) as $key ) { + $description = plsr_get_field_description( $key ); + $this->assertGreaterThan( 0, strlen( $description ) ); + } + $this->assertSame( '', plsr_get_field_description( 'bogus' ) ); } /** From 538bcc7c9a4de895caccc2ad196979b6e03588ef Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 22 Aug 2025 15:50:25 -0700 Subject: [PATCH 14/16] Use event delegaction as advised by Gemini --- plugins/speculation-rules/settings.php | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index a5b5d9a4ab..be276ab857 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -288,7 +288,7 @@ function plsr_render_settings_field( array $args ): void { $show_notice = 'authentication' === $args['field'] && ! wp_using_ext_object_cache(); $show_warning = $show_notice && 'logged_out' !== $value; ?> -

+
$label ) : ?>

@@ -345,16 +345,18 @@ function plsr_render_settings_field( array $args ): void { if ( $show_notice ) { // phpcs:ignore Squiz.PHP.Heredoc.NotAllowed -- Part of the PCP ruleset. Appealed in . $js = <<<'JS' - const authRadios = /** @type {NodeListOf} */ ( document.querySelectorAll( "input[name='plsr_speculation_rules[authentication]']" ) ); - const noticeDiv = document.getElementById( "plsr-auth-notice" ); - if ( authRadios.length && noticeDiv ) { - for ( const authRadio of authRadios ) { - authRadio.addEventListener( "change", () => { - const isLoggedOut = ( authRadio.value === "logged_out" ); - noticeDiv.classList.toggle( "notice-info", isLoggedOut ) - noticeDiv.classList.toggle( "notice-warning", ! isLoggedOut ) - } ); - } + const authOptions = document.getElementById( 'plsr-authentication-setting' ); + const noticeDiv = document.getElementById( 'plsr-auth-notice' ); + if ( authOptions && noticeDiv ) { + authOptions.addEventListener( 'change', ( /** @type {Event} */ event ) => { + const target = event.target; + if ( ! ( target instanceof HTMLInputElement && 'radio' === target.type ) ) { + return; + } + const isLoggedOut = ( target.value === 'logged_out' ); + noticeDiv.classList.toggle( 'notice-info', isLoggedOut ); + noticeDiv.classList.toggle( 'notice-warning', ! isLoggedOut ); + } ); } JS; // 👆 This 'JS;' line can only be indented two tabs when minimum PHP version is increased to 7.3+. From 823018e033e1c8f01c9183221986cb3f1d12062c Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 22 Aug 2025 16:04:38 -0700 Subject: [PATCH 15/16] Further iterate on the warning and description --- plugins/speculation-rules/settings.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index be276ab857..b758c88da2 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -71,7 +71,7 @@ function plsr_get_field_description( string $field ): string { 'eagerness' => __( 'The eagerness setting defines the heuristics based on which the loading is triggered. "Eager" will have the minimum delay to start speculative loads, "Conservative" increases the chance that only URLs the user actually navigates to are loaded.', 'speculation-rules' ), 'authentication' => sprintf( /* translators: %s: URL to persistent object cache documentation */ - __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance when enabling authenticated user support, ensure you have a persistent object cache configured. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ), + __( 'Only unauthenticated pages are typically served from cache. So in order to reduce load on the server, speculative loading is not enabled by default for logged-in users. If your server can handle the additional load, you can opt in to speculative loading for all logged-in users or just administrator users only. For optimal performance, regardless of the user authentication status but especially when logged-in, ensure you have a persistent object cache configured. This only applies to pages on the frontend; admin screens remain excluded.', 'speculation-rules' ), 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' ), ); @@ -311,7 +311,7 @@ function plsr_render_settings_field( array $args ): void { echo wp_kses( sprintf( /* translators: %s: URL to persistent object cache documentation */ - __( 'Enabling speculative loading for authenticated users without a persistent object cache may significantly increase server load. Consider setting up a persistent object cache before enabling this feature for logged-in users.', 'speculation-rules' ), + __( 'Enabling speculative loading for authenticated users may significantly increase the server load. Consider setting up a persistent object cache before enabling this feature for logged-in users.', 'speculation-rules' ), 'https://developer.wordpress.org/advanced-administration/performance/optimization/#object-caching' ), array( @@ -331,10 +331,11 @@ function plsr_render_settings_field( array $args ): void { echo wp_kses( $args['description'], array( - 'a' => array( + 'a' => array( 'href' => array(), 'target' => array(), ), + 'em' => array(), ) ); ?> From 639bd9d408f1a5ff9a06019b1f6728a35d121057 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Fri, 22 Aug 2025 16:14:25 -0700 Subject: [PATCH 16/16] Remove unnecessary variables and consolidate changes --- plugins/speculation-rules/settings.php | 49 ++++++++++++-------------- 1 file changed, 23 insertions(+), 26 deletions(-) diff --git a/plugins/speculation-rules/settings.php b/plugins/speculation-rules/settings.php index b758c88da2..f8a7dba5f1 100644 --- a/plugins/speculation-rules/settings.php +++ b/plugins/speculation-rules/settings.php @@ -284,9 +284,7 @@ function plsr_render_settings_field( array $args ): void { return; // @codeCoverageIgnore } - $value = $option[ $args['field'] ]; - $show_notice = 'authentication' === $args['field'] && ! wp_using_ext_object_cache(); - $show_warning = $show_notice && 'logged_out' !== $value; + $value = $option[ $args['field'] ]; ?>

@@ -304,8 +302,8 @@ function plsr_render_settings_field( array $args ): void {

- -
+ +

+ . + $js = <<<'JS' + const authOptions = document.getElementById( 'plsr-authentication-setting' ); + const noticeDiv = document.getElementById( 'plsr-auth-notice' ); + if ( authOptions && noticeDiv ) { + authOptions.addEventListener( 'change', ( /** @type {Event} */ event ) => { + const target = event.target; + if ( ! ( target instanceof HTMLInputElement && 'radio' === target.type ) ) { + return; + } + const isLoggedOut = ( target.value === 'logged_out' ); + noticeDiv.classList.toggle( 'notice-info', isLoggedOut ); + noticeDiv.classList.toggle( 'notice-warning', ! isLoggedOut ); + } ); + } +JS; + // 👆 This 'JS;' line can only be indented two tabs when minimum PHP version is increased to 7.3+. + wp_print_inline_script_tag( $js, array( 'type' => 'module' ) ); + ?>

@@ -341,28 +359,7 @@ function plsr_render_settings_field( array $args ): void { ?>

- . - $js = <<<'JS' - const authOptions = document.getElementById( 'plsr-authentication-setting' ); - const noticeDiv = document.getElementById( 'plsr-auth-notice' ); - if ( authOptions && noticeDiv ) { - authOptions.addEventListener( 'change', ( /** @type {Event} */ event ) => { - const target = event.target; - if ( ! ( target instanceof HTMLInputElement && 'radio' === target.type ) ) { - return; - } - const isLoggedOut = ( target.value === 'logged_out' ); - noticeDiv.classList.toggle( 'notice-info', isLoggedOut ); - noticeDiv.classList.toggle( 'notice-warning', ! isLoggedOut ); - } ); - } -JS; - // 👆 This 'JS;' line can only be indented two tabs when minimum PHP version is increased to 7.3+. - wp_print_inline_script_tag( $js, array( 'type' => 'module' ) ); - } } /**