Skip to content
Merged
3 changes: 3 additions & 0 deletions backport-changelog/7.0/10573.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
https://github.com/WordPress/wordpress-develop/pull/10573

* https://github.com/WordPress/gutenberg/pull/74889
1 change: 1 addition & 0 deletions docs/how-to-guides/themes/global-settings-and-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ The settings section has the following structure:
"textAlign": true,
"textColumns": false,
"textDecoration": true,
"textIndent": true,
"textTransform": true
},
"blocks": {
Expand Down
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -598,7 +598,7 @@ Start with the basic building block of all narrative. ([Source](https://github.c

- **Name:** core/paragraph
- **Category:** text
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign, textColumns), ~~className~~
- **Supports:** __unstablePasteTextInline, align (full, wide), anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), splitting, typography (fitText, fontSize, lineHeight, textAlign, textColumns, textIndent), ~~className~~
- **Attributes:** content, direction, dropCap, placeholder

## Pattern Placeholder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ Settings related to typography.
| fluid | Enables fluid typography and allows users to set global fluid typography parameters. | `boolean`, `{ minFontSize, maxViewportWidth, minViewportWidth }` | `false` |
| letterSpacing | Allow users to set custom letter spacing. | `boolean` | `true` |
| lineHeight | Allow users to set custom line height. | `boolean` | `false` |
| textIndent | Allow users to set custom line indent. | `boolean`, `string` | `"subsequent"` |
| textAlign | Allow users to set the text align. | `boolean` | `true` |
| textColumns | Allow users to set the number of text columns. | `boolean` | `false` |
| textDecoration | Allow users to set custom text decorations. | `boolean` | `true` |
Expand Down Expand Up @@ -329,6 +330,7 @@ Typography styles.
| fontWeight | Sets the `font-weight` CSS property. | `string`, `{ ref }` |
| letterSpacing | Sets the `letter-spacing` CSS property. | `string`, `{ ref }` |
| lineHeight | Sets the `line-height` CSS property. | `string`, `{ ref }` |
| textIndent | Sets the `text-indent` CSS property. | `string`, `{ ref }` |
| textAlign | Sets the `text-align` CSS property. | `string`, `{ ref }` |
| textColumns | Sets the `column-count` CSS property. | `string`, `{ ref }` |
| textDecoration | Sets the `text-decoration` CSS property. | `string`, `{ ref }` |
Expand Down
8 changes: 8 additions & 0 deletions lib/block-supports/typography.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ function gutenberg_register_typography_support( $block_type ) {
$has_text_columns_support = $typography_supports['textColumns'] ?? false;
$has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false;
$has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false;
$has_text_indent_support = $typography_supports['textIndent'] ?? false;
$has_writing_mode_support = $typography_supports['__experimentalWritingMode'] ?? false;

$has_typography_support = $has_font_family_support
Expand All @@ -42,6 +43,7 @@ function gutenberg_register_typography_support( $block_type ) {
|| $has_text_columns_support
|| $has_text_decoration_support
|| $has_text_transform_support
|| $has_text_indent_support
|| $has_writing_mode_support;

if ( ! $block_type->attributes ) {
Expand Down Expand Up @@ -101,6 +103,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$has_text_columns_support = $typography_supports['textColumns'] ?? false;
$has_text_decoration_support = $typography_supports['__experimentalTextDecoration'] ?? false;
$has_text_transform_support = $typography_supports['__experimentalTextTransform'] ?? false;
$has_text_indent_support = $typography_supports['textIndent'] ?? false;
$has_writing_mode_support = $typography_supports['__experimentalWritingMode'] ?? false;

// Whether to skip individual block support features.
Expand All @@ -114,6 +117,7 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$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' );
$should_skip_text_indent = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'textIndent' );
$should_skip_writing_mode = wp_should_skip_block_supports_serialization( $block_type, 'typography', 'writingMode' );

$typography_block_styles = array();
Expand Down Expand Up @@ -174,6 +178,10 @@ function gutenberg_apply_typography_support( $block_type, $block_attributes ) {
$typography_block_styles['writingMode'] = $block_attributes['style']['typography']['writingMode'] ?? null;
}

if ( $has_text_indent_support && ! $should_skip_text_indent && isset( $block_attributes['style']['typography']['textIndent'] ) ) {
$typography_block_styles['textIndent'] = $block_attributes['style']['typography']['textIndent'] ?? null;
}

$attributes = array();
$classnames = array();
$styles = gutenberg_style_engine_get_styles(
Expand Down
61 changes: 58 additions & 3 deletions lib/class-wp-theme-json-gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,8 @@ class WP_Theme_JSON_Gutenberg {
* @since 6.2.0 Added `outline-*`, and `min-height` properties.
* @since 6.3.0 Added `writing-mode` property.
* @since 6.6.0 Added `background-[image|position|repeat|size]` properties.
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
* @since 7.0.0 Added `dimensions.width`, `dimensions.height`. and
* `typography.textIndent` properties.
*
* @var array
*/
Expand Down Expand Up @@ -305,6 +306,7 @@ class WP_Theme_JSON_Gutenberg {
'--wp--style--root--padding-left' => array( 'spacing', 'padding', 'left' ),
'text-decoration' => array( 'typography', 'textDecoration' ),
'text-transform' => array( 'typography', 'textTransform' ),
'text-indent' => array( 'typography', 'textIndent' ),
'filter' => array( 'filter', 'duotone' ),
'box-shadow' => array( 'shadow' ),
'height' => array( 'dimensions', 'height' ),
Expand Down Expand Up @@ -385,7 +387,8 @@ class WP_Theme_JSON_Gutenberg {
* @since 6.4.0 Added `layout.allowEditing`.
* @since 6.4.0 Added `lightbox`.
* @since 7.0.0 Added type markers to the schema for boolean values.
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
* @since 7.0.0 Added `dimensions.width`, `dimensions.height`. and
* `typography.textIndent` properties.
* @var array
*/
const VALID_SETTINGS = array(
Expand Down Expand Up @@ -471,6 +474,7 @@ class WP_Theme_JSON_Gutenberg {
'textAlign' => null,
'textColumns' => null,
'textDecoration' => null,
'textIndent' => null,
'textTransform' => null,
'writingMode' => null,
),
Expand Down Expand Up @@ -514,7 +518,8 @@ class WP_Theme_JSON_Gutenberg {
* @since 6.2.0 Added `outline`, and `minHeight` properties.
* @since 6.6.0 Added `background` sub properties to top-level only.
* @since 6.6.0 Added `dimensions.aspectRatio`.
* @since 7.0.0 Added `dimensions.width` and `dimensions.height`.
* @since 7.0.0 Added `dimensions.width`, `dimensions.height`. and
* `typography.textIndent` properties.
* @var array
*/
const VALID_STYLES = array(
Expand Down Expand Up @@ -571,6 +576,7 @@ class WP_Theme_JSON_Gutenberg {
'textAlign' => null,
'textColumns' => null,
'textDecoration' => null,
'textIndent' => null,
'textTransform' => null,
'writingMode' => null,
),
Expand Down Expand Up @@ -2752,6 +2758,48 @@ private static function update_separator_declarations( $declarations ) {
return $declarations;
}

/**
* Updates the text indent selector for paragraph blocks based on the textIndent setting.
*
* The textIndent setting can be 'subsequent' (default), 'all', or false.
* When set to 'all', the selector should be '.wp-block-paragraph' instead of
* '.wp-block-paragraph + .wp-block-paragraph' to apply indent to all paragraphs.
*
* @since 7.0.0
*
* @param array $feature_declarations The feature declarations keyed by selector.
* @param array $settings The theme.json settings.
* @param string $block_name The block name being processed.
* @return array The updated feature declarations.
*/
private static function update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name ) {
if ( 'core/paragraph' !== $block_name ) {
return $feature_declarations;
}

// Check block-level settings first, then fall back to global settings.
$block_settings = $settings['blocks']['core/paragraph'] ?? null;
$text_indent_setting = $block_settings['typography']['textIndent']
?? $settings['typography']['textIndent']
?? 'subsequent';

if ( 'all' !== $text_indent_setting ) {
return $feature_declarations;
}

// Look for the text indent selector and replace it.
$old_selector = '.wp-block-paragraph + .wp-block-paragraph';
$new_selector = '.wp-block-paragraph';

if ( isset( $feature_declarations[ $old_selector ] ) ) {
$declarations = $feature_declarations[ $old_selector ];
unset( $feature_declarations[ $old_selector ] );
$feature_declarations[ $new_selector ] = $declarations;
}

return $feature_declarations;
}

/**
* An internal method to get the block nodes from a theme.json file.
*
Expand Down Expand Up @@ -2914,6 +2962,10 @@ public function get_styles_for_block( $block_metadata ) {

$feature_declarations = static::get_feature_declarations_for_node( $block_metadata, $node );

// Update text indent selector for paragraph blocks based on the textIndent setting.
$block_name = $block_metadata['name'] ?? null;
$feature_declarations = static::update_paragraph_text_indent_selector( $feature_declarations, $settings, $block_name );

// If there are style variations, generate the declarations for them, including any feature selectors the block may have.
$style_variation_declarations = array();
$style_variation_custom_css = array();
Expand All @@ -2926,6 +2978,9 @@ public function get_styles_for_block( $block_metadata ) {
// Generate any feature/subfeature style declarations for the current style variation.
$variation_declarations = static::get_feature_declarations_for_node( $block_metadata, $style_variation_node );

// Update text indent selector for paragraph blocks based on the textIndent setting.
$variation_declarations = static::update_paragraph_text_indent_selector( $variation_declarations, $settings, $block_name );

// Combine selectors with style variation's selector and add to overall style variation declarations.
foreach ( $variation_declarations as $current_selector => $new_declarations ) {
/*
Expand Down
1 change: 1 addition & 0 deletions lib/theme.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@
"textAlign": true,
"textColumns": false,
"textDecoration": true,
"textIndent": "subsequent",
"textTransform": true,
"writingMode": false
},
Expand Down
10 changes: 10 additions & 0 deletions packages/block-editor/src/components/global-styles/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ export function useSettingsForBlockElement(
'textAlign',
'textTransform',
'textDecoration',
'textIndent',
'writingMode',
].forEach( ( key ) => {
if ( ! supportedStyles.includes( key ) ) {
Expand All @@ -110,6 +111,15 @@ export function useSettingsForBlockElement(
}
} );

// Text indent needs explicit handling since it may not be in parent settings.
if ( supportedStyles.includes( 'textIndent' ) ) {
updatedSettings.typography = {
...updatedSettings.typography,
textIndent:
updatedSettings.typography?.textIndent ?? 'subsequent',
};
}

// 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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
__experimentalToolsPanel as ToolsPanel,
__experimentalToolsPanelItem as ToolsPanelItem,
Notice,
ToggleControl,
} from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import { useCallback, useMemo } from '@wordpress/element';
Expand All @@ -22,6 +23,7 @@ import LetterSpacingControl from '../letter-spacing-control';
import TextAlignmentControl from '../text-alignment-control';
import TextTransformControl from '../text-transform-control';
import TextDecorationControl from '../text-decoration-control';
import TextIndentControl from '../text-indent-control';
import WritingModeControl from '../writing-mode-control';
import { useToolsPanelDropdownMenuProps } from './utils';
import { setImmutably } from '../../utils/object';
Expand All @@ -42,6 +44,7 @@ export function useHasTypographyPanel( settings ) {
const hasTextAlign = useHasTextAlignmentControl( settings );
const hasTextTransform = useHasTextTransformControl( settings );
const hasTextDecoration = useHasTextDecorationControl( settings );
const hasTextIndent = useHasTextIndentControl( settings );
const hasWritingMode = useHasWritingModeControl( settings );
const hasTextColumns = useHasTextColumnsControl( settings );
const hasFontSize = useHasFontSizeControl( settings );
Expand All @@ -55,6 +58,7 @@ export function useHasTypographyPanel( settings ) {
hasTextTransform ||
hasFontSize ||
hasTextDecoration ||
hasTextIndent ||
hasWritingMode ||
hasTextColumns
);
Expand Down Expand Up @@ -118,6 +122,10 @@ function useHasTextColumnsControl( settings ) {
return settings?.typography?.textColumns;
}

function useHasTextIndentControl( settings ) {
return settings?.typography?.textIndent;
}

/**
* Concatenate all the font sizes into a single list for the font size picker.
*
Expand Down Expand Up @@ -169,6 +177,7 @@ const DEFAULT_CONTROLS = {
textAlign: true,
textTransform: true,
textDecoration: true,
textIndent: true,
writingMode: true,
textColumns: true,
};
Expand All @@ -181,6 +190,7 @@ export default function TypographyPanel( {
settings,
panelId,
defaultControls = DEFAULT_CONTROLS,
isGlobalStyles = false,
} ) {
const decodeValue = ( rawValue ) =>
getValueFromVariable( { settings }, '', rawValue );
Expand Down Expand Up @@ -358,6 +368,48 @@ export default function TypographyPanel( {
const hasLetterSpacing = () => !! value?.typography?.letterSpacing;
const resetLetterSpacing = () => setLetterSpacing( undefined );

// Text Indent
const hasTextIndentControl = useHasTextIndentControl( settings );
const textIndent = decodeValue( inheritedValue?.typography?.textIndent );

// Get the setting value - can be 'subsequent' (default), 'all', or false.
// The setting determines which CSS selector is used for the text-indent style.
const textIndentSetting = settings?.typography?.textIndent ?? 'subsequent';
const isTextIndentAll = textIndentSetting === 'all';

const setTextIndentValue = ( newValue ) => {
onChange(
setImmutably(
value,
[ 'typography', 'textIndent' ],
newValue || undefined
)
);
};

const onToggleTextIndentAll = ( newValue ) => {
// Toggle between 'all' and 'subsequent' for the setting.
// Include the settings change so it can be handled atomically by the parent.
onChange( {
...value,
settings: {
typography: {
textIndent: newValue ? 'all' : 'subsequent',
},
},
} );
};

const hasTextIndent = () => !! value?.typography?.textIndent;
const resetTextIndent = () => {
onChange(
setImmutably( value, [ 'typography', 'textIndent' ], undefined )
);
};
const textIndentHelp = isTextIndentAll
? __( 'Indents the first line of all paragraphs.' )
: __( 'Indents the first line of each paragraph after the first one.' );

// Text Columns
const hasTextColumnsControl = useHasTextColumnsControl( settings );
const textColumns = decodeValue( inheritedValue?.typography?.textColumns );
Expand Down Expand Up @@ -490,7 +542,6 @@ export default function TypographyPanel( {
) }
{ hasAppearanceControl && (
<ToolsPanelItem
className="single-column"
label={ appearanceControlLabel }
hasValue={ hasFontAppearance }
onDeselect={ resetFontAppearance }
Expand Down Expand Up @@ -544,6 +595,33 @@ export default function TypographyPanel( {
/>
</ToolsPanelItem>
) }
{ hasTextIndentControl && (
<ToolsPanelItem
label={ __( 'Line indent' ) }
hasValue={ hasTextIndent }
onDeselect={ resetTextIndent }
isShownByDefault={ defaultControls.textIndent }
panelId={ panelId }
>
<TextIndentControl
value={ textIndent }
onChange={ setTextIndentValue }
size="__unstable-large"
__unstableInputWidth="auto"
withSlider
hasBottomMargin={ isGlobalStyles }
/>
{ isGlobalStyles && (
<ToggleControl
__nextHasNoMarginBottom
label={ __( 'Indent all paragraphs' ) }
checked={ isTextIndentAll }
onChange={ onToggleTextIndentAll }
help={ textIndentHelp }
/>
) }
</ToolsPanelItem>
) }
{ hasTextColumnsControl && (
<ToolsPanelItem
className="single-column"
Expand Down
Loading
Loading