Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
91 changes: 83 additions & 8 deletions plugins/speculation-rules/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,28 @@ function plsr_get_authentication_labels(): array {
);
}

/**
* Returns translated description strings for settings fields.
*
* @since n.e.x.t
* @access private
*
* @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 ): 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, regardless of the user authentication status but <em>especially</em> when logged-in, ensure you have a <a href="%s" target="_blank">persistent object cache</a> 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'
),
);
return $descriptions[ $field ] ?? '';
}

/**
* Returns the default setting value for Speculative Loading configuration.
*
Expand Down Expand Up @@ -153,17 +175,17 @@ function plsr_register_setting(): void {
'type' => 'object',
'properties' => array(
'mode' => array(
'description' => __( 'Whether to prefetch or prerender URLs.', 'speculation-rules' ),
'description' => wp_strip_all_tags( plsr_get_field_description( 'mode' ) ),
'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' => wp_strip_all_tags( plsr_get_field_description( 'eagerness' ) ),
'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. This only applies to pages on frontend; admin screens remain excluded.', 'speculation-rules' ),
'description' => wp_strip_all_tags( plsr_get_field_description( 'authentication' ) ),
'type' => 'string',
'enum' => array_keys( plsr_get_authentication_labels() ),
),
Expand Down Expand Up @@ -203,15 +225,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' => __( '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' => plsr_get_field_description( 'authentication' ),
),
);
foreach ( $fields as $slug => $args ) {
Expand Down Expand Up @@ -264,7 +286,7 @@ function plsr_render_settings_field( array $args ): void {

$value = $option[ $args['field'] ];
?>
<fieldset>
<fieldset id="<?php echo esc_attr( 'plsr-' . $args['field'] . '-setting' ); ?>">
<legend class="screen-reader-text"><?php echo esc_html( $args['title'] ); ?></legend>
<?php foreach ( $choices as $slug => $label ) : ?>
<p>
Expand All @@ -280,8 +302,61 @@ function plsr_render_settings_field( array $args ): void {
</p>
<?php endforeach; ?>

<?php if ( 'authentication' === $args['field'] && ! wp_using_ext_object_cache() ) : ?>
<div id="plsr-auth-notice" class="notice <?php echo esc_attr( 'logged_out' !== $value ? 'notice-warning' : 'notice-info' ); ?> inline">
<p>
<?php
echo wp_kses(
Copy link
Copy Markdown
Contributor Author

@b1ink0 b1ink0 Aug 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alternatively, what if the notice is always displayed but as info, and then if someone switches to the non-default option, it then becomes a warning?

The benefit here is that it adds more visibility to the lack of a persistent object cache, which is important also for Speculative Loading generally when there is a page cache MISS.

Makes sense. I’ve now added the persistence notice as shown below:

demo1.mp4

I have added a bold Warning: text when there is a warning. Do you think the change of color in the notice is enough, or should the Warning: text be included as well? It does make the text slide.

cc: @westonruter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the warning text is a nice touch, but it may be over the top. The main downside I see is that it causes the text to reflow. Let's try removing.

Also, I think the warning could be placed above the description so that it doesn't get missed when the user hasn't scrolled down enough to see it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 3ced504.

Now it looks like this:

Demo2.mp4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks good.

sprintf(
/* translators: %s: URL to persistent object cache documentation */
__( 'Enabling speculative loading for authenticated users may significantly increase the server load. Consider setting up a <a href="%s" target="_blank">persistent object cache</a> 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(),
),
)
);
?>
</p>
</div>
<?php
// phpcs:ignore Squiz.PHP.Heredoc.NotAllowed -- Part of the PCP ruleset. Appealed in <https://github.com/WordPress/plugin-check/issues/792#issuecomment-3214985527>.
$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' ) );
?>
<?php endif; ?>

<p class="description" style="max-width: 800px;">
<?php echo esc_html( $args['description'] ); ?>
<?php
echo wp_kses(
$args['description'],
array(
'a' => array(
'href' => array(),
'target' => array(),
),
'em' => array(),
)
);
?>
</p>
</fieldset>
<?php
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' );
Expand All @@ -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 );
Expand All @@ -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' ) );
}

/**
Expand Down