diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index abd247003f9b6f..0afd4dc411ccb8 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -698,7 +698,7 @@ Help visitors find your content. ([Source](https://github.com/WordPress/gutenber
- **Name:** core/search
- **Category:** widgets
-- **Supports:** align (center, left, right), color (background, gradients, text), ~~html~~
+- **Supports:** align (center, left, right), color (background, gradients, text), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** buttonPosition, buttonText, buttonUseIcon, label, placeholder, query, showLabel, width, widthUnit
## Separator
diff --git a/packages/block-editor/README.md b/packages/block-editor/README.md
index c2b8ebc4efd714..ccdb5b9e375951 100644
--- a/packages/block-editor/README.md
+++ b/packages/block-editor/README.md
@@ -474,6 +474,19 @@ _Returns_
- `string`: returns the cssUnit value in a simple px format.
+### getTypographyClassesAndStyles
+
+Provides the CSS class names and inline styles for a block's typography support
+attributes.
+
+_Parameters_
+
+- _attributes_ `Object`: Block attributes.
+
+_Returns_
+
+- `Object`: Typography block support derived CSS classes & styles.
+
### InnerBlocks
_Related_
diff --git a/packages/block-editor/src/hooks/index.js b/packages/block-editor/src/hooks/index.js
index 5a07d864beb620..3ed81af7cda60c 100644
--- a/packages/block-editor/src/hooks/index.js
+++ b/packages/block-editor/src/hooks/index.js
@@ -21,5 +21,6 @@ export { useCustomSides } from './dimensions';
export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
export { getSpacingClassesAndStyles } from './use-spacing-props';
+export { getTypographyClassesAndStyles } from './use-typography-props';
export { getGapCSSValue } from './gap';
export { useCachedTruthy } from './use-cached-truthy';
diff --git a/packages/block-editor/src/hooks/test/use-typography-props.js b/packages/block-editor/src/hooks/test/use-typography-props.js
new file mode 100644
index 00000000000000..93e4de29bc7348
--- /dev/null
+++ b/packages/block-editor/src/hooks/test/use-typography-props.js
@@ -0,0 +1,28 @@
+/**
+ * Internal dependencies
+ */
+import { getTypographyClassesAndStyles } from '../use-typography-props';
+
+describe( 'getTypographyClassesAndStyles', () => {
+ it( 'should return styles and classes', () => {
+ const attributes = {
+ fontFamily: 'tofu',
+ fontSize: 'large',
+ style: {
+ typography: {
+ letterSpacing: '22px',
+ fontSize: '2rem',
+ textTransform: 'uppercase',
+ },
+ },
+ };
+ expect( getTypographyClassesAndStyles( attributes ) ).toEqual( {
+ className: 'has-tofu-font-family has-large-font-size',
+ style: {
+ letterSpacing: '22px',
+ fontSize: '2rem',
+ textTransform: 'uppercase',
+ },
+ } );
+ } );
+} );
diff --git a/packages/block-editor/src/hooks/use-typography-props.js b/packages/block-editor/src/hooks/use-typography-props.js
new file mode 100644
index 00000000000000..d08105d8d90c1e
--- /dev/null
+++ b/packages/block-editor/src/hooks/use-typography-props.js
@@ -0,0 +1,41 @@
+/**
+ * External dependencies
+ */
+import { kebabCase } from 'lodash';
+import classnames from 'classnames';
+
+/**
+ * Internal dependencies
+ */
+import { getInlineStyles } from './style';
+import { getFontSizeClass } from '../components/font-sizes';
+
+// This utility is intended to assist where the serialization of the typography
+// block support is being skipped for a block but the typography related CSS
+// styles still need to be generated so they can be applied to inner elements.
+
+/**
+ * Provides the CSS class names and inline styles for a block's typography support
+ * attributes.
+ *
+ * @param {Object} attributes Block attributes.
+ *
+ * @return {Object} Typography block support derived CSS classes & styles.
+ */
+export function getTypographyClassesAndStyles( attributes ) {
+ const typographyStyles = attributes?.style?.typography || {};
+ const style = getInlineStyles( { typography: typographyStyles } );
+ const fontFamilyClassName = !! attributes?.fontFamily
+ ? `has-${ kebabCase( attributes.fontFamily ) }-font-family`
+ : '';
+
+ const className = classnames(
+ fontFamilyClassName,
+ getFontSizeClass( attributes?.fontSize )
+ );
+
+ return {
+ className,
+ style,
+ };
+}
diff --git a/packages/block-editor/src/index.js b/packages/block-editor/src/index.js
index c3d55ce8962c7a..ec0f20a8f9c892 100644
--- a/packages/block-editor/src/index.js
+++ b/packages/block-editor/src/index.js
@@ -6,6 +6,7 @@ export {
getBorderClassesAndStyles as __experimentalGetBorderClassesAndStyles,
useBorderProps as __experimentalUseBorderProps,
getColorClassesAndStyles as __experimentalGetColorClassesAndStyles,
+ getTypographyClassesAndStyles,
useColorProps as __experimentalUseColorProps,
useCustomSides as __experimentalUseCustomSides,
getSpacingClassesAndStyles as __experimentalGetSpacingClassesAndStyles,
diff --git a/packages/block-library/src/search/block.json b/packages/block-library/src/search/block.json
index cb9ae01a648bcc..fbd0fa874c4087 100644
--- a/packages/block-library/src/search/block.json
+++ b/packages/block-library/src/search/block.json
@@ -54,6 +54,21 @@
"text": true
}
},
+ "typography": {
+ "__experimentalSkipSerialization": true,
+ "__experimentalSelector": ".wp-block-search__label, .wp-block-search__input, .wp-block-search__button",
+ "fontSize": true,
+ "lineHeight": true,
+ "__experimentalFontFamily": true,
+ "__experimentalFontWeight": true,
+ "__experimentalFontStyle": true,
+ "__experimentalTextTransform": true,
+ "__experimentalTextDecoration": true,
+ "__experimentalLetterSpacing": true,
+ "__experimentalDefaultControls": {
+ "fontSize": true
+ }
+ },
"__experimentalBorder": {
"color": true,
"radius": true,
diff --git a/packages/block-library/src/search/edit.js b/packages/block-library/src/search/edit.js
index 0206986961cef6..807dda04e743e4 100644
--- a/packages/block-library/src/search/edit.js
+++ b/packages/block-library/src/search/edit.js
@@ -13,6 +13,7 @@ import {
RichText,
__experimentalUseBorderProps as useBorderProps,
__experimentalUseColorProps as useColorProps,
+ getTypographyClassesAndStyles as useTypographyProps,
store as blockEditorStore,
__experimentalGetElementClassName,
} from '@wordpress/block-editor';
@@ -112,6 +113,7 @@ export default function SearchEdit( {
}
const colorProps = useColorProps( attributes );
+ const typographyProps = useTypographyProps( attributes );
const unitControlInstanceId = useInstanceId( UnitControl );
const unitControlInputId = `wp-block-search__width-${ unitControlInstanceId }`;
const isButtonPositionInside = 'button-inside' === buttonPosition;
@@ -208,11 +210,16 @@ export default function SearchEdit( {
// If the input is inside the wrapper, the wrapper gets the border color styles/classes, not the input control.
const textFieldClasses = classnames(
'wp-block-search__input',
- isButtonPositionInside ? undefined : borderProps.className
+ isButtonPositionInside ? undefined : borderProps.className,
+ typographyProps.className
);
- const textFieldStyles = isButtonPositionInside
- ? { borderRadius }
- : borderProps.style;
+ const textFieldStyles = {
+ ...( isButtonPositionInside
+ ? { borderRadius }
+ : borderProps.style ),
+ ...typographyProps.style,
+ textDecoration: undefined,
+ };
return (
{ controls }
{ showLabel && (
setAttributes( { label: html } ) }
+ style={ typographyProps.style }
/>
) }
diff --git a/packages/block-library/src/search/index.php b/packages/block-library/src/search/index.php
index d056da16d958a5..8e2a158969acb4 100644
--- a/packages/block-library/src/search/index.php
+++ b/packages/block-library/src/search/index.php
@@ -37,6 +37,7 @@ function render_block_core_search( $attributes ) {
$query_params_markup = '';
$inline_styles = styles_for_block_core_search( $attributes );
$color_classes = get_color_classes_for_block_core_search( $attributes );
+ $typography_classes = get_typography_classes_for_block_core_search( $attributes );
$is_button_inside = ! empty( $attributes['buttonPosition'] ) &&
'button-inside' === $attributes['buttonPosition'];
// Border color classes need to be applied to the elements that have a border color.
@@ -50,19 +51,31 @@ function render_block_core_search( $attributes ) {
$label_inner_html
);
if ( $show_label && ! empty( $attributes['label'] ) ) {
+ $label_classes = array( 'wp-block-search__label' );
+ if ( ! empty( $typography_classes ) ) {
+ $label_classes[] = $typography_classes;
+ }
$label_markup = sprintf(
- '',
- $input_id,
+ '',
+ esc_attr( $input_id ),
+ esc_attr( implode( ' ', $label_classes ) ),
+ $inline_styles['label'],
$label_inner_html
);
}
if ( $show_input ) {
- $input_classes = ! $is_button_inside ? $border_color_classes : '';
- $input_markup = sprintf(
+ $input_classes = array( 'wp-block-search__input' );
+ if ( $is_button_inside ) {
+ $input_classes[] = $border_color_classes;
+ }
+ if ( ! empty( $typography_classes ) ) {
+ $input_classes[] = $typography_classes;
+ }
+ $input_markup = sprintf(
'',
$input_id,
- esc_attr( $input_classes ),
+ esc_attr( implode( ' ', $input_classes ) ),
get_search_query(),
esc_attr( $attributes['placeholder'] ),
$inline_styles['input']
@@ -80,11 +93,14 @@ function render_block_core_search( $attributes ) {
}
if ( $show_button ) {
- $button_classes = array();
+ $button_classes = array( 'wp-block-search__button' );
$button_internal_markup = '';
if ( ! empty( $color_classes ) ) {
$button_classes[] = $color_classes;
}
+ if ( ! empty( $typography_classes ) ) {
+ $button_classes[] = $typography_classes;
+ }
$aria_label = '';
if ( ! $is_button_inside && ! empty( $border_color_classes ) ) {
@@ -107,7 +123,7 @@ function render_block_core_search( $attributes ) {
// Include the button element class.
$button_classes[] = WP_Theme_JSON_Gutenberg::get_element_class_name( 'button' );
$button_markup = sprintf(
- '',
+ '',
esc_attr( implode( ' ', $button_classes ) ),
$inline_styles['button'],
$aria_label,
@@ -122,7 +138,9 @@ function render_block_core_search( $attributes ) {
$inline_styles['wrapper'],
$input_markup . $query_params_markup . $button_markup
);
- $wrapper_attributes = get_block_wrapper_attributes( array( 'class' => $classnames ) );
+ $wrapper_attributes = get_block_wrapper_attributes(
+ array( 'class' => $classnames )
+ );
return sprintf(
'',
@@ -270,8 +288,10 @@ function styles_for_block_core_search( $attributes ) {
$wrapper_styles = array();
$button_styles = array();
$input_styles = array();
+ $label_styles = array();
$is_button_inside = ! empty( $attributes['buttonPosition'] ) &&
'button-inside' === $attributes['buttonPosition'];
+ $show_label = ( isset( $attributes['showLabel'] ) ) && false !== $attributes['showLabel'];
// Add width styles.
$has_width = ! empty( $attributes['width'] ) && ! empty( $attributes['widthUnit'] );
@@ -360,13 +380,98 @@ function styles_for_block_core_search( $attributes ) {
$button_styles[] = sprintf( 'background: %s;', $attributes['style']['color']['gradient'] );
}
+ // Get typography styles to be shared across inner elements.
+ $typography_styles = get_typography_styles_for_block_core_search( $attributes );
+ if ( ! empty( $typography_styles ) ) {
+ $label_styles [] = $typography_styles;
+ $button_styles[] = $typography_styles;
+ $input_styles [] = $typography_styles;
+ }
+
+ // Typography text-decoration is only applied to the label and button.
+ if ( ! empty( $attributes['style']['typography']['textDecoration'] ) ) {
+ $text_decoration_value = sprintf( 'text-decoration: %s;', esc_attr( $attributes['style']['typography']['textDecoration'] ) );
+ $button_styles[] = $text_decoration_value;
+ // Input opts out of text decoration.
+ if ( $show_label ) {
+ $label_styles[] = $text_decoration_value;
+ }
+ }
+
return array(
'input' => ! empty( $input_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $input_styles ) ) ) : '',
'button' => ! empty( $button_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $button_styles ) ) ) : '',
'wrapper' => ! empty( $wrapper_styles ) ? sprintf( ' style="%s"', safecss_filter_attr( implode( ' ', $wrapper_styles ) ) ) : '',
+ 'label' => ! empty( $label_styles ) ? sprintf( ' style="%s"', esc_attr( safecss_filter_attr( implode( ' ', $label_styles ) ) ) ) : '',
);
}
+/**
+ * Returns typography classnames depending on whether there are named font sizes/families .
+ *
+ * @param array $attributes The block attributes.
+ *
+ * @return string The typography color classnames to be applied to the block elements.
+ */
+function get_typography_classes_for_block_core_search( $attributes ) {
+ $typography_classes = array();
+ $has_named_font_family = ! empty( $attributes['fontFamily'] );
+ $has_named_font_size = ! empty( $attributes['fontSize'] );
+
+ if ( $has_named_font_size ) {
+ $typography_classes[] = sprintf( 'has-%s-font-size', esc_attr( $attributes['fontSize'] ) );
+ }
+
+ if ( $has_named_font_family ) {
+ $typography_classes[] = sprintf( 'has-%s-font-family', esc_attr( $attributes['fontFamily'] ) );
+ }
+
+ return implode( ' ', $typography_classes );
+}
+
+/**
+ * Returns typography styles to be included in an HTML style tag.
+ * This excludes text-decoration, which is applied only to the label and button elements of the search block.
+ *
+ * @param array $attributes The block attributes.
+ *
+ * @return string A string of typography CSS declarations.
+ */
+function get_typography_styles_for_block_core_search( $attributes ) {
+ $typography_styles = array();
+
+ // Add typography styles.
+ if ( ! empty( $attributes['style']['typography']['fontSize'] ) ) {
+ $typography_styles[] = sprintf( 'font-size: %s;', esc_attr( $attributes['style']['typography']['fontSize'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['fontFamily'] ) ) {
+ $typography_styles[] = sprintf( 'font-family: %s;', esc_attr( $attributes['style']['typography']['fontFamily'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['letterSpacing'] ) ) {
+ $typography_styles[] = sprintf( 'letter-spacing: %s;', esc_attr( $attributes['style']['typography']['letterSpacing'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['fontWeight'] ) ) {
+ $typography_styles[] = sprintf( 'font-weight: %s;', esc_attr( $attributes['style']['typography']['fontWeight'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['fontStyle'] ) ) {
+ $typography_styles[] = sprintf( 'font-style: %s;', esc_attr( $attributes['style']['typography']['fontStyle'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['lineHeight'] ) ) {
+ $typography_styles[] = sprintf( 'line-height: %s;', esc_attr( $attributes['style']['typography']['lineHeight'] ) );
+ }
+
+ if ( ! empty( $attributes['style']['typography']['textTransform'] ) ) {
+ $typography_styles[] = sprintf( 'text-transform: %s;', esc_attr( $attributes['style']['typography']['textTransform'] ) );
+ }
+
+ return implode( '', $typography_styles );
+}
+
/**
* Returns border color classnames depending on whether there are named or custom border colors.
*
diff --git a/packages/block-library/src/search/style.scss b/packages/block-library/src/search/style.scss
index f6eb7ed287c5ef..9a713804603ba3 100644
--- a/packages/block-library/src/search/style.scss
+++ b/packages/block-library/src/search/style.scss
@@ -10,6 +10,7 @@
min-width: 1.5em;
min-height: 1.5em;
fill: currentColor;
+ vertical-align: text-bottom;
}
}
@@ -38,9 +39,9 @@
margin-right: 0;
min-width: 3em;
border: 1px solid #949494;
- font-size: inherit;
- font-family: inherit;
- line-height: inherit;
+ // !important used to forcibly prevent undesired application of
+ // text-decoration styles on the input field.
+ text-decoration: unset !important;
}
.wp-block-search.wp-block-search__button-only {