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

Do not render global styles coming from the server in the site editor #40185

Merged
merged 9 commits into from
Apr 13, 2022
85 changes: 56 additions & 29 deletions lib/compat/wordpress-6.0/block-editor-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,49 @@
* @package gutenberg
*/

/**
* Returns true if the style is coming from global styles.
*
* @param array $style Array containing a '__unstableType' key.
* @return boolean
*/
function gutenberg_is_global_styles_in_5_8( $style ) {
if ( isset( $style['__unstableType'] ) && ( 'globalStyles' === $style['__unstableType'] ) ) {
return true;
}

return false;
}

/**
* Returns true if the style is coming from global styles.
*
* @param array $style Array containing a '__unstableType' key and a 'css' key with the actual CSS.
* @return boolean
*/
function gutenberg_is_global_styles_in_5_9( $style ) {
/*
* In WordPress 5.9 we don't have a mechanism to distinguish block styles generated via theme.json
* from styles that come from the stylesheet of a theme.
*
* We do know that the block styles generated via theme.json have some rules for alignment.
* Hence, by detecting the presence of these rules, we can tell with high certainty
* whether or not the incoming $style has been generated from theme.json.
*/
$root_styles = '.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
$root_styles .= '.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
$root_styles .= '.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';

if (
( isset( $style['__unstableType'] ) && ( 'presets' === $style['__unstableType'] ) ) ||
( isset( $style['__unstableType'] ) && ( 'theme' === $style['__unstableType'] ) && str_contains( $style['css'], $root_styles ) )
) {
return true;
}

return false;
}

/**
* Adds styles and __experimentalFeatures to the block editor settings.
*
Expand All @@ -15,15 +58,6 @@
function gutenberg_get_block_editor_settings( $settings ) {
// Set what is the context for this data request.
$context = 'other';
if (
is_callable( 'get_current_screen' ) &&
function_exists( 'gutenberg_is_edit_site_page' ) &&
is_object( get_current_screen() ) &&
gutenberg_is_edit_site_page( get_current_screen()->id )
) {
$context = 'site-editor';
}

if (
defined( 'REST_REQUEST' ) &&
REST_REQUEST &&
Expand All @@ -34,49 +68,41 @@ function_exists( 'gutenberg_is_edit_site_page' ) &&
}

if ( 'other' === $context ) {
global $wp_version;
$is_wp_5_8 = version_compare( $wp_version, '5.8', '>=' ) && version_compare( $wp_version, '5.9', '<' );
$is_wp_5_9 = version_compare( $wp_version, '5.9', '>=' ) && version_compare( $wp_version, '6.0-beta1', '<' );
$is_wp_6_0 = version_compare( $wp_version, '6.0-beta1', '>=' );

// Make sure the styles array exists.
// In some contexts, like the navigation editor, it doesn't.
if ( ! isset( $settings['styles'] ) ) {
$settings['styles'] = array();
}

// Remove existing global styles provided by core.
$styles_without_existing_global_styles = array();
foreach ( $settings['styles'] as $style ) {
if (
! isset( $style['__unstableType'] ) ||
// '__unstableType' is 'globalStyles' for WordPress 5.8 and 'presets' for WordPress 5.9.
//
// Note that styles classified as'theme', can be from the theme stylesheet
// or from the theme.json (the styles section).
// We are unable to identify which is which, so we can't remove and recreate those.
// Instead, we reload the theme.json styles from the plugin.
// Because they'll use the same selectors and load later,
// they'll have higher priority than core's.
//
// Theoretically, this approach with 'theme' styles could be problematic:
// if we remove style properties in the plugin, if selectors change, etc.
// We need to address this issue directly in core by alowing to identify
// styles coming from theme.json.
//
// A final note about 'theme' styles: this flag is used to identify theme
// styles that may need to be removed if the user toggles
// "Preferences > Use theme styles" in the preferences modal.
//
! in_array( $style['__unstableType'], array( 'globalStyles', 'presets' ), true )
( $is_wp_5_8 && ! gutenberg_is_global_styles_in_5_8( $style ) ) || // Can be removed when plugin minimum version is 5.9.
( $is_wp_5_9 && ! gutenberg_is_global_styles_in_5_9( $style ) ) || // Can be removed when plugin minimum version is 6.0.
( $is_wp_6_0 && ( ! isset( $style['isGlobalStyles'] ) || ! $style['isGlobalStyles'] ) )
) {
$styles_without_existing_global_styles[] = $style;
}
}

// Recreate global styles.
$new_global_styles = array();
$presets = array(
array(
'css' => 'variables',
'__unstableType' => 'presets',
'isGlobalStyles' => true,
),
array(
'css' => 'presets',
'__unstableType' => 'presets',
'isGlobalStyles' => true,
),
);
foreach ( $presets as $preset_style ) {
Expand All @@ -91,6 +117,7 @@ function_exists( 'gutenberg_is_edit_site_page' ) &&
$block_classes = array(
'css' => 'styles',
'__unstableType' => 'theme',
'isGlobalStyles' => true,
);
$actual_css = gutenberg_get_global_stylesheet( array( $block_classes['css'] ) );
if ( '' !== $actual_css ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,10 @@ describe( 'global styles renderer', () => {
};

expect( toStyles( tree, blockSelectors ) ).toEqual(
'.wp-site-blocks > * { margin-top: 0; margin-bottom: 0; }.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); }body{background-color: red;margin: 10px;padding: 10px;}h1{font-size: 42px;}.wp-block-group{margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color: hotpink;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}'
'body {margin: 0;}' +
'body{background-color: red;margin: 10px;padding: 10px;}h1{font-size: 42px;}.wp-block-group{margin-top: 10px;margin-right: 20px;margin-bottom: 30px;margin-left: 40px;padding-top: 11px;padding-right: 22px;padding-bottom: 33px;padding-left: 44px;}h1,h2,h3,h4,h5,h6{color: orange;}h1 a,h2 a,h3 a,h4 a,h5 a,h6 a{color: hotpink;}' +
'.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }.wp-site-blocks > .alignright { float: right; margin-left: 2em; }.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }' +
'.has-white-color{color: var(--wp--preset--color--white) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}h1.has-blue-color,h2.has-blue-color,h3.has-blue-color,h4.has-blue-color,h5.has-blue-color,h6.has-blue-color{color: var(--wp--preset--color--blue) !important;}h1.has-blue-background-color,h2.has-blue-background-color,h3.has-blue-background-color,h4.has-blue-background-color,h5.has-blue-background-color,h6.has-blue-background-color{background-color: var(--wp--preset--color--blue) !important;}h1.has-blue-border-color,h2.has-blue-border-color,h3.has-blue-border-color,h4.has-blue-border-color,h5.has-blue-border-color,h6.has-blue-border-color{border-color: var(--wp--preset--color--blue) !important;}'
);
} );
} );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,12 @@ import {
import { useEffect, useState, useContext } from '@wordpress/element';
import { getCSSRules } from '@wordpress/style-engine';

/**
* Internal dependencies
*/

/**
* Internal dependencies
*/
import { PRESET_METADATA, ROOT_BLOCK_SELECTOR } from './utils';
import { GlobalStylesContext } from './context';
import { useSetting } from './hooks';

function compileStyleValue( uncompiledValue ) {
const VARIABLE_REFERENCE_PREFIX = 'var:';
Expand Down Expand Up @@ -329,12 +326,19 @@ export const toCustomProperties = ( tree, blockSelectors ) => {
return ruleset;
};

export const toStyles = ( tree, blockSelectors ) => {
export const toStyles = ( tree, blockSelectors, hasBlockGapSupport ) => {
const nodesWithStyles = getNodesWithStyles( tree, blockSelectors );
const nodesWithSettings = getNodesWithSettings( tree, blockSelectors );

let ruleset =
'.wp-site-blocks > * { margin-top: 0; margin-bottom: 0; }.wp-site-blocks > * + * { margin-top: var( --wp--style--block-gap ); }';
/*
* Reset default browser margin on the root body element.
* This is set on the root selector **before** generating the ruleset
* from the `theme.json`. This is to ensure that if the `theme.json` declares
* `margin` in its `spacing` declaration for the `body` element then these
* user-generated values take precedence in the CSS cascade.
* @link https://github.com/WordPress/gutenberg/issues/36147.
*/
let ruleset = 'body {margin: 0;}';
nodesWithStyles.forEach( ( { selector, styles } ) => {
const declarations = getStylesDeclarations( styles );
if ( declarations.length === 0 ) {
Expand All @@ -343,6 +347,26 @@ export const toStyles = ( tree, blockSelectors ) => {
ruleset = ruleset + `${ selector }{${ declarations.join( ';' ) };}`;
} );

/* Add alignment / layout styles */
ruleset =
ruleset +
'.wp-site-blocks > .alignleft { float: left; margin-right: 2em; }';
ruleset =
ruleset +
'.wp-site-blocks > .alignright { float: right; margin-left: 2em; }';
ruleset =
ruleset +
'.wp-site-blocks > .aligncenter { justify-content: center; margin-left: auto; margin-right: auto; }';

if ( hasBlockGapSupport ) {
ruleset =
ruleset +
'.wp-site-blocks > * { margin-block-start: 0; margin-block-end: 0; }';
ruleset =
ruleset +
'.wp-site-blocks > * + * { margin-block-start: var( --wp--style--block-gap ); }';
}

nodesWithSettings.forEach( ( { selector, presets } ) => {
if ( ROOT_BLOCK_SELECTOR === selector ) {
// Do not add extra specificity for top-level classes.
Expand Down Expand Up @@ -378,6 +402,8 @@ export function useGlobalStylesOutput() {
const [ stylesheets, setStylesheets ] = useState( [] );
const [ settings, setSettings ] = useState( {} );
const { merged: mergedConfig } = useContext( GlobalStylesContext );
const [ blockGap ] = useSetting( 'spacing.blockGap' );
const hasBlockGapSupport = blockGap !== null;

useEffect( () => {
if ( ! mergedConfig?.styles || ! mergedConfig?.settings ) {
Expand All @@ -389,7 +415,11 @@ export function useGlobalStylesOutput() {
mergedConfig,
blockSelectors
);
const globalStyles = toStyles( mergedConfig, blockSelectors );
const globalStyles = toStyles(
mergedConfig,
blockSelectors,
hasBlockGapSupport
);
setStylesheets( [
{
css: customProperties,
Expand All @@ -403,5 +433,5 @@ export function useGlobalStylesOutput() {
setSettings( mergedConfig.settings );
}, [ mergedConfig ] );

return [ stylesheets, settings ];
return [ stylesheets, settings, hasBlockGapSupport ];
}