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

Fix extraction of class names from string literals in [class] attributes #5403

Merged
merged 2 commits into from
Sep 18, 2020

Conversation

westonruter
Copy link
Member

@westonruter westonruter commented Sep 18, 2020

Summary

Fixes #5401.

This fixes a regression introduced in #5356 for 2.0.2. Certain sites using amp-bind to control whether the mobile nav menu is displayed (for example) would find that if the CSS to toggle visibility would be tree-shaken if the string literals in the amp-bind expression had multiple class names (e.g. 'sidebar open') or whitespace padding (e.g. ' opened '). Impacted themes include Twenty Seventeen given the [class] attribute value: "main-navigation" + ( navMenuToggledOn ? " toggled-on" : '' ). Actually, any theme relying on the AMP_Nav_Menu_Toggle_Sanitizer (via declaring the nav-menu-toggle flag for amp theme support) will have this problem given the padding of ' ' used:

sprintf( "%s + ( $state_id ? %s : '' )", wp_json_encode( $button_el->getAttribute( 'class' ) ), wp_json_encode( ' ' . $this->args['menu_button_toggle_class'] ) )

This regression was introduced (by me) in 0cd5776 with this change:

 		// Find all [class] attributes and capture the contents of any single- or double-quoted strings.
 		foreach ( $this->dom->xpath->query( '//*/@' . Document::AMP_BIND_DATA_ATTR_PREFIX . 'class' ) as $bound_class_attribute ) {
 			if ( preg_match_all( '/([\'"])([^\1]*?)\1/', $bound_class_attribute->nodeValue, $matches ) ) {
-				$classes .= ' ' . implode( ' ', $matches[2] );
+				$classes = array_merge( $classes, $matches[2] );
 			}
 		}
 
 		$class_names = array_merge(
 			$dynamic_class_names,
-			array_unique( array_filter( preg_split( '/\s+/', trim( $classes ) ) ) )
+			array_unique( array_filter( $classes ) )
 		);

In particular, the string literals in the amp-bind expression were no longer getting split by whitespace when added to the $classes array.

The fix is just to make sure that we split $matches[2] into tokenized class names before merging with $classes

Checklist

  • My pull request is addressing an open issue (please create one otherwise).
  • My code is tested and passes existing tests.
  • My code follows the Engineering Guidelines (updates are often made to the guidelines, check it out periodically).

@westonruter westonruter added Bug Something isn't working P0 High priority CSS labels Sep 18, 2020
@westonruter westonruter added this to the v2.0.3 milestone Sep 18, 2020
@google-cla google-cla bot added the cla: yes Signed the Google CLA label Sep 18, 2020
$classes = array_merge( $classes, $matches[2] );
$classes = array_merge(
$classes,
preg_split( '/\s+/', trim( implode( ' ', $matches[2] ) ) )
Copy link
Member Author

@westonruter westonruter Sep 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps better to use PREG_SPLIT_NO_EMPTY here than trim()?

Suggested change
preg_split( '/\s+/', trim( implode( ' ', $matches[2] ) ) )
preg_split( '/\s+/', implode( ' ', $matches[2] ), -1, PREG_SPLIT_NO_EMPTY )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe doesn't matter anyway since below we are filtering out values anyway:

array_unique( array_filter( $classes ) )

@github-actions
Copy link
Contributor

github-actions bot commented Sep 18, 2020

Plugin builds for 8c5ca67 are ready 🛎️!

<style>.sidebar2.visible { display:block }</style>
<style>.sidebar2.visible, .sidebar2.displayed, .sidebar2.shown { display:block }</style>
<style>.sidebar3.open, .sidebar3.abierto { display:block }</style>
<style>.sidebar3.cerrado { display:none }</style>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should have tests with tabs and newlines in between classes as well here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@schlessera The test here is regarding the [class] attributes. I do indeed have newlines and tabs below:

<aside class="sidebar3" [class]='mySidebar.expanded ? " open abierto " : "
closed
cerrado
"'>...</aside>

@westonruter westonruter added WS:Core Work stream for Plugin core and removed P0 High priority labels Sep 18, 2020
@schlessera
Copy link
Collaborator

One Tiktok embed handler test in external-http group failed, assuming due to network connectivity for now...

@westonruter
Copy link
Member Author

@westonruter westonruter merged commit af2bc00 into develop Sep 18, 2020
@westonruter westonruter deleted the fix/bind-class-name-extraction branch September 18, 2020 19:19
@westonruter westonruter added the Changelogged Whether the issue/PR has been added to release notes. label Sep 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Something isn't working Changelogged Whether the issue/PR has been added to release notes. cla: yes Signed the Google CLA CSS WS:Core Work stream for Plugin core
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Version 2.0.2 broke my navigation menus because of CSS sanitizer
2 participants