-
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
1094: Transform CSS selectors according to sanitizer HTML element to AMP component conversions #1175
Merged
Merged
1094: Transform CSS selectors according to sanitizer HTML element to AMP component conversions #1175
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
e530045
Initial take on CSS selector conversions according to AMP.
miina f2395ee
Add @todo note.
miina 958fd48
Add @todo note.
miina 488ebd2
Merge remote-tracking branch 'origin/develop' into add/1094-convert_c…
miina 077a094
Add additional mappings.
miina ed1cc03
Merge branch 'develop' of https://github.com/Automattic/amp-wp into a…
westonruter 6091533
Merge remote-tracking branch 'origin/develop' into add/1094-convert_c…
miina 7a218aa
Add get_selector_conversion_mapping method to all sanitizers and util…
westonruter fcc0b44
Merge branch 'add/1094-convert_css_selectors' of github.com:Automatti…
miina d815891
Refactor code.
miina 12c9ff8
Use tree-shaking in test_amp_selector_conversion
westonruter 91e3eef
Include selector mappings in dynamic_element_selectors to preserve se…
westonruter 04f6b85
Preserve original pb_feed class on translated amp-playbuzz elements
westonruter 19db2c1
Allow tree shaking on selectors with dynamic elements when non-dynami…
westonruter 1b8405a
Stop replacing CSS selectors which are addressing AMP components dire…
miina 592aca7
Merge branch 'add/1094-convert_css_selectors' of github.com:Automatti…
miina a564410
Fix tests.
miina 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
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
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
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
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -182,6 +182,13 @@ class AMP_Style_Sanitizer extends AMP_Base_Sanitizer { | |
*/ | ||
private $processed_imported_stylesheet_urls = array(); | ||
|
||
/** | ||
* Mapping of HTML element selectors to AMP selector elements. | ||
* | ||
* @var array | ||
*/ | ||
private $selector_mappings = array(); | ||
|
||
/** | ||
* Get error codes that can be raised during parsing of CSS. | ||
* | ||
|
@@ -308,6 +315,36 @@ private function get_used_tag_names() { | |
return $this->used_tag_names; | ||
} | ||
|
||
/** | ||
* Run logic before any sanitizers are run. | ||
* | ||
* After the sanitizers are instantiated but before calling sanitize on each of them, this | ||
* method is called with list of all the instantiated sanitizers. | ||
* | ||
* @param AMP_Base_Sanitizer[] $sanitizers Sanitizers. | ||
*/ | ||
public function init( $sanitizers ) { | ||
parent::init( $sanitizers ); | ||
|
||
foreach ( $sanitizers as $sanitizer ) { | ||
foreach ( $sanitizer->get_selector_conversion_mapping() as $html_selectors => $amp_selectors ) { | ||
if ( ! isset( $this->selector_mappings[ $html_selectors ] ) ) { | ||
$this->selector_mappings[ $html_selectors ] = $amp_selectors; | ||
} else { | ||
$this->selector_mappings[ $html_selectors ] = array_unique( | ||
array_merge( $this->selector_mappings[ $html_selectors ], $amp_selectors ) | ||
); | ||
} | ||
|
||
// Prevent selectors like `amp-img img` getting deleted since `img` does not occur in the DOM. | ||
$this->args['dynamic_element_selectors'] = array_merge( | ||
$this->args['dynamic_element_selectors'], | ||
$this->selector_mappings[ $html_selectors ] | ||
); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Sanitize CSS styles within the HTML contained in this instance's DOMDocument. | ||
* | ||
|
@@ -647,7 +684,7 @@ private function fetch_external_stylesheet( $url ) { | |
private function process_stylesheet( $stylesheet, $options = array() ) { | ||
$parsed = null; | ||
$cache_key = null; | ||
$cache_group = 'amp-parsed-stylesheet-v6'; | ||
$cache_group = 'amp-parsed-stylesheet-v7'; | ||
|
||
$cache_impacting_options = array_merge( | ||
wp_array_slice_assoc( | ||
|
@@ -912,6 +949,16 @@ private function prepare_stylesheet( $stylesheet_string, $options = array() ) { | |
$pattern .= preg_quote( $after_declaration_block, '#' ); | ||
$pattern .= '#s'; | ||
|
||
$dynamic_selector_pattern = null; | ||
if ( ! empty( $this->args['dynamic_element_selectors'] ) ) { | ||
$dynamic_selector_pattern = implode( '|', array_map( | ||
function( $selector ) { | ||
return preg_quote( $selector, '#' ); | ||
}, | ||
$this->args['dynamic_element_selectors'] | ||
) ); | ||
} | ||
|
||
$split_stylesheet = preg_split( $pattern, $stylesheet_string, -1, PREG_SPLIT_DELIM_CAPTURE ); | ||
$length = count( $split_stylesheet ); | ||
for ( $i = 0; $i < $length; $i++ ) { | ||
|
@@ -929,6 +976,11 @@ private function prepare_stylesheet( $stylesheet_string, $options = array() ) { | |
// Remove attribute selectors to eliminate false negative, such as with `.social-navigation a[href*="example.com"]:before`. | ||
$reduced_selector = preg_replace( '/\[\w.*?\]/', '', $reduced_selector ); | ||
|
||
// Ignore any selector terms that occur under a dynamic selector. | ||
if ( $dynamic_selector_pattern ) { | ||
$reduced_selector = preg_replace( '#((?:' . $dynamic_selector_pattern . ')(?:\.[a-z0-9_-]+)*)[^a-z0-9_-].*#si', '$1', $reduced_selector . ' ' ); | ||
} | ||
|
||
$reduced_selector = preg_replace_callback( | ||
'/\.([a-zA-Z0-9_-]+)/', | ||
function( $matches ) use ( $selector, &$selectors_parsed ) { | ||
|
@@ -1236,6 +1288,10 @@ private function real_path_urls( $urls, $stylesheet_url ) { | |
private function process_css_declaration_block( RuleSet $ruleset, CSSList $css_list, $options ) { | ||
$results = array(); | ||
|
||
if ( $ruleset instanceof DeclarationBlock ) { | ||
$this->ampify_ruleset_selectors( $ruleset ); | ||
} | ||
|
||
// Remove disallowed properties. | ||
if ( ! empty( $options['property_whitelist'] ) ) { | ||
$properties = $ruleset->getRules(); | ||
|
@@ -1754,6 +1810,45 @@ private function finalize_styles() { | |
} | ||
} | ||
|
||
/** | ||
* Convert CSS selectors. | ||
* | ||
* @param DeclarationBlock $ruleset Ruleset. | ||
*/ | ||
private function ampify_ruleset_selectors( $ruleset ) { | ||
$selectors = array(); | ||
$replacements = 0; | ||
foreach ( $ruleset->getSelectors() as $old_selector ) { | ||
$edited_selectors = array( $old_selector->getSelector() ); | ||
foreach ( $this->selector_mappings as $html_selector => $amp_selectors ) { // Note: The $selector_mappings array contains ~6 items. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These notes are here because 4 level of loop nesting is normally something that is a big red flag for performance. |
||
$html_pattern = '/(?<=^|[^a-z0-9_-])' . preg_quote( $html_selector ) . '(?=$|[^a-z0-9_-])/i'; | ||
foreach ( $edited_selectors as &$edited_selector ) { // Note: The $edited_selectors array contains only item in the normal case. | ||
$original_selector = $edited_selector; | ||
$amp_selector = array_shift( $amp_selectors ); | ||
$amp_tag_pattern = '/(?<=^|[^a-z0-9_-])' . preg_quote( $amp_selector ) . '(?=$|[^a-z0-9_-])/i'; | ||
preg_match( $amp_tag_pattern, $edited_selector, $matches ); | ||
if ( ! empty( $matches ) && $amp_selector === $matches[0] ) { | ||
continue; | ||
} | ||
$edited_selector = preg_replace( $html_pattern, $amp_selector, $edited_selector, -1, $count ); | ||
if ( ! $count ) { | ||
continue; | ||
} | ||
$replacements += $count; | ||
while ( ! empty( $amp_selectors ) ) { // Note: This array contains only a couple items. | ||
$amp_selector = array_shift( $amp_selectors ); | ||
$edited_selectors[] = preg_replace( $html_pattern, $amp_selector, $original_selector, -1, $count ); | ||
} | ||
} | ||
} | ||
$selectors = array_merge( $selectors, $edited_selectors ); | ||
} | ||
|
||
if ( $replacements > 0 ) { | ||
$ruleset->setSelectors( $selectors ); | ||
} | ||
} | ||
|
||
/** | ||
* Finalize a stylesheet set (amp-custom or amp-keyframes). | ||
* | ||
|
@@ -1778,16 +1873,6 @@ private function finalize_stylesheet_set( $stylesheet_set ) { | |
) ); | ||
} | ||
|
||
$dynamic_selector_pattern = null; | ||
if ( $should_tree_shake && ! empty( $this->args['dynamic_element_selectors'] ) ) { | ||
$dynamic_selector_pattern = '#' . implode( '|', array_map( | ||
function( $selector ) { | ||
return preg_quote( $selector, '#' ); | ||
}, | ||
$this->args['dynamic_element_selectors'] | ||
) ) . '#'; | ||
} | ||
|
||
$stylesheet_set['processed_nodes'] = array(); | ||
|
||
$final_size = 0; | ||
|
@@ -1804,8 +1889,6 @@ function( $selector ) { | |
$selectors = array(); | ||
foreach ( $selectors_parsed as $selector => $parsed_selector ) { | ||
$should_include = ( | ||
( $dynamic_selector_pattern && preg_match( $dynamic_selector_pattern, $selector ) ) | ||
|| | ||
( | ||
// If all class names are used in the doc. | ||
( | ||
|
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.
Note that
self:AMP_IMAGE_LIGHTBOX_ID
is also used byAMP_Gallery_Block_Sanitizer
, that's why it toAMP_Base_Sanitizer
.