Skip to content

Commit

Permalink
Closes #6987 Add dynamic list Automatic Lazy Render exclusions (#6988)
Browse files Browse the repository at this point in the history
Co-authored-by: Gael Robin <[email protected]>
  • Loading branch information
remyperona and Miraeld committed Sep 24, 2024
1 parent a0f3dec commit d05b068
Show file tree
Hide file tree
Showing 12 changed files with 317 additions and 3 deletions.
11 changes: 11 additions & 0 deletions inc/Engine/Optimization/DynamicLists/DynamicLists.php
Original file line number Diff line number Diff line change
Expand Up @@ -302,4 +302,15 @@ public function get_exclude_js_templates(): array {

return $lists->exclude_js_template ?? [];
}

/**
* Get the lazy rendered exclusions.
*
* @return array
*/
public function get_lrc_exclusions(): array {
$lists = $this->providers['defaultlists']->data_manager->get_lists();

return $lists->lazy_rendering_exclusions ?? [];
}
}
12 changes: 12 additions & 0 deletions inc/Engine/Optimization/DynamicLists/Subscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public static function get_subscribed_events() {
'rocket_exclude_js' => 'add_js_exclude_files',
'rocket_plugins_to_deactivate' => 'add_incompatible_plugins_to_deactivate',
'rocket_staging_list' => 'add_staging_exclusions',
'rocket_lrc_exclusions' => 'add_lrc_exclusions',
];
}

Expand Down Expand Up @@ -213,4 +214,15 @@ public function add_incompatible_plugins_to_deactivate( $plugins = [] ): array {
public function add_staging_exclusions( $stagings = [] ): array {
return array_merge( (array) $stagings, (array) $this->dynamic_lists->get_stagings() );
}

/**
* Add the LRC exclusions to the array
*
* @param array $exclusions Array of LRC exclusions.
*
* @return array
*/
public function add_lrc_exclusions( $exclusions ): array {
return array_merge( (array) $exclusions, $this->dynamic_lists->get_lrc_exclusions() );
}
}
19 changes: 19 additions & 0 deletions inc/Engine/Optimization/LazyRenderContent/Frontend/Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,10 +145,29 @@ public function add_hashes( $html ) {
$processor = wpm_apply_filters_typed( 'string', 'rocket_lrc_processor', 'dom' );

$this->processor->set_processor( $processor );
$this->processor->get_processor()->set_exclusions( $this->get_exclusions() );

return $this->processor->get_processor()->add_hashes( $html );
}

/**
* Get the list of patterns to exclude from hash injection.
*
* @return string[]
*/
private function get_exclusions(): array {
/**
* Filters the list of patterns to exclude from hash injection.
*
* @since 3.17.0.2
*
* @param string[] $exclusions The list of patterns to exclude from hash injection.
*/
$exclusions = wpm_apply_filters_typed( 'string[]', 'rocket_lrc_exclusions', [] );

return $exclusions;
}

/**
* Add custom data like the List of elements to be considered for optimization.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
use WP_Rocket\Logger\Logger;

class Dom implements ProcessorInterface {

use HelperTrait;

/**
Expand All @@ -28,6 +27,46 @@ class Dom implements ProcessorInterface {
*/
private $max_hashes;

/**
* Array of patterns to exclude from hash injection.
*
* @since 3.17.0.2
*
* @var array
*/
private $exclusions = [];

/**
* Sets the exclusions list
*
* @param string[] $exclusions The list of patterns to exclude from hash injection.
*
* @return void
*/
public function set_exclusions( $exclusions ): void {
$this->exclusions = $exclusions;
}

/**
* Gets the exclusions pattern
*
* @return string
*/
private function get_exclusions_pattern(): string {
if ( empty( $this->exclusions ) ) {
return '';
}

$exclusions = array_map(
function ( $exclusion ) {
return preg_quote( $exclusion, '/' );
},
$this->exclusions
);

return implode( '|', $exclusions );
}

/**
* Add hashes to the HTML elements
*
Expand Down Expand Up @@ -107,6 +146,16 @@ private function add_hash_to_element( $element, $depth, $html ) {
$child_html = $child->ownerDocument->saveHTML( $child ); // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
$opening_tag_html = strstr( $child_html, '>', true ) . '>';

$exclusions_pattern = $this->get_exclusions_pattern();

if (
! empty( $exclusions_pattern )
&&
preg_match( '/(' . $exclusions_pattern . ')/i', $opening_tag_html )
) {
continue;
}

$hash = md5( $opening_tag_html . $this->count );

++$this->count;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,13 @@ interface ProcessorInterface {
* @return string
*/
public function add_hashes( $html );

/**
* Sets the exclusions list
*
* @param string[] $exclusions The list of patterns to exclude from hash injection.
*
* @return void
*/
public function set_exclusions( array $exclusions ): void;
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ class Regex implements ProcessorInterface {
*/
private $max_hashes;

/**
* Array of patterns to exclude from hash injection.
*
* @since 3.17.0.2
*
* @var array
*/
private $exclusions;

/**
* Sets the exclusions list
*
* @param string[] $exclusions The list of patterns to exclude from hash injection.
*
* @return void
*/
public function set_exclusions( $exclusions ): void {
$this->exclusions = $exclusions;
}

/**
* Add hashes to the HTML elements
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,26 @@ class SimpleHtmlDom implements ProcessorInterface {
*/
private $max_hashes;

/**
* Array of patterns to exclude from hash injection.
*
* @since 3.17.0.2
*
* @var array
*/
private $exclusions;

/**
* Sets the exclusions list
*
* @param string[] $exclusions The list of patterns to exclude from hash injection.
*
* @return void
*/
public function set_exclusions( $exclusions ): void {
$this->exclusions = $exclusions;
}

/**
* Add hashes to the HTML elements
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

return [
'shouldReturnUpdatedArray' => [
'config' => [
'dynamic_lists' => (object) [
'lazy_rendering_exclusions' => [
'a'
]
],
'exclusions' => ['p', 'div']
],
'expected' => [
'p',
'div',
'a'
],
],
'shouldReturnUpdatedArrayWhenOriginalEmpty' => [
'config' => [
'dynamic_lists' => (object) [
'lazy_rendering_exclusions' => [
]
],
'exclusions' => ['p', 'div']
],
'expected' => [
'p',
'div',
],
],
];
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,30 @@
'expected' => [
'html' => file_get_contents( WP_ROCKET_TESTS_FIXTURES_DIR . '/inc/Engine/Optimization/LazyRenderContent/Frontend/Subscriber/html/long_expected_150_hashes.php' ),
]
]
],
'shouldNotAddHashesToExclusions' => [
'config' => [
'row' => [
'url' => 'http://example.org/',
'is_mobile' => 0,
'below_the_fold' => json_encode(
[
"93548b90aa8f4989f7198144479055dc",
"7b16eca0652d4703f83ba63e304f2030",
"737184bbad8e65d0172a89cc68a46107",
"8a4ef50742cf3456f9db6425e16930dc"
]
),
'status' => 'completed'
],
'html' => file_get_contents( WP_ROCKET_TESTS_FIXTURES_DIR . '/inc/Engine/Optimization/LazyRenderContent/Frontend/Subscriber/html/original.php' ),
'exclusions' => [
'footer'
],
],
'expected' => [
'html' => file_get_contents( WP_ROCKET_TESTS_FIXTURES_DIR . '/inc/Engine/Optimization/LazyRenderContent/Frontend/Subscriber/html/expected_exclusions.php' ),
]
],
]
];
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
/**
* Template Name: LRC Template
* Template Post Type: post, page
*
* @package WordPress
* @subpackage Twenty_Twenty
* @since Twenty Twenty 1.0
*/
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
.external .external-css-background-image-space{
width: 100%;
height: 400px;
background-image: url("https://fastly.picsum.photos/id/10/2500/1667.jpg?hmac=J04WWC_ebchx3WwzbM-Z4_KC_LeLBWr5LZMaAkWkF68");
}

.external-css-background-image-space{
width: 100%;
height: 400px;
background-image: url("https://fastly.picsum.photos/id/12/2500/1667.jpg?hmac=Pe3284luVre9ZqNzv1jMFpLihFI6lwq7TPgMSsNXw2w");
}
.margin-top {
margin-top:1800px;
}
.margin-top-2 {
margin-top:3000px;
}
</style>
</head>
<body>
<div data-rocket-location-hash="3ead51141d9876165378a22a92d90415" class="external"> 400px
<div data-rocket-location-hash="eb156891061284662641900bc9136fae" class="external-css-background-image-space"> 800 px
<br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br /><br />
1800 px<div data-rocket-location-hash="93548b90aa8f4989f7198144479055dc">Testing something</div>
</div>
</div>

<div data-rocket-location-hash="7b16eca0652d4703f83ba63e304f2030">
<div data-rocket-location-hash="1d3bac2039255355f77f171c50019b44" class="margin-top-2">
<div data-rocket-location-hash="57f84b25dc0def2056eb68ae21a02316">
<div attribute-added-to-bypass-dom-processor-known-issue="1">
This is a class with margin-top set to 3000px
</div>
</div>
</div>
</div>

<div data-rocket-location-hash="737184bbad8e65d0172a89cc68a46107" class="margin-top">
<div data-rocket-location-hash="bd74d375918add18d6b92168fe60b650">
<div data-rocket-location-hash="d7e6e4a5cd6da651d79890911470ebb9">
This is a class with margin-top set to 1800px
</div>
</div>
</div>

<footer>
Somethign fishy going on.
</footer>
</body>
</html>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace WP_Rocket\tests\Integration\inc\Engine\Optimization\DynamicLists\Subscriber;

use Mockery;
use WP_Rocket\Engine\Optimization\DynamicLists\DynamicLists;
use WP_Rocket\Tests\Integration\TestCase;

/**
* Test class covering \WP_Rocket\Engine\Optimization\DynamicLists\Subscriber::add_lrc_exclusions()
*
* @group DynamicLists
*/
class Test_AddLrcExclusions extends TestCase {
private $dynamic_lists;
public function set_up() {
parent::set_up();

$this->unregisterAllCallbacksExcept( 'rocket_lrc_exclusions', 'add_lrc_exclusions', 10 );
}

public function tear_down() {
remove_filter( 'pre_transient_wpr_dynamic_lists', [$this, 'set_dynamic_list'] );

$this->restoreWpHook( 'rocket_lrc_exclusions' );

parent::tear_down();
}

/**
* @dataProvider configTestData
*/
public function testShouldReturnExpected( $config, $expected ) {
$this->dynamic_lists = $config['dynamic_lists'];
add_filter( 'pre_transient_wpr_dynamic_lists', [$this, 'set_dynamic_list'], 12 );

$this->assertSame(
$expected,
wpm_apply_filters_typed('array', 'rocket_lrc_exclusions', $config['exclusions'] )
);
}

public function set_dynamic_list() {
return $this->dynamic_lists;
}
}
Loading

0 comments on commit d05b068

Please sign in to comment.