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

Render presets coming from the settings of a section #40683

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ Gather blocks in a layout container. ([Source](https://github.com/WordPress/gute

- **Name:** core/group
- **Category:** design
- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Supports:** align (full, wide), anchor, color (background, gradients, link, text), settings, spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** tagName, templateLock

## Heading
Expand Down
73 changes: 73 additions & 0 deletions lib/block-supports/settings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<?php

function gutenberg_register_settings_support( $block_type ) {
$settings_support = false;
if ( property_exists( $block_type, 'supports' ) ) {
$settings_support = _wp_array_get( $block_type->supports, array( 'settings' ), false );
}

if ( ! $settings_support ) {
return;
}

if ( ! $block_type->attributes ) {
$block_type->attributes = array();
}

if ( ! array_key_exists( 'settings', $block_type->attributes ) ) {
$block_type->attributes['settings'] = array(
'type' => 'object',
);
}
}

function gutenberg_render_settings_support( $block_content, $block ) {
// Return early if the block does not have support for settings.
$settings_support = false;
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block['blockName'] );
if ( $block_type && property_exists( $block_type, 'supports' ) ) {
$settings_support = _wp_array_get( $block_type->supports, array( 'settings' ), false );
}
if ( ! $settings_support ) {
return $block_content;
}

// Return early if the block does not have settings applied.
if ( ! isset( $block['attrs']['settings'] ) ) {
return $block_content;
}

// TODO:
// - Render all origins (this code assumes only the custom origin is set so far).
// - Move the origin transformation to WP_Theme_JSON class.
// - Do not render the classes if they're already defined in theme.json.
$settings = $block['attrs']['settings'];
if ( _wp_array_get( $settings, array( 'color', 'palette', 'custom' ), false ) ) {
$settings['color']['palette'] = $settings['color']['palette']['custom'];
}
if ( _wp_array_get( $settings, array( 'color', 'duotone', 'custom' ), false ) ) {
$settings['color']['duotone'] = $settings['color']['duotone']['custom'];
}
if ( _wp_array_get( $settings, array( 'color', 'gradients', 'custom' ), false ) ) {
$settings['color']['gradients'] = $settings['color']['gradients']['custom'];
}
if ( _wp_array_get( $settings, array( 'typography', 'fontSizes', 'custom' ), false ) ) {
$settings['color']['fontSizes'] = $settings['color']['fontSizes']['custom'];
}

$theme_json = new WP_Theme_JSON_Gutenberg( array( 'version' => 2, 'settings' => $settings ), 'custom' );
$styles = $theme_json->get_stylesheet( array( 'variables', 'presets' ) );
gutenberg_enqueue_block_support_styles( $styles );

return $block_content;
}

// Register the block support.
WP_Block_Supports::get_instance()->register(
'settings',
array(
'register_attribute' => 'gutenberg_register_settings_support',
)
);

add_filter( 'render_block', 'gutenberg_render_settings_support', 10, 2 );
1 change: 1 addition & 0 deletions lib/load.php
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,4 @@ function gutenberg_is_experiment_enabled( $name ) {
require __DIR__ . '/block-supports/spacing.php';
require __DIR__ . '/block-supports/dimensions.php';
require __DIR__ . '/block-supports/duotone.php';
require __DIR__ . '/block-supports/settings.php';
6 changes: 4 additions & 2 deletions packages/block-editor/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -762,8 +762,10 @@ _Parameters_

### useSetting

Hook that retrieves the editor setting.
It works with nested objects using by finding the value at path.
Hook that retrieves the given setting for the block instance in use.

It looks up the settings first in the block instance hierarchy.
If none is found, it'll look it up in the block editor store.

_Usage_

Expand Down
74 changes: 53 additions & 21 deletions packages/block-editor/src/components/use-setting/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ import { get } from 'lodash';
* WordPress dependencies
*/
import { useSelect } from '@wordpress/data';
import { __EXPERIMENTAL_PATHS_WITH_MERGE as PATHS_WITH_MERGE } from '@wordpress/blocks';
import {
__EXPERIMENTAL_PATHS_WITH_MERGE as PATHS_WITH_MERGE,
hasBlockSupport,
} from '@wordpress/blocks';

/**
* Internal dependencies
Expand Down Expand Up @@ -91,8 +94,10 @@ const removeCustomPrefixes = ( path ) => {
};

/**
* Hook that retrieves the editor setting.
* It works with nested objects using by finding the value at path.
* Hook that retrieves the given setting for the block instance in use.
*
* It looks up the settings first in the block instance hierarchy.
* If none is found, it'll look it up in the block editor store.
*
* @param {string} path The path to the setting.
* @return {any} Returns the value defined for the setting.
Expand All @@ -102,7 +107,7 @@ const removeCustomPrefixes = ( path ) => {
* ```
*/
export default function useSetting( path ) {
const { name: blockName } = useBlockEditContext();
const { name: blockName, clientId } = useBlockEditContext();

const setting = useSelect(
( select ) => {
Expand All @@ -113,42 +118,69 @@ export default function useSetting( path ) {
);
return undefined;
}
const settings = select( blockEditorStore ).getSettings();

// 1 - Use __experimental features, if available.
// We cascade to the all value if the block one is not available.
let result;
const normalizedPath = removeCustomPrefixes( path );
const defaultsPath = `__experimentalFeatures.${ normalizedPath }`;
const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ normalizedPath }`;
const experimentalFeaturesResult =
get( settings, blockPath ) ?? get( settings, defaultsPath );

if ( experimentalFeaturesResult !== undefined ) {
// 1. Take settings from the block instance or its ancestors.
const candidates = [
...select( blockEditorStore ).getBlockParents( clientId ),
clientId, // The current block is added last, so it overwrites any ancestor.
];
candidates.forEach( ( candidateClientId ) => {
const candidateBlockName = select(
blockEditorStore
).getBlockName( candidateClientId );
if (
hasBlockSupport( candidateBlockName, 'settings', false )
) {
const candidateAtts = select(
blockEditorStore
).getBlockAttributes( candidateClientId );
const candidateResult =
get(
candidateAtts,
`settings.blocks.${ blockName }.${ normalizedPath }`
) ??
get( candidateAtts, `settings.${ normalizedPath }` );
if ( candidateResult !== undefined ) {
result = candidateResult;
}
}
} );

// 2. Fall back to the settings from the block editor store (__experimentalFeatures).
const settings = select( blockEditorStore ).getSettings();
if ( result === undefined ) {
const defaultsPath = `__experimentalFeatures.${ normalizedPath }`;
const blockPath = `__experimentalFeatures.blocks.${ blockName }.${ normalizedPath }`;
result =
get( settings, blockPath ) ?? get( settings, defaultsPath );
}

// Return if the setting was found in either the block instance or the store.
if ( result !== undefined ) {
if ( PATHS_WITH_MERGE[ normalizedPath ] ) {
return (
experimentalFeaturesResult.custom ??
experimentalFeaturesResult.theme ??
experimentalFeaturesResult.default
);
return result.custom ?? result.theme ?? result.default;
}
return experimentalFeaturesResult;
return result;
}

// 2 - Use deprecated settings, otherwise.
// 3. Otherwise, use deprecated settings.
const deprecatedSettingsValue = deprecatedFlags[ normalizedPath ]
? deprecatedFlags[ normalizedPath ]( settings )
: undefined;
if ( deprecatedSettingsValue !== undefined ) {
return deprecatedSettingsValue;
}

// 3 - Fall back for typography.dropCap:
// 4. Fallback for typography.dropCap:
// This is only necessary to support typography.dropCap.
// when __experimentalFeatures are not present (core without plugin).
// To remove when __experimentalFeatures are ported to core.
return normalizedPath === 'typography.dropCap' ? true : undefined;
},
[ blockName, path ]
[ blockName, clientId, path ]
);

return setting;
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/hooks/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import './anchor';
import './custom-class-name';
import './generated-class-name';
import './style';
import './settings';
import './color';
import './duotone';
import './font-size';
Expand Down
32 changes: 32 additions & 0 deletions packages/block-editor/src/hooks/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* WordPress dependencies
*/
import { addFilter } from '@wordpress/hooks';
import { hasBlockSupport } from '@wordpress/blocks';

const hasSettingsSupport = ( blockType ) =>
hasBlockSupport( blockType, 'settings', false );

function addAttribute( settings ) {
if ( ! hasSettingsSupport( settings ) ) {
return settings;
}

// Allow blocks to specify their own attribute definition with default values if needed.
if ( ! settings?.attributes?.settings ) {
settings.attributes = {
...settings.attributes,
settings: {
type: 'object',
},
};
}

return settings;
}

addFilter(
'blocks.registerBlockType',
'core/settings/addAttribute',
addAttribute
);
48 changes: 48 additions & 0 deletions packages/block-editor/src/hooks/test/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* WordPress dependencies
*/
import { applyFilters } from '@wordpress/hooks';

/**
* Internal dependencies
*/
import '../settings';

describe( 'with settings', () => {
const blockSettings = {
save: () => <div className="default" />,
category: 'text',
title: 'block title',
};

describe( 'addAttribute', () => {
const addAttribute = applyFilters.bind(
null,
'blocks.registerBlockType'
);

it( 'does not have settings att if settings block support is not enabled', () => {
const settings = addAttribute( {
...blockSettings,
supports: {
settings: false,
},
} );

expect( settings.attributes ).toBe( undefined );
} );

it( 'has settings att if settings block supports is enabled', () => {
const settings = addAttribute( {
...blockSettings,
supports: {
settings: true,
},
} );

expect( settings.attributes ).toStrictEqual( {
settings: { type: 'object' },
} );
} );
} );
} );
1 change: 1 addition & 0 deletions packages/block-library/src/group/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
}
},
"supports": {
"settings": true,
"align": [ "wide", "full" ],
"anchor": true,
"html": false,
Expand Down