diff --git a/docs/how-to-guides/themes/theme-json.md b/docs/how-to-guides/themes/theme-json.md
index 8e2b60a7693eb6..be7489d78c05e0 100644
--- a/docs/how-to-guides/themes/theme-json.md
+++ b/docs/how-to-guides/themes/theme-json.md
@@ -289,6 +289,7 @@ The settings section has the following structure:
"fontWeight": true,
"letterSpacing": true,
"lineHeight": false,
+ "textColumns": false,
"textDecoration": true,
"textTransform": true
},
@@ -824,6 +825,7 @@ Each block declares which style properties it exposes via the [block supports me
"fontWeight": "value",
"letterSpacing": "value",
"lineHeight": "value",
+ "textColumns": "value",
"textDecoration": "value",
"textTransform": "value"
},
diff --git a/docs/reference-guides/theme-json-reference/theme-json-living.md b/docs/reference-guides/theme-json-reference/theme-json-living.md
index acc0a499ec61b0..c8a59c5e10f0c0 100644
--- a/docs/reference-guides/theme-json-reference/theme-json-living.md
+++ b/docs/reference-guides/theme-json-reference/theme-json-living.md
@@ -134,6 +134,7 @@ Settings related to typography.
| fluid | undefined | false | |
| letterSpacing | boolean | true | |
| lineHeight | boolean | false | |
+| textColumns | boolean | false | |
| textDecoration | boolean | true | |
| textTransform | boolean | true | |
| dropCap | boolean | true | |
@@ -204,6 +205,7 @@ Typography styles.
| fontWeight | string, object | |
| letterSpacing | string, object | |
| lineHeight | string, object | |
+| textColumns | string | |
| textDecoration | string, object | |
| textTransform | string, object | |
diff --git a/docs/reference-guides/theme-json-reference/theme-json-migrations.md b/docs/reference-guides/theme-json-reference/theme-json-migrations.md
index cac253f64ffbe9..b043ca1fba52ac 100644
--- a/docs/reference-guides/theme-json-reference/theme-json-migrations.md
+++ b/docs/reference-guides/theme-json-reference/theme-json-migrations.md
@@ -41,6 +41,7 @@ Additions to settings:
- `settings.typography.fontStyle`
- `settings.typography.fontWeight`
- `settings.typography.letterSpacing`
+- `settings.typography.textColumns`
- `settings.typography.textDecoration`
- `settings.typography.textTransform`
@@ -55,6 +56,7 @@ Additions to styles:
- `styles.typography.fontStyle`
- `styles.typography.fontWeight`
- `styles.typography.letterSpacing`
+- `styles.typography.textColumns`
- `styles.typography.textDecoration`
- `styles.typography.textTransform`
diff --git a/lib/block-supports/typography.php b/lib/block-supports/typography.php
index c2e033eb176778..a7a26423e32d6a 100644
--- a/lib/block-supports/typography.php
+++ b/lib/block-supports/typography.php
@@ -26,6 +26,7 @@ function gutenberg_register_typography_support( $block_type ) {
$has_font_weight_support = _wp_array_get( $typography_supports, array( '__experimentalFontWeight' ), false );
$has_letter_spacing_support = _wp_array_get( $typography_supports, array( '__experimentalLetterSpacing' ), false );
$has_line_height_support = _wp_array_get( $typography_supports, array( 'lineHeight' ), false );
+ $has_text_columns_support = _wp_array_get( $typography_supports, array( 'textColumns' ), false );
$has_text_decoration_support = _wp_array_get( $typography_supports, array( '__experimentalTextDecoration' ), false );
$has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false );
@@ -35,6 +36,7 @@ function gutenberg_register_typography_support( $block_type ) {
|| $has_font_weight_support
|| $has_letter_spacing_support
|| $has_line_height_support
+ || $has_text_columns_support
|| $has_text_decoration_support
|| $has_text_transform_support;
@@ -91,6 +93,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$has_font_weight_support = _wp_array_get( $typography_supports, array( '__experimentalFontWeight' ), false );
$has_letter_spacing_support = _wp_array_get( $typography_supports, array( '__experimentalLetterSpacing' ), false );
$has_line_height_support = _wp_array_get( $typography_supports, array( 'lineHeight' ), false );
+ $has_text_columns_support = _wp_array_get( $typography_supports, array( 'textColumns' ), false );
$has_text_decoration_support = _wp_array_get( $typography_supports, array( '__experimentalTextDecoration' ), false );
$has_text_transform_support = _wp_array_get( $typography_supports, array( '__experimentalTextTransform' ), false );
@@ -100,6 +103,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$should_skip_font_style = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontStyle' );
$should_skip_font_weight = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'fontWeight' );
$should_skip_line_height = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'lineHeight' );
+ $should_skip_text_columns = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textColumns' );
$should_skip_text_decoration = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textDecoration' );
$should_skip_text_transform = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textTransform' );
$should_skip_letter_spacing = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'letterSpacing' );
@@ -135,6 +139,10 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$typography_block_styles['lineHeight'] = _wp_array_get( $block_attributes, array( 'style', 'typography', 'lineHeight' ), null );
}
+ if ( $has_text_columns_support && ! $should_skip_text_columns && isset( $block_attributes['style']['typography']['textColumns'] ) ) {
+ $typography_block_styles['textColumns'] = _wp_array_get( $block_attributes, array( 'style', 'typography', 'textColumns' ), null );
+ }
+
if ( $has_text_decoration_support && ! $should_skip_text_decoration && isset( $block_attributes['style']['typography']['textDecoration'] ) ) {
$typography_block_styles['textDecoration'] =
gutenberg_typography_get_preset_inline_style_value( $block_attributes['style']['typography']['textDecoration'], 'text-decoration' );
diff --git a/lib/class-wp-theme-json-gutenberg.php b/lib/class-wp-theme-json-gutenberg.php
index 4597ae059f05af..b71a7c95457418 100644
--- a/lib/class-wp-theme-json-gutenberg.php
+++ b/lib/class-wp-theme-json-gutenberg.php
@@ -229,6 +229,7 @@ class WP_Theme_JSON_Gutenberg {
'border-left-width' => array( 'border', 'left', 'width' ),
'border-left-style' => array( 'border', 'left', 'style' ),
'color' => array( 'color', 'text' ),
+ 'column-count' => array( 'typography', 'textColumns' ),
'font-family' => array( 'typography', 'fontFamily' ),
'font-size' => array( 'typography', 'fontSize' ),
'font-style' => array( 'typography', 'fontStyle' ),
@@ -396,6 +397,7 @@ class WP_Theme_JSON_Gutenberg {
'fontWeight' => null,
'letterSpacing' => null,
'lineHeight' => null,
+ 'textColumns' => null,
'textDecoration' => null,
'textTransform' => null,
),
@@ -456,6 +458,7 @@ class WP_Theme_JSON_Gutenberg {
'fontWeight' => null,
'letterSpacing' => null,
'lineHeight' => null,
+ 'textColumns' => null,
'textDecoration' => null,
'textTransform' => null,
),
diff --git a/lib/theme.json b/lib/theme.json
index 8e60c945456b1b..fa3a872518adc7 100644
--- a/lib/theme.json
+++ b/lib/theme.json
@@ -398,6 +398,7 @@
"fontWeight": true,
"letterSpacing": true,
"lineHeight": false,
+ "textColumns": false,
"textDecoration": true,
"textTransform": true
},
diff --git a/packages/block-editor/src/components/global-styles/hooks.js b/packages/block-editor/src/components/global-styles/hooks.js
index 2414f3d4b4b9c7..c169cb03a60836 100644
--- a/packages/block-editor/src/components/global-styles/hooks.js
+++ b/packages/block-editor/src/components/global-styles/hooks.js
@@ -65,6 +65,7 @@ const VALID_SETTINGS = [
'typography.fontWeight',
'typography.letterSpacing',
'typography.lineHeight',
+ 'typography.textColumns',
'typography.textDecoration',
'typography.textTransform',
];
@@ -178,7 +179,7 @@ export function useGlobalStyle(
switch ( source ) {
case 'all':
rawResult =
- // The stlyes.css path is allowed to be empty, so don't revert to base if undefined.
+ // The styles.css path is allowed to be empty, so don't revert to base if undefined.
finalPath === 'styles.css'
? get( userConfig, finalPath )
: get( mergedConfig, finalPath );
@@ -266,6 +267,16 @@ export function useSettingsForBlockElement(
}
} );
+ // The column-count style is named text column to reduce confusion with
+ // the columns block and manage expectations from the support.
+ // See: https://github.com/WordPress/gutenberg/pull/33587
+ if ( ! supportedStyles.includes( 'columnCount' ) ) {
+ updatedSettings.typography = {
+ ...updatedSettings.typography,
+ textColumns: false,
+ };
+ }
+
[ 'contentSize', 'wideSize' ].forEach( ( key ) => {
if ( ! supportedStyles.includes( key ) ) {
updatedSettings.layout = {
diff --git a/packages/block-editor/src/components/global-styles/typography-panel.js b/packages/block-editor/src/components/global-styles/typography-panel.js
index 9a928e30227f8f..1c3c253c7b69db 100644
--- a/packages/block-editor/src/components/global-styles/typography-panel.js
+++ b/packages/block-editor/src/components/global-styles/typography-panel.js
@@ -3,6 +3,7 @@
*/
import {
FontSizePicker,
+ __experimentalNumberControl as NumberControl,
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
} from '@wordpress/components';
@@ -20,6 +21,9 @@ import TextTransformControl from '../text-transform-control';
import TextDecorationControl from '../text-decoration-control';
import { getValueFromVariable } from './utils';
+const MIN_TEXT_COLUMNS = 1;
+const MAX_TEXT_COLUMNS = 6;
+
export function useHasTypographyPanel( settings ) {
const hasFontFamily = useHasFontFamilyControl( settings );
const hasLineHeight = useHasLineHeightControl( settings );
@@ -27,6 +31,7 @@ export function useHasTypographyPanel( settings ) {
const hasLetterSpacing = useHasLetterSpacingControl( settings );
const hasTextTransform = useHasTextTransformControl( settings );
const hasTextDecoration = useHasTextDecorationControl( settings );
+ const hasTextColumns = useHasTextColumnsControl( settings );
const hasFontSize = useHasFontSizeControl( settings );
return (
@@ -36,7 +41,8 @@ export function useHasTypographyPanel( settings ) {
hasLetterSpacing ||
hasTextTransform ||
hasFontSize ||
- hasTextDecoration
+ hasTextDecoration ||
+ hasTextColumns
);
}
@@ -93,6 +99,10 @@ function useHasTextDecorationControl( settings ) {
return settings?.typography?.textDecoration;
}
+function useHasTextColumnsControl( settings ) {
+ return settings?.typography?.textColumns;
+}
+
function TypographyToolsPanel( {
resetAllFilter,
onChange,
@@ -124,6 +134,7 @@ const DEFAULT_CONTROLS = {
letterSpacing: true,
textTransform: true,
textDecoration: true,
+ textColumns: true,
};
export default function TypographyPanel( {
@@ -246,6 +257,21 @@ export default function TypographyPanel( {
const hasLetterSpacing = () => !! value?.typography?.letterSpacing;
const resetLetterSpacing = () => setLetterSpacing( undefined );
+ // Text Columns
+ const hasTextColumnsControl = useHasTextColumnsControl( settings );
+ const textColumns = decodeValue( inheritedValue?.typography?.textColumns );
+ const setTextColumns = ( newValue ) => {
+ onChange( {
+ ...value,
+ typography: {
+ ...value?.typography,
+ textColumns: newValue,
+ },
+ } );
+ };
+ const hasTextColumns = () => !! value?.typography?.textColumns;
+ const resetTextColumns = () => setTextColumns( undefined );
+
// Text Transform
const hasTextTransformControl = useHasTextTransformControl( settings );
const textTransform = decodeValue(
@@ -388,6 +414,27 @@ export default function TypographyPanel( {
/>
) }
+ { hasTextColumnsControl && (
+
+
+
+ ) }
{ hasTextDecorationControl && (
{
expect(
getInlineStyles( {
color: { text: 'red', background: 'black' },
- typography: { lineHeight: 1.5, fontSize: 10 },
+ typography: { lineHeight: 1.5, fontSize: 10, textColumns: 2 },
border: {
radius: '10px',
width: '1em',
@@ -44,6 +44,7 @@ describe( 'getInlineStyles', () => {
borderStyle: 'dotted',
borderWidth: '1em',
color: 'red',
+ columnCount: 2,
lineHeight: 1.5,
fontSize: 10,
marginBottom: '15px',
diff --git a/packages/block-editor/src/hooks/test/use-typography-props.js b/packages/block-editor/src/hooks/test/use-typography-props.js
index 12336eb2c44afd..9b43a074cfcbaf 100644
--- a/packages/block-editor/src/hooks/test/use-typography-props.js
+++ b/packages/block-editor/src/hooks/test/use-typography-props.js
@@ -12,6 +12,7 @@ describe( 'getTypographyClassesAndStyles', () => {
typography: {
letterSpacing: '22px',
fontSize: '2rem',
+ textColumns: 3,
textTransform: 'uppercase',
},
},
@@ -19,6 +20,7 @@ describe( 'getTypographyClassesAndStyles', () => {
expect( getTypographyClassesAndStyles( attributes ) ).toEqual( {
className: 'has-tofu-font-family has-large-font-size',
style: {
+ columnCount: 3,
letterSpacing: '22px',
fontSize: '2rem',
textTransform: 'uppercase',
diff --git a/packages/block-editor/src/hooks/typography.js b/packages/block-editor/src/hooks/typography.js
index c5d3c74852777f..00e1c348f57c80 100644
--- a/packages/block-editor/src/hooks/typography.js
+++ b/packages/block-editor/src/hooks/typography.js
@@ -27,6 +27,7 @@ function omit( object, keys ) {
const LETTER_SPACING_SUPPORT_KEY = 'typography.__experimentalLetterSpacing';
const TEXT_TRANSFORM_SUPPORT_KEY = 'typography.__experimentalTextTransform';
const TEXT_DECORATION_SUPPORT_KEY = 'typography.__experimentalTextDecoration';
+const TEXT_COLUMNS_SUPPORT_KEY = 'typography.textColumns';
const FONT_STYLE_SUPPORT_KEY = 'typography.__experimentalFontStyle';
const FONT_WEIGHT_SUPPORT_KEY = 'typography.__experimentalFontWeight';
export const TYPOGRAPHY_SUPPORT_KEY = 'typography';
@@ -36,6 +37,7 @@ export const TYPOGRAPHY_SUPPORT_KEYS = [
FONT_STYLE_SUPPORT_KEY,
FONT_WEIGHT_SUPPORT_KEY,
FONT_FAMILY_SUPPORT_KEY,
+ TEXT_COLUMNS_SUPPORT_KEY,
TEXT_DECORATION_SUPPORT_KEY,
TEXT_TRANSFORM_SUPPORT_KEY,
LETTER_SPACING_SUPPORT_KEY,
diff --git a/packages/block-editor/src/hooks/utils.js b/packages/block-editor/src/hooks/utils.js
index 3684598997a6a8..f324bd99bc6eac 100644
--- a/packages/block-editor/src/hooks/utils.js
+++ b/packages/block-editor/src/hooks/utils.js
@@ -202,6 +202,7 @@ export function useBlockSettings( name, parentLayout ) {
const fontStyle = useSetting( 'typography.fontStyle' );
const fontWeight = useSetting( 'typography.fontWeight' );
const lineHeight = useSetting( 'typography.lineHeight' );
+ const textColumns = useSetting( 'typography.textColumns' );
const textDecoration = useSetting( 'typography.textDecoration' );
const textTransform = useSetting( 'typography.textTransform' );
const letterSpacing = useSetting( 'typography.letterSpacing' );
@@ -244,6 +245,7 @@ export function useBlockSettings( name, parentLayout ) {
fontStyle,
fontWeight,
lineHeight,
+ textColumns,
textDecoration,
textTransform,
letterSpacing,
@@ -276,6 +278,7 @@ export function useBlockSettings( name, parentLayout ) {
fontStyle,
fontWeight,
lineHeight,
+ textColumns,
textDecoration,
textTransform,
letterSpacing,
diff --git a/packages/blocks/src/api/constants.js b/packages/blocks/src/api/constants.js
index 28801b3cf4882e..1ab0b26448c1a5 100644
--- a/packages/blocks/src/api/constants.js
+++ b/packages/blocks/src/api/constants.js
@@ -123,6 +123,11 @@ export const __EXPERIMENTAL_STYLE_PROPERTY = {
requiresOptOut: true,
useEngine: true,
},
+ columnCount: {
+ value: [ 'typography', 'textColumns' ],
+ support: [ 'typography', 'textColumns' ],
+ useEngine: true,
+ },
filter: {
value: [ 'filter', 'duotone' ],
support: [ 'color', '__experimentalDuotone' ],
diff --git a/packages/blocks/src/store/private-selectors.js b/packages/blocks/src/store/private-selectors.js
index 2f4fb1dbea3866..9e38194cd11cb0 100644
--- a/packages/blocks/src/store/private-selectors.js
+++ b/packages/blocks/src/store/private-selectors.js
@@ -72,6 +72,11 @@ function filterElementBlockSupports( blockSupports, name, element ) {
return false;
}
+ // Text columns is only available for blocks.
+ if ( support === 'textColumns' && ! name ) {
+ return false;
+ }
+
return true;
} );
}
diff --git a/phpunit/class-wp-theme-json-test.php b/phpunit/class-wp-theme-json-test.php
index abb7c26cba866a..742c2d948b4515 100644
--- a/phpunit/class-wp-theme-json-test.php
+++ b/phpunit/class-wp-theme-json-test.php
@@ -388,7 +388,7 @@ public function test_get_stylesheet() {
),
),
'blocks' => array(
- 'core/group' => array(
+ 'core/group' => array(
'border' => array(
'radius' => '10px',
),
@@ -406,7 +406,7 @@ public function test_get_stylesheet() {
'padding' => '24px',
),
),
- 'core/heading' => array(
+ 'core/heading' => array(
'color' => array(
'text' => '#123456',
),
@@ -422,7 +422,7 @@ public function test_get_stylesheet() {
),
),
),
- 'core/post-date' => array(
+ 'core/post-date' => array(
'color' => array(
'text' => '#123456',
),
@@ -435,7 +435,12 @@ public function test_get_stylesheet() {
),
),
),
- 'core/image' => array(
+ 'core/post-excerpt' => array(
+ 'typography' => array(
+ 'textColumns' => 2,
+ ),
+ ),
+ 'core/image' => array(
'border' => array(
'radius' => array(
'topLeft' => '10px',
@@ -455,7 +460,7 @@ public function test_get_stylesheet() {
);
$variables = 'body{--wp--preset--color--grey: grey;--wp--preset--font-family--small: 14px;--wp--preset--font-family--big: 41px;}.wp-block-group{--wp--custom--base-font: 16;--wp--custom--line-height--small: 1.2;--wp--custom--line-height--medium: 1.4;--wp--custom--line-height--large: 1.8;}';
- $styles = 'body { margin: 0;}.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; }body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}';
+ $styles = 'body { margin: 0;}.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; }body{color: var(--wp--preset--color--grey);}a:where(:not(.wp-element-button)){background-color: #333;color: #111;}.wp-block-group{border-radius: 10px;min-height: 50vh;padding: 24px;}.wp-block-group a:where(:not(.wp-element-button)){color: #111;}.wp-block-heading{color: #123456;}.wp-block-heading a:where(:not(.wp-element-button)){background-color: #333;color: #111;font-size: 60px;}.wp-block-post-date{color: #123456;}.wp-block-post-date a:where(:not(.wp-element-button)){background-color: #777;color: #555;}.wp-block-post-excerpt{column-count: 2;}.wp-block-image{margin-bottom: 30px;}.wp-block-image img, .wp-block-image .wp-block-image__crop-area{border-top-left-radius: 10px;border-bottom-right-radius: 1em;}';
$presets = '.has-grey-color{color: var(--wp--preset--color--grey) !important;}.has-grey-background-color{background-color: var(--wp--preset--color--grey) !important;}.has-grey-border-color{border-color: var(--wp--preset--color--grey) !important;}.has-small-font-family{font-family: var(--wp--preset--font-family--small) !important;}.has-big-font-family{font-family: var(--wp--preset--font-family--big) !important;}';
$all = $variables . $styles . $presets;
diff --git a/schemas/json/theme.json b/schemas/json/theme.json
index d2fb13b6f13b4c..39c4b3ac902000 100644
--- a/schemas/json/theme.json
+++ b/schemas/json/theme.json
@@ -424,6 +424,11 @@
"type": "boolean",
"default": false
},
+ "textColumns": {
+ "description": "Allow users to set the number of text columns.",
+ "type": "boolean",
+ "default": false
+ },
"textDecoration": {
"description": "Allow users to set custom text decorations.",
"type": "boolean",
@@ -1443,6 +1448,10 @@
}
]
},
+ "textColumns": {
+ "description": "Sets the `column-count` CSS property.",
+ "type": "string"
+ },
"textDecoration": {
"description": "Sets the `text-decoration` CSS property.",
"oneOf": [