-
Notifications
You must be signed in to change notification settings - Fork 384
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
Use wp_unique_id
-based block class names instead of uniqid
#6949
Merged
Merged
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
fcb7244
Use `wp_unique_id`-based block class names instead of `uniqid`
delawski 90b7886
Merge branch 'develop' of github.com:ampproject/amp-wp into fix/6925-…
westonruter 41fa877
Utilize static variable for constructed regex
westonruter 54746e3
Reorganize transform_class_names_in_block_content slightly
westonruter e7c349f
Add failing test case for class being incorrectly transformed in text…
westonruter b441abe
Restrict replacements to class attribute values in start tags
westonruter 473a8e7
Provide polyfill for wp_unique_id() for WP<5.0.3
westonruter e41fa08
Implement AMP_Block_Uniqid_Sanitizer
westonruter 9fb0510
Use transformer only with some versions of Gutenberg
delawski 703e853
Transform uniqid in WordPress 5.8 through 6.0
delawski f68c8e2
Add support for legacy version of duotone prefix
delawski 76c1415
Test for correct WP and Gutenberg versions
delawski af994b1
Do not check if test is dealing with AMP request
delawski 5c7cffe
Migrate block uniqid tests cases to `AMP_Block_Uniqid_Sanitizer`
delawski 605a746
Extend MonitorCssTransientCaching with BlockUniqidTransformer awareness
westonruter 6e6d332
Merge branch 'develop' of github.com:ampproject/amp-wp into fix/6925-…
westonruter 4a6846a
Ignore wp_unique_id() polyfill code for coverage
westonruter a8e8f84
Add tests for MonitorCssTransientCaching and BlockUniqidTransformer
westonruter f95a1af
Normalize to allow AMP_Block_Uniqid_Sanitizer tests to run in isolation
westonruter 8a8ae96
Use proper coversDefaultClass phpdoc tag
westonruter c27435c
Restore wp_version global after tests
westonruter 35dda9d
Use data provider for test_handle_plugin_update
westonruter d87b78b
Ensure CSS transients disabling is not reset with each version update
westonruter File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
204 changes: 204 additions & 0 deletions
204
includes/sanitizers/class-amp-block-uniqid-sanitizer.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
<?php | ||
/** | ||
* Class AMP_Block_Uniqid_Sanitizer. | ||
* | ||
* @package AMP | ||
*/ | ||
|
||
use AmpProject\Dom\Element; | ||
use AmpProject\Html\Attribute; | ||
use AmpProject\Html\Tag; | ||
use AmpProject\Dom\Document; | ||
|
||
/** | ||
* Work around use of uniqid() in blocks which breaks parsed CSS caching. | ||
* | ||
* @link https://github.com/ampproject/amp-wp/issues/6925 | ||
* @link https://github.com/WordPress/gutenberg/issues/38889 | ||
* | ||
* @since 2.2.2 | ||
* @internal | ||
*/ | ||
class AMP_Block_Uniqid_Sanitizer extends AMP_Base_Sanitizer { | ||
|
||
/** | ||
* Prefixes of class names that should be transformed. | ||
* | ||
* @var string[] | ||
*/ | ||
const KEY_PREFIXES = [ | ||
'wp-container-', | ||
'wp-duotone-', | ||
'wp-duotone-filter-', | ||
'wp-elements-', | ||
]; | ||
|
||
/** | ||
* Class name pattern. | ||
* | ||
* @var string | ||
*/ | ||
private $key_pattern; | ||
|
||
/** | ||
* The mapping between uniqid- and wp_unique_id-based class names. | ||
* | ||
* @var array | ||
*/ | ||
private $key_mapping = []; | ||
|
||
/** | ||
* @param Document $dom DOM. | ||
* @param array $args Args. | ||
*/ | ||
public function __construct( $dom, $args = [] ) { | ||
parent::__construct( $dom, $args ); | ||
|
||
$this->key_pattern = sprintf( | ||
'/\b(?P<prefix>%s)(?P<uniqid>[0-9a-f]{13})\b/', | ||
implode( | ||
'|', | ||
self::KEY_PREFIXES | ||
) | ||
); | ||
} | ||
|
||
/** | ||
* Sanitize. | ||
*/ | ||
public function sanitize() { | ||
$elements = $this->dom->xpath->query( | ||
sprintf( | ||
'//*[ %s ]', | ||
implode( | ||
' or ', | ||
array_map( | ||
static function ( $class_name_prefix ) { | ||
return sprintf( | ||
'contains( @class, "%s" )', | ||
$class_name_prefix | ||
); | ||
}, | ||
self::KEY_PREFIXES | ||
) | ||
) | ||
) | ||
); | ||
|
||
$replaced_count = 0; | ||
foreach ( $elements as $element ) { | ||
if ( $this->transform_element_with_class_attribute( $element ) ) { | ||
$replaced_count++; | ||
} | ||
} | ||
|
||
if ( $replaced_count > 0 ) { | ||
$this->transform_styles(); | ||
} | ||
} | ||
|
||
/** | ||
* Transform element with class. | ||
* | ||
* @param Element $element Element. | ||
*/ | ||
public function transform_element_with_class_attribute( Element $element ) { | ||
$class_name = $element->getAttribute( Attribute::CLASS_ ); | ||
|
||
$count = 0; | ||
|
||
$new_class_name = preg_replace_callback( | ||
$this->key_pattern, | ||
function ( $matches ) { | ||
$old_key = $matches[0]; | ||
|
||
if ( ! isset( $this->key_mapping[ $old_key ] ) ) { | ||
$this->key_mapping[ $old_key ] = self::unique_id( $matches['prefix'] ); | ||
} | ||
$new_key = $this->key_mapping[ $old_key ]; | ||
|
||
if ( in_array( $matches['prefix'], [ 'wp-duotone-', 'wp-duotone-filter-' ], true ) ) { | ||
$this->transform_duotone_filter( $old_key, $new_key ); | ||
} | ||
|
||
return $new_key; | ||
}, | ||
$class_name, | ||
-1, | ||
$count | ||
); | ||
if ( 0 === $count ) { | ||
return false; | ||
} else { | ||
$element->setAttribute( Attribute::CLASS_, $new_class_name ); | ||
return true; | ||
} | ||
} | ||
|
||
/** | ||
* Transform duotone filter by updating its ID. | ||
* | ||
* @param string $old_key Old identifier. | ||
* @param string $new_key New identifier. | ||
* | ||
* @return void | ||
*/ | ||
public function transform_duotone_filter( $old_key, $new_key ) { | ||
$svg_filter = $this->dom->getElementById( $old_key ); | ||
if ( $svg_filter instanceof Element && Tag::FILTER === $svg_filter->tagName ) { | ||
$svg_filter->setAttribute( Attribute::ID, $new_key ); | ||
} | ||
} | ||
|
||
/** | ||
* Transform styles. | ||
*/ | ||
public function transform_styles() { | ||
$styles = $this->dom->xpath->query( | ||
sprintf( | ||
'//style[ %s ]', | ||
implode( | ||
' or ', | ||
array_map( | ||
static function ( $key_prefix ) { | ||
return sprintf( | ||
'contains( text(), "%s" )', | ||
$key_prefix | ||
); | ||
}, | ||
self::KEY_PREFIXES | ||
) | ||
) | ||
) | ||
); | ||
|
||
foreach ( $styles as $style ) { | ||
$style->textContent = str_replace( | ||
array_keys( $this->key_mapping ), | ||
array_values( $this->key_mapping ), | ||
$style->textContent | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Gets unique ID. | ||
* | ||
* This is a polyfill for WordPress <5.0.3. | ||
* | ||
* @see wp_unique_id() | ||
* | ||
* @param string $prefix Prefix for the returned ID. | ||
* @return string Unique ID. | ||
*/ | ||
private static function unique_id( $prefix = '' ) { | ||
if ( function_exists( 'wp_unique_id' ) ) { | ||
return wp_unique_id( $prefix ); | ||
} else { | ||
// @codeCoverageIgnoreStart | ||
static $id_counter = 0; | ||
return $prefix . (string) ++$id_counter; | ||
// @codeCoverageIgnoreEnd | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize that these conditions probably will never happen because when the
$old_version
is older than 2.2.2, the$disabled
value will always betrue
here.