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

Closes #6987 Add dynamic list Automatic Lazy Render exclusions #6988

Merged
merged 12 commits into from
Sep 24, 2024
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 )
Tabrisrp marked this conversation as resolved.
Show resolved Hide resolved
) {
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;
}
Tabrisrp marked this conversation as resolved.
Show resolved Hide resolved

/**
* 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
Loading