Skip to content
Open
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
13 changes: 13 additions & 0 deletions plugins/speculation-rules/hooks.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,16 @@ function plsr_render_generator_meta_tag(): void {
echo '<meta name="generator" content="speculation-rules ' . esc_attr( SPECULATION_RULES_VERSION ) . '">' . "\n";
}
add_action( 'wp_head', 'plsr_render_generator_meta_tag' );

/**
* Prints the Origin Trial meta tag if a token is configured.
*
* @since 1.7.0
*/
function plsr_print_origin_trial_meta_tag(): void {
$option = plsr_get_stored_setting_value();
if ( '' !== $option['origin_trial_token'] && 'prerender_until_script' === $option['mode'] && plsr_is_speculative_loading_enabled() ) {
echo '<meta http-equiv="origin-trial" content="' . esc_attr( $option['origin_trial_token'] ) . '">' . "\n";
}
}
add_action( 'wp_head', 'plsr_print_origin_trial_meta_tag', 1 );
8 changes: 7 additions & 1 deletion plugins/speculation-rules/plugin-api.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ function plsr_get_speculation_rules(): array {
*
* @param string[] $href_exclude_paths Additional paths to disable speculative prerendering for. The base exclude paths,
* such as for wp-admin, cannot be removed.
* @param string $mode Mode used to apply speculative prerendering. Either 'prefetch' or 'prerender'.
* @param string $mode Mode used to apply speculative prerendering. Either 'prefetch', 'prerender', or 'prerender_until_script'.
*/
$href_exclude_paths = (array) apply_filters( 'plsr_speculation_rules_href_exclude_paths', array(), $mode );

Expand Down Expand Up @@ -119,6 +119,12 @@ static function ( string $href_exclude_path ) use ( $prefixer ): string {
'selector_matches' => '.no-prerender',
),
);
} elseif ( 'prerender_until_script' === $mode ) {
$rules[0]['where']['and'][] = array(
'not' => array(
'selector_matches' => '.no-prerender, .no-prerender_until_script',
),
);
}

return array( $mode => $rules );
Expand Down
87 changes: 61 additions & 26 deletions plugins/speculation-rules/settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
*
* @since 1.0.0
*
* @return array{ prefetch: string, prerender: string } Associative array of `$mode => $label` pairs.
* @return array{ prefetch: string, prerender: string, prerender_until_script: string } Associative array of `$mode => $label` pairs.
*/
function plsr_get_mode_labels(): array {
return array(
'prefetch' => _x( 'Prefetch', 'setting label', 'speculation-rules' ),
'prerender' => _x( 'Prerender', 'setting label', 'speculation-rules' ),
'prefetch' => _x( 'Prefetch', 'setting label', 'speculation-rules' ),
'prerender' => _x( 'Prerender', 'setting label', 'speculation-rules' ),
'prerender_until_script' => _x( 'Prerender until script', 'setting label', 'speculation-rules' ),
);
}

Expand Down Expand Up @@ -69,7 +70,7 @@ function plsr_get_authentication_labels(): array {
*/
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' ),
'mode' => __( 'Prerendering will lead to faster load times than prefetching. Prerender until script starts rendering but pauses before executing script elements. Prefetching is the safest choice for interactive content.', '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 */
Expand All @@ -85,19 +86,21 @@ function plsr_get_field_description( string $field ): string {
*
* @since 1.0.0
*
* @return array{ mode: 'prerender', eagerness: 'moderate', authentication: 'logged_out' } {
* @return array{ mode: 'prerender', eagerness: 'moderate', authentication: 'logged_out', origin_trial_token: string } {
* Default setting value.
*
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $origin_trial_token Origin trial token.
* }
*/
function plsr_get_setting_default(): array {
return array(
'mode' => 'prerender',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'mode' => 'prerender',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'origin_trial_token' => '',
);
}

Expand All @@ -106,12 +109,13 @@ function plsr_get_setting_default(): array {
*
* @since 1.4.0
*
* @return array{ mode: 'prefetch'|'prerender', eagerness: 'conservative'|'moderate'|'eager', authentication: 'logged_out'|'logged_out_and_admins'|'any' } {
* @return array{ mode: 'prefetch'|'prerender'|'prerender_until_script', eagerness: 'conservative'|'moderate'|'eager', authentication: 'logged_out'|'logged_out_and_admins'|'any', origin_trial_token: string } {
* Stored setting value.
*
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $origin_trial_token Origin trial token.
* }
*/
function plsr_get_stored_setting_value(): array {
Expand All @@ -125,12 +129,13 @@ function plsr_get_stored_setting_value(): array {
* @todo Consider whether the JSON schema for the setting could be reused here.
*
* @param mixed $input Setting to sanitize.
* @return array{ mode: 'prefetch'|'prerender', eagerness: 'conservative'|'moderate'|'eager', authentication: 'logged_out'|'logged_out_and_admins'|'any' } {
* @return array{ mode: 'prefetch'|'prerender'|'prerender_until_script', eagerness: 'conservative'|'moderate'|'eager', authentication: 'logged_out'|'logged_out_and_admins'|'any', origin_trial_token: string } {
* Sanitized setting.
*
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $mode Mode.
* @type string $eagerness Eagerness.
* @type string $authentication Authentication.
* @type string $origin_trial_token Origin trial token.
* }
*/
function plsr_sanitize_setting( $input ): array {
Expand All @@ -154,6 +159,8 @@ function plsr_sanitize_setting( $input ): array {
$value['authentication'] = $default_value['authentication'];
}

$value['origin_trial_token'] = sanitize_text_field( $value['origin_trial_token'] );

return $value;
}

Expand All @@ -176,21 +183,25 @@ function plsr_register_setting(): void {
'schema' => array(
'type' => 'object',
'properties' => array(
'mode' => array(
'mode' => array(
'description' => wp_strip_all_tags( plsr_get_field_description( 'mode' ) ),
'type' => 'string',
'enum' => array_keys( plsr_get_mode_labels() ),
),
'eagerness' => array(
'eagerness' => array(
'description' => wp_strip_all_tags( plsr_get_field_description( 'eagerness' ) ),
'type' => 'string',
'enum' => array_keys( plsr_get_eagerness_labels() ),
),
'authentication' => array(
'authentication' => array(
'description' => wp_strip_all_tags( plsr_get_field_description( 'authentication' ) ),
'type' => 'string',
'enum' => array_keys( plsr_get_authentication_labels() ),
),
'origin_trial_token' => array(
'description' => __( 'Origin Trial Token for Prerender Until Script.', 'speculation-rules' ),
'type' => 'string',
),
),
'additionalProperties' => false,
),
Expand Down Expand Up @@ -225,18 +236,22 @@ static function (): void {
);

$fields = array(
'mode' => array(
'mode' => array(
'title' => __( 'Speculation Mode', 'speculation-rules' ),
'description' => plsr_get_field_description( 'mode' ),
),
'eagerness' => array(
'eagerness' => array(
'title' => __( 'Eagerness', 'speculation-rules' ),
'description' => plsr_get_field_description( 'eagerness' ),
),
'authentication' => array(
'authentication' => array(
'title' => __( 'User Authentication Status', 'speculation-rules' ),
'description' => plsr_get_field_description( 'authentication' ),
),
'origin_trial_token' => array(
'title' => __( 'Origin Trial Token', 'speculation-rules' ),
'description' => __( 'If you are using the "Prerender until script" mode in production, you can register for the Chrome Origin Trial and paste your token here to enable it for visitors.', 'speculation-rules' ),
),
);
foreach ( $fields as $slug => $args ) {
add_settings_field(
Expand All @@ -260,7 +275,7 @@ static function (): void {
* @since 1.0.0
* @access private
*
* @param array{ field: 'mode'|'eagerness'|'authentication', title: non-empty-string, description: non-empty-string } $args {
* @param array{ field: 'mode'|'eagerness'|'authentication'|'origin_trial_token', title: non-empty-string, description: non-empty-string } $args {
* Associative array of arguments.
*
* @type string $field The slug of the sub setting controlled by the field.
Expand All @@ -281,6 +296,26 @@ function plsr_render_settings_field( array $args ): void {
case 'authentication':
$choices = plsr_get_authentication_labels();
break;
case 'origin_trial_token':
$value = $option['origin_trial_token'];
?>
<fieldset id="plsr-origin_trial_token-setting">
<legend class="screen-reader-text"><?php echo esc_html( $args['title'] ); ?></legend>
<p>
<input
name="plsr_speculation_rules[origin_trial_token]"
type="text"
class="regular-text"
value="<?php echo esc_attr( $value ); ?>"
placeholder="e.g. ApX...=="
>
</p>
<p class="description" style="max-width: 800px;">
<?php echo esc_html( $args['description'] ); ?>
</p>
</fieldset>
<?php
return;
default:
// Invalid (and this case should never occur).
return; // @codeCoverageIgnore
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,22 @@ public function test_plsr_get_speculation_rules_prerender(): void {
$this->assertCount( 4, $rules['prerender'][0]['where']['and'] );
}

/**
* @covers ::plsr_get_speculation_rules
*/
public function test_plsr_get_speculation_rules_prerender_until_script(): void {
update_option( 'plsr_speculation_rules', array( 'mode' => 'prerender_until_script' ) );

$rules = plsr_get_speculation_rules();

$this->assertArrayHasKey( 'prerender_until_script', $rules );
$this->assertCount( 4, $rules['prerender_until_script'][0]['where']['and'] );
$this->assertSame(
'.no-prerender, .no-prerender_until_script',
$rules['prerender_until_script'][0]['where']['and'][3]['not']['selector_matches']
);
}

/**
* @covers ::plsr_get_speculation_rules
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ public function test_plsr_sanitize_setting( $input, array $expected ): void {
/** @return array<string, mixed> */
public function data_plsr_sanitize_setting(): array {
$default_value = array(
'mode' => 'prerender',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'mode' => 'prerender',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'origin_trial_token' => '',
);

return array(
Expand Down Expand Up @@ -215,17 +216,19 @@ public function test_get_stored_setting_value(): void {
update_option(
'plsr_speculation_rules',
array(
'mode' => 'prefetch',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'mode' => 'prefetch',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'origin_trial_token' => '',
)
);
$settings = plsr_get_stored_setting_value();
$this->assertEquals(
array(
'mode' => 'prefetch',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'mode' => 'prefetch',
'eagerness' => 'moderate',
'authentication' => 'logged_out',
'origin_trial_token' => '',
),
$settings
);
Expand Down Expand Up @@ -283,24 +286,30 @@ public function test_plsr_add_setting_ui(): void {
*/
public function data_provider_to_test_render_settings_field(): array {
return array(
'mode' => array(
'mode' => array(
'field' => 'mode',
'value' => 'prefetch',
'title' => 'Speculation Mode',
'description' => 'The mode description',
),
'eagerness' => array(
'eagerness' => array(
'field' => 'eagerness',
'value' => 'moderate',
'title' => 'Eagerness',
'description' => 'The eagerness description',
),
'authentication' => array(
'authentication' => array(
'field' => 'authentication',
'value' => 'any',
'title' => 'Authentication',
'description' => 'The authentication description.',
),
'origin_trial_token' => array(
'field' => 'origin_trial_token',
'value' => 'some_token',
'title' => 'Origin Trial Token',
'description' => 'The origin trial token description.',
),
);
}

Expand Down Expand Up @@ -332,7 +341,11 @@ public function test_plsr_render_settings_field( string $field, string $value, s
&&
$p->get_attribute( 'value' ) === $value
) {
$found = null !== $p->get_attribute( 'checked' );
if ( 'origin_trial_token' === $field ) {
$found = true;
} else {
$found = null !== $p->get_attribute( 'checked' );
}
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ public function test_plsr_filter_speculation_rules_exclude_paths_with_invalid():
$this->assertSame( array( '/personalized/*' ), plsr_filter_speculation_rules_exclude_paths( '/personalized/*', 'prefetch' ) );
}

/**
* @covers ::plsr_filter_speculation_rules_configuration
*/
public function test_plsr_filter_speculation_rules_configuration_with_prerender_until_script(): void {
add_filter( 'plsr_enabled_without_pretty_permalinks', '__return_true' );
update_option( 'plsr_speculation_rules', array( 'mode' => 'prerender_until_script' ) );
$this->assertSame(
array(
'mode' => 'prerender_until_script',
'eagerness' => 'moderate',
),
plsr_filter_speculation_rules_configuration( null )
);
}

private function disable_pretty_permalinks(): void {
update_option( 'permalink_structure', '' );
}
Expand Down
Loading
Loading