Skip to content

Commit e892b41

Browse files
westonruterpierlon
andcommitted
Support @-moz-document url-prefix() Firefox CSS hack by transforming into @supports (-moz-appearance:meterbar) (#5530)
Co-authored-by: Pierre Gordon <[email protected]>
1 parent 79ee528 commit e892b41

File tree

6 files changed

+193
-110
lines changed

6 files changed

+193
-110
lines changed

includes/sanitizers/class-amp-core-theme-sanitizer.php

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ protected static function get_theme_features_config( $theme_slug ) {
130130
],
131131
'add_twentynineteen_masthead_styles' => [],
132132
'adjust_twentynineteen_images' => [],
133-
'accept_remove_moz_document_at_rule' => [],
134133
];
135134

136135
// Twenty Seventeen.
@@ -289,27 +288,6 @@ public static function get_acceptable_errors() {
289288
return [];
290289
}
291290

292-
/**
293-
* Accept the removal of `@-moz-document` at-rules.
294-
*
295-
* This is temporary with the hope that the at-rule will become allowed in AMP.
296-
*
297-
* @since 2.0.1
298-
* @link https://github.com/ampproject/amp-wp/issues/5302
299-
* @link https://github.com/ampproject/amphtml/issues/26406
300-
*/
301-
public static function accept_remove_moz_document_at_rule() {
302-
AMP_Validation_Error_Taxonomy::accept_validation_errors(
303-
[
304-
AMP_Style_Sanitizer::CSS_SYNTAX_INVALID_AT_RULE => [
305-
[
306-
'at_rule' => '-moz-document',
307-
],
308-
],
309-
]
310-
);
311-
}
312-
313291
/**
314292
* Adds extra theme support arguments on the fly.
315293
*

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

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -381,15 +381,6 @@ public static function get_css_parser_validation_error_codes() {
381381
* @return bool Returns true if the plugin's forked version of PHP-CSS-Parser is loaded by Composer.
382382
*/
383383
public static function has_required_php_css_parser() {
384-
$has_required_methods = (
385-
method_exists( 'Sabberworm\CSS\CSSList\Document', 'splice' )
386-
&&
387-
method_exists( 'Sabberworm\CSS\CSSList\Document', 'replace' )
388-
);
389-
if ( ! $has_required_methods ) {
390-
return false;
391-
}
392-
393384
$reflection = new ReflectionClass( 'Sabberworm\CSS\OutputFormat' );
394385

395386
$has_output_format_extensions = (
@@ -1570,7 +1561,7 @@ private function get_parsed_stylesheet( $stylesheet, $options = [] ) {
15701561
$parsed = null;
15711562
$cache_key = null;
15721563
$cached = true;
1573-
$cache_group = 'amp-parsed-stylesheet-v33'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
1564+
$cache_group = 'amp-parsed-stylesheet-v34'; // This should be bumped whenever the PHP-CSS-Parser is updated or parsed format is updated.
15741565
$use_transients = $this->should_use_transient_caching();
15751566

15761567
$cache_impacting_options = array_merge(
@@ -1743,25 +1734,48 @@ private function splice_imported_stylesheet( Import $item, CSSList $css_list, $o
17431734
);
17441735
$viewport_rules = $parsed_stylesheet['viewport_rules'];
17451736

1746-
if ( ! empty( $parsed_stylesheet['css_document'] ) && method_exists( $css_list, 'replace' ) ) {
1737+
if ( ! empty( $parsed_stylesheet['css_document'] ) ) {
17471738
/**
17481739
* CSS Doc.
17491740
*
17501741
* @var CSSDocument $css_document
17511742
*/
17521743
$css_document = $parsed_stylesheet['css_document'];
17531744

1754-
// Work around bug in \Sabberworm\CSS\CSSList\CSSList::replace() when array keys are not 0-based.
1755-
$css_list->setContents( array_values( $css_list->getContents() ) );
1756-
1757-
$css_list->replace( $item, $css_document->getContents() );
1745+
$this->replace_inside_css_list( $css_list, $item, $css_document->getContents() );
17581746
} else {
17591747
$css_list->remove( $item );
17601748
}
17611749

17621750
return compact( 'validation_results', 'imported_font_urls', 'viewport_rules' );
17631751
}
17641752

1753+
/**
1754+
* Replace an item inside of a CSSList.
1755+
*
1756+
* This is being used instead of `CSSList::splice()` because it uses `array_splice()` which does not work properly
1757+
* if the array keys are not sequentially indexed from 0, which happens when `CSSList::remove()` is employed.
1758+
*
1759+
* @see CSSList::splice()
1760+
* @see CSSList::replace()
1761+
* @see CSSList::remove()
1762+
*
1763+
* @param CSSList $css_list CSS list.
1764+
* @param AtRule|RuleSet|CSSList $old_item Old item.
1765+
* @param AtRule[]|RuleSet[]|CSSList[] $new_items New item(s). If empty, the old item is simply removed.
1766+
* @return bool Whether the replacement was successful.
1767+
*/
1768+
private function replace_inside_css_list( CSSList $css_list, $old_item, $new_items = [] ) {
1769+
$contents = array_values( $css_list->getContents() ); // Required to obtain the offset instead of the index.
1770+
$offset = array_search( $old_item, $contents, true );
1771+
if ( false !== $offset ) {
1772+
array_splice( $contents, $offset, 1, $new_items );
1773+
$css_list->setContents( $contents );
1774+
return true;
1775+
}
1776+
return false;
1777+
}
1778+
17651779
/**
17661780
* Create validated CSS document.
17671781
*
@@ -2138,7 +2152,24 @@ private function process_css_list( CSSList $css_list, $options ) {
21382152
$this->process_css_declaration_block( $css_item, $css_list, $options )
21392153
);
21402154
} elseif ( $css_item instanceof AtRuleBlockList ) {
2141-
if ( ! in_array( $css_item->atRuleName(), $options['allowed_at_rules'], true ) ) {
2155+
if (
2156+
'-moz-document' === $css_item->atRuleName()
2157+
&&
2158+
'url-prefix()' === $css_item->atRuleArgs()
2159+
&&
2160+
in_array( 'supports', $options['allowed_at_rules'], true )
2161+
) {
2162+
// Replace `@-moz-document url-prefix()` with `@supports (-moz-appearance:meterbar)` as an alternative
2163+
// way to provide Firefox-specific style rules. This is a workaround since @-moz-document is not
2164+
// yet allowed in AMP, and this use of @supports is another recognized Firefox-specific CSS hack,
2165+
// per <http://browserhacks.com/#hack-8e9b5504d9fda44ec75169381b3c3157>.
2166+
// For adding @-moz-document to AMP, see <https://github.com/ampproject/amphtml/issues/26406>.
2167+
$new_css_item = new AtRuleBlockList( 'supports', '(-moz-appearance:meterbar)' );
2168+
$new_css_item->setContents( $css_item->getContents() );
2169+
$this->replace_inside_css_list( $css_list, $css_item, [ $new_css_item ] );
2170+
$css_item = $new_css_item; // To process_css_list below.
2171+
$sanitized = false;
2172+
} elseif ( ! in_array( $css_item->atRuleName(), $options['allowed_at_rules'], true ) ) {
21422173
$error = [
21432174
'code' => self::CSS_SYNTAX_INVALID_AT_RULE,
21442175
'at_rule' => $css_item->atRuleName(),
@@ -2702,13 +2733,12 @@ static function( Selector $old_selector ) {
27022733
);
27032734
$important_ruleset->setRules( $importants );
27042735

2705-
$i = array_search( $ruleset, $css_list->getContents(), true );
2706-
if ( false !== $i && method_exists( $css_list, 'splice' ) ) {
2707-
$css_list->splice( $i + 1, 0, [ $important_ruleset ] );
2708-
} else {
2709-
$css_list->append( $important_ruleset );
2736+
$contents = array_values( $css_list->getContents() ); // Ensure keys are 0-indexed and sequential.
2737+
$offset = array_search( $ruleset, $contents, true );
2738+
if ( false !== $offset ) {
2739+
array_splice( $contents, $offset + 1, 0, [ $important_ruleset ] );
2740+
$css_list->setContents( $contents );
27102741
}
2711-
27122742
return $results;
27132743
}
27142744

src/PluginSuppression.php

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ final class PluginSuppression implements Service, Registerable {
4545
*/
4646
private $callback_reflection;
4747

48+
/**
49+
* Original render callbacks for blocks.
50+
*
51+
* Populated via the `register_block_type_args` filter at the moment the block is first registered. This is useful
52+
* to detect a suppressed plugin's blocks which had their `render_callback` wrapped by another function before
53+
* plugin suppression is started at the `wp` action.
54+
*
55+
* @see gutenberg_current_parsed_block_tracking()
56+
* @var array
57+
*/
58+
private $original_block_render_callbacks = [];
59+
4860
/**
4961
* Instantiate the plugin suppression service.
5062
*
@@ -63,6 +75,18 @@ public function register() {
6375
add_filter( 'amp_default_options', [ $this, 'filter_default_options' ] );
6476
add_filter( 'amp_options_updating', [ $this, 'sanitize_options' ], 10, 2 );
6577

78+
add_filter(
79+
'register_block_type_args',
80+
function ( $props, $block_name ) {
81+
if ( isset( $props['render_callback'] ) ) {
82+
$this->original_block_render_callbacks[ $block_name ] = $props['render_callback'];
83+
}
84+
return $props;
85+
},
86+
~PHP_INT_MAX,
87+
2
88+
);
89+
6690
// When a Reader theme is selected and an AMP request is being made, start suppressing as early as possible.
6791
// This can be done because we know it is an AMP page due to the query parameter, but it also _has_ to be done
6892
// specifically for the case of accessing the AMP Customizer (in which customize.php is requested with the query
@@ -426,11 +450,22 @@ private function suppress_blocks( $suppressed_plugins ) {
426450
$registry = WP_Block_Type_Registry::get_instance();
427451

428452
foreach ( $registry->get_all_registered() as $block_type ) {
429-
if ( ! $block_type->is_dynamic() || ! $this->is_callback_plugin_suppressed( $block_type->render_callback, $suppressed_plugins ) ) {
453+
if ( ! $block_type->is_dynamic() ) {
430454
continue;
431455
}
432-
unset( $block_type->script, $block_type->style );
433-
$block_type->render_callback = '__return_empty_string';
456+
457+
if (
458+
$this->is_callback_plugin_suppressed( $block_type->render_callback, $suppressed_plugins )
459+
||
460+
(
461+
isset( $this->original_block_render_callbacks[ $block_type->name ] )
462+
&&
463+
$this->is_callback_plugin_suppressed( $this->original_block_render_callbacks[ $block_type->name ], $suppressed_plugins )
464+
)
465+
) {
466+
unset( $block_type->script, $block_type->style );
467+
$block_type->render_callback = '__return_empty_string';
468+
}
434469
}
435470
}
436471

0 commit comments

Comments
 (0)