Skip to content

Commit

Permalink
In the theme JSON class, only skip top-level style properties when co…
Browse files Browse the repository at this point in the history
…mpiling the styles.

In layout.php, if there is no block-level value for blockGap, but a global styles value available for blockGap, use the latter.
  • Loading branch information
ramonjd committed Mar 30, 2022
1 parent 45a8e6b commit 7f7d330
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 12 deletions.
16 changes: 14 additions & 2 deletions lib/block-supports/layout.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function gutenberg_register_layout_support( $block_type ) {
/**
* Generates the CSS corresponding to the provided layout.
*
* @param string $block_name Name of the current block.
* @param string $selector CSS selector.
* @param array $layout Layout object. The one that is passed has already checked the existence of default block layout.
* @param boolean $has_block_gap_support Whether the theme has support for the block gap.
Expand All @@ -36,9 +37,20 @@ function gutenberg_register_layout_support( $block_type ) {
*
* @return string CSS style.
*/
function gutenberg_get_layout_style( $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false ) {
function gutenberg_get_layout_style( $block_name, $selector, $layout, $has_block_gap_support = false, $gap_value = null, $should_skip_gap_serialization = false ) {
$layout_type = isset( $layout['type'] ) ? $layout['type'] : 'default';

// If there is no block-level value for blockGap,
// but a global styles value available for blockGap,
// use the latter.
if ( $has_block_gap_support && empty( $gap_value ) ) {
$block_global_styles = gutenberg_get_global_styles( array( 'blocks', $block_name, 'spacing' ) );

if ( isset( $block_global_styles['blockGap'] ) && ! empty( $block_global_styles['blockGap'] ) ) {
$gap_value = $block_global_styles['blockGap'];
}
}

$style = '';
if ( 'default' === $layout_type ) {
$content_size = isset( $layout['contentSize'] ) ? $layout['contentSize'] : '';
Expand Down Expand Up @@ -176,7 +188,7 @@ function gutenberg_render_layout_support_flag( $block_content, $block ) {
// If a block's block.json skips serialization for spacing or spacing.blockGap,
// don't apply the user-defined value to the styles.
$should_skip_gap_serialization = gutenberg_should_skip_block_supports_serialization( $block_type, 'spacing', 'blockGap' );
$style = gutenberg_get_layout_style( ".$class_name", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization );
$style = gutenberg_get_layout_style( $block['blockName'], ".$class_name", $used_layout, $has_block_gap_support, $gap_value, $should_skip_gap_serialization );
// This assumes the hook only applies to blocks with a single wrapper.
// I think this is a reasonable limitation for that particular hook.
$content = preg_replace(
Expand Down
139 changes: 130 additions & 9 deletions lib/compat/wordpress-6.0/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
* @access private
*/
class WP_Theme_JSON_Gutenberg extends WP_Theme_JSON_5_9 {

/**
* The top-level keys a theme.json can have.
*
Expand All @@ -32,16 +31,62 @@ class WP_Theme_JSON_Gutenberg extends WP_Theme_JSON_5_9 {
);

/**
* Returns the current theme's wanted patterns(slugs) to be
* registered from Pattern Directory.
* Sanitizes the input according to the schemas.
*
* @return array
* @param array $input Structure to sanitize.
* @param array $valid_block_names List of valid block names.
* @param array $valid_element_names List of valid element names.
* @return array The sanitized output.
*/
public function get_patterns() {
if ( isset( $this->theme_json['patterns'] ) && is_array( $this->theme_json['patterns'] ) ) {
return $this->theme_json['patterns'];
protected static function sanitize( $input, $valid_block_names, $valid_element_names ) {
$output = array();

if ( ! is_array( $input ) ) {
return $output;
}
return array();

$output = array_intersect_key( $input, array_flip( static::VALID_TOP_LEVEL_KEYS ) );

// Build the schema based on valid block & element names.
$schema = array();
$schema_styles_elements = array();
foreach ( $valid_element_names as $element ) {
$schema_styles_elements[ $element ] = static::VALID_STYLES;
}
$schema_styles_blocks = array();
$schema_settings_blocks = array();
foreach ( $valid_block_names as $block ) {
$schema_settings_blocks[ $block ] = static::VALID_SETTINGS;
$schema_styles_blocks[ $block ] = static::VALID_STYLES;
$schema_styles_blocks[ $block ]['elements'] = $schema_styles_elements;
}
$schema['styles'] = static::VALID_STYLES;
$schema['styles']['blocks'] = $schema_styles_blocks;
$schema['styles']['elements'] = $schema_styles_elements;
$schema['settings'] = static::VALID_SETTINGS;
$schema['settings']['blocks'] = $schema_settings_blocks;

// Remove anything that's not present in the schema.
foreach ( array( 'styles', 'settings' ) as $subtree ) {
if ( ! isset( $input[ $subtree ] ) ) {
continue;
}

if ( ! is_array( $input[ $subtree ] ) ) {
unset( $output[ $subtree ] );
continue;
}

$result = static::remove_keys_not_in_schema( $input[ $subtree ], $schema[ $subtree ] );

if ( empty( $result ) ) {
unset( $output[ $subtree ] );
} else {
$output[ $subtree ] = $result;
}
}

return $output;
}

/**
Expand All @@ -62,6 +107,7 @@ public function get_patterns() {
protected function get_block_classes( $style_nodes ) {
$block_rules = '';


foreach ( $style_nodes as $metadata ) {
if ( null === $metadata['selector'] ) {
continue;
Expand All @@ -70,7 +116,7 @@ protected function get_block_classes( $style_nodes ) {
$node = _wp_array_get( $this->theme_json, $metadata['path'], array() );
$selector = $metadata['selector'];
$settings = _wp_array_get( $this->theme_json, array( 'settings' ) );
$declarations = static::compute_style_properties( $node, $settings );
$declarations = static::compute_style_properties( $node, $settings, null, $metadata['selector'] );

// 1. Separate the ones who use the general selector
// and the ones who use the duotone selector.
Expand Down Expand Up @@ -119,6 +165,69 @@ protected function get_block_classes( $style_nodes ) {
return $block_rules;
}

/**
* Given a styles array, it extracts the style properties
* and adds them to the $declarations array following the format:
*
* ```php
* array(
* 'name' => 'property_name',
* 'value' => 'property_value,
* )
* ```
*
* @param array $styles Styles to process.
* @param array $settings Theme settings.
* @param array $properties Properties metadata.
* @param string|null $selector Current selector.
* @return array Returns the modified $declarations.
*/
protected static function compute_style_properties( $styles, $settings = array(), $properties = null, $selector = null ) {
if ( null === $properties ) {
$properties = static::PROPERTIES_METADATA;
}

$declarations = array();
if ( empty( $styles ) ) {
return $declarations;
}

foreach ( $properties as $css_property => $value_path ) {
// Some styles such as blockGap are only meant to be available at the top level (ROOT_BLOCK_SELECTOR),
// hence we only output styles at the top level.
if ( 'top' === _wp_array_get( self::VALID_STYLES, array( $value_path[0], $value_path[1] ), null ) && static::ROOT_BLOCK_SELECTOR !== $selector ) {
continue;
}

$value = static::get_property_value( $styles, $value_path );

// Look up protected properties, keyed by value path.
// Skip protected properties that are explicitly set to `null`.
if ( is_array( $value_path ) ) {
$path_string = implode( '.', $value_path );
if (
array_key_exists( $path_string, static::PROTECTED_PROPERTIES ) &&
_wp_array_get( $settings, static::PROTECTED_PROPERTIES[ $path_string ], null ) === null
) {
continue;
}
}

// Skip if empty and not "0" or value represents array of longhand values.
$has_missing_value = empty( $value ) && ! is_numeric( $value );
if ( $has_missing_value || is_array( $value ) ) {
continue;
}

$declarations[] = array(
'name' => $css_property,
'value' => $value,
);
}

return $declarations;
}

/**
* Returns a valid theme.json for a theme.
* Essentially, it flattens the preset data.
Expand Down Expand Up @@ -162,4 +271,16 @@ public function get_data() {
return $flattened_theme_json;
}

/**
* Returns the current theme's wanted patterns(slugs) to be
* registered from Pattern Directory.
*
* @return array
*/
public function get_patterns() {
if ( isset( $this->theme_json['patterns'] ) && is_array( $this->theme_json['patterns'] ) ) {
return $this->theme_json['patterns'];
}
return array();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
__experimentalBoxControl as BoxControl,
__experimentalUnitControl as UnitControl,
__experimentalUseCustomUnits as useCustomUnits,
} from '@wordpress/components';
import { __experimentalUseCustomSides as useCustomSides } from '@wordpress/block-editor';
Expand All @@ -20,8 +21,9 @@ const AXIAL_SIDES = [ 'horizontal', 'vertical' ];
export function useHasDimensionsPanel( name ) {
const hasPadding = useHasPadding( name );
const hasMargin = useHasMargin( name );
const hasGap = useHasGap( name );

return hasPadding || hasMargin;
return hasPadding || hasMargin || hasGap;
}

function useHasPadding( name ) {
Expand All @@ -38,6 +40,13 @@ function useHasMargin( name ) {
return settings && supports.includes( 'margin' );
}

function useHasGap( name ) {
const supports = getSupportedGlobalStylesPanels( name );
const [ settings ] = useSetting( 'spacing.blockGap', name );

return settings && supports.includes( '--wp--style--block-gap' );
}

function filterValuesBySides( values, sides ) {
if ( ! sides ) {
// If no custom side configuration all sides are opted into by default.
Expand Down Expand Up @@ -79,6 +88,7 @@ function splitStyleValue( value ) {
export default function DimensionsPanel( { name } ) {
const showPaddingControl = useHasPadding( name );
const showMarginControl = useHasMargin( name );
const showGapControl = useHasGap( name );
const units = useCustomUnits( {
availableUnits: useSetting( 'spacing.units', name )[ 0 ] || [
'%',
Expand Down Expand Up @@ -118,9 +128,15 @@ export default function DimensionsPanel( { name } ) {
const resetMarginValue = () => setMarginValues( {} );
const hasMarginValue = () =>
!! marginValues && Object.keys( marginValues ).length;

const [ gapValue, setGapValue ] = useStyle( 'spacing.blockGap', name );
const resetGapValue = () => setGapValue( undefined );
const hasGapValue = () => !! gapValue;

const resetAll = () => {
resetPaddingValue();
resetMarginValue();
resetGapValue();
};

return (
Expand Down Expand Up @@ -161,6 +177,23 @@ export default function DimensionsPanel( { name } ) {
/>
</ToolsPanelItem>
) }
{ showGapControl && (
<ToolsPanelItem
hasValue={ hasGapValue }
label={ __( 'Block spacing' ) }
onDeselect={ resetGapValue }
isShownByDefault={ true }
>
<UnitControl
label={ __( 'Block spacing' ) }
__unstableInputWidth="80px"
min={ 0 }
onChange={ setGapValue }
units={ units }
value={ gapValue }
/>
</ToolsPanelItem>
) }
</ToolsPanel>
);
}

0 comments on commit 7f7d330

Please sign in to comment.