Skip to content

Commit bbc87ad

Browse files
committed
Convert percentage-based width & height attributes to style properties
1 parent 80272f5 commit bbc87ad

File tree

3 files changed

+81
-5
lines changed

3 files changed

+81
-5
lines changed

includes/sanitizers/class-amp-layout-sanitizer.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,52 @@ class AMP_Layout_Sanitizer extends AMP_Base_Sanitizer {
2020
public function sanitize() {
2121
$xpath = new DOMXPath( $this->dom );
2222

23+
/*
24+
* Convert all percentage-based width or height values into style properties.
25+
*
26+
* The following query could be made simpler by using the `ends-with` function, but it is not a valid function in
27+
* XPath 1.0, which the `DOMXPath` class uses.
28+
*/
29+
$nodes = $xpath->query( '//*[ "%" = substring( @width, string-length( @width ) ) or "%" = substring( @height, string-length( @height ) ) ]' );
30+
31+
foreach ( $nodes as $node ) {
32+
$width = $node->getAttribute( 'width' );
33+
$height = $node->getAttribute( 'height' );
34+
$style = $node->getAttribute( 'style' );
35+
36+
$styles = $this->is_empty_attribute_value( $style ) ? [] : $this->parse_style_string( $style );
37+
$attr_converted = false;
38+
39+
// Convert the percentage-based width attribute to a style property.
40+
if ( ! isset( $styles['width'] ) && '%' === substr( $width, -1 ) ) {
41+
// Ignore if its an AMP component and the width is `100%`.
42+
if ( '100%' === $width && strpos( $node->tagName, 'amp-' ) === 0 ) {
43+
continue;
44+
}
45+
46+
$styles['width'] = $width;
47+
$attr_converted = true;
48+
$node->removeAttribute( 'width' );
49+
}
50+
51+
// Convert the percentage-based height attribute to a style property.
52+
if ( ! isset( $styles['height'] ) && '%' === substr( $height, -1 ) ) {
53+
// Ignore if its an AMP component and the height is `100%`.
54+
if ( '100%' === $height && strpos( $node->tagName, 'amp-' ) === 0 ) {
55+
continue;
56+
}
57+
58+
$styles['height'] = $height;
59+
$attr_converted = true;
60+
$node->removeAttribute( 'height' );
61+
}
62+
63+
// If either dimension was converted, update the style property with it.
64+
if ( $attr_converted ) {
65+
$node->setAttribute( 'style', $this->reassemble_style_string( $styles ) );
66+
}
67+
}
68+
2369
/**
2470
* Sanitize AMP nodes to be AMP compatible. Elements with the `layout` attribute will be validated by
2571
* `AMP_Tag_And_Attribute_Sanitizer`.

tests/php/test-amp-iframe-sanitizer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public function get_data() {
8989
'
9090
<amp-iframe src="https://example.com/video/132886713" height="123" width="auto" layout="fixed-height" sandbox="allow-scripts allow-same-origin">
9191
<noscript>
92-
<iframe src="https://example.com/video/132886713" height="123" width="100%"></iframe>
92+
<iframe src="https://example.com/video/132886713" height="123" style="width:100%"></iframe>
9393
</noscript>
9494
</amp-iframe>
9595
',
@@ -100,7 +100,7 @@ public function get_data() {
100100
'
101101
<amp-iframe src="https://example.com/video/132886713" layout="fill" sandbox="allow-scripts allow-same-origin">
102102
<noscript>
103-
<iframe src="https://example.com/video/132886713" width="100%" height="100%"></iframe>
103+
<iframe src="https://example.com/video/132886713" style="width:100%;height:100%"></iframe>
104104
</noscript>
105105
</amp-iframe>
106106
',

tests/php/test-amp-layout-sanitizer.php

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,39 @@ class AMP_Layout_Sanitizer_Test extends WP_UnitTestCase {
1919
*/
2020
public function get_body_data() {
2121
return [
22-
'non_amp_component' => [
23-
'<svg height="10%" width="10%"></svg>',
24-
'<svg height="10%" width="10%"></svg>',
22+
'non_amp_component_with_percent_style_props' => [
23+
'<svg height="100%" width="100%" style="width:20%;height:20%"></svg>',
24+
'<svg height="100%" width="100%" style="width:20%;height:20%"></svg>',
25+
],
26+
27+
'amp_component_with_percent_style_props' => [
28+
'<amp-img height="100%" width="10%" style="width:20%;height:20%"></amp-img>',
29+
'<amp-img height="100%" width="10%" style="width:20%;height:20%"></amp-img>',
30+
],
31+
32+
'non_amp_component_no_percent_attrs' => [
33+
'<svg height="100" width="100"></svg>',
34+
'<svg height="100" width="100"></svg>',
35+
],
36+
37+
'non_amp_component_with_percent_attrs' => [
38+
'<svg height="100%" width="100%"></svg>',
39+
'<svg style="width:100%;height:100%"></svg>',
40+
],
41+
42+
'amp_component_with_percent_attrs' => [
43+
'<amp-img height="10%" width="10%"></amp-img>',
44+
'<amp-img style="width:10%;height:10%"></amp-img>',
45+
],
46+
47+
'amp_component_with_100%_percent_attrs' => [
48+
'<amp-img height="100%" width="100%"></amp-img>',
49+
'<amp-img layout="fill"></amp-img>',
50+
],
51+
52+
'amp_component_with_a_100%_percent_attr' => [
53+
'<amp-img height="10%" width="10"></amp-img>',
54+
'<amp-img width="10" style="height:10%"></amp-img>',
2555
],
2656

2757
'no_width_or_height' => [

0 commit comments

Comments
 (0)