diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index 2917c8577b07d..7d8ff54432c79 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -555,7 +555,7 @@ Display a post's featured image. ([Source](https://github.com/WordPress/gutenber
- **Name:** core/post-featured-image
- **Category:** theme
- **Supports:** align (center, full, left, right, wide), anchor, color (~~background~~, ~~text~~), spacing (margin, padding), ~~html~~
-- **Attributes:** aspectRatio, customGradient, customOverlayColor, dimRatio, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, width
+- **Attributes:** aspectRatio, caption, customGradient, customOverlayColor, dimRatio, displayCaption, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, width
## Post Navigation Link
diff --git a/packages/block-library/src/post-featured-image/block.json b/packages/block-library/src/post-featured-image/block.json
index c6007785cd82a..f971bc7ded91d 100644
--- a/packages/block-library/src/post-featured-image/block.json
+++ b/packages/block-library/src/post-featured-image/block.json
@@ -51,6 +51,13 @@
},
"customGradient": {
"type": "string"
+ },
+ "displayCaption": {
+ "type": "boolean",
+ "default": false
+ },
+ "caption": {
+ "type": "string"
}
},
"usesContext": [ "postId", "postType", "queryId" ],
diff --git a/packages/block-library/src/post-featured-image/edit.js b/packages/block-library/src/post-featured-image/edit.js
index f378a14f5c9d1..d88f8756e2d41 100644
--- a/packages/block-library/src/post-featured-image/edit.js
+++ b/packages/block-library/src/post-featured-image/edit.js
@@ -15,6 +15,7 @@ import {
Placeholder,
Button,
TextControl,
+ ToolbarButton,
} from '@wordpress/components';
import {
InspectorControls,
@@ -23,11 +24,16 @@ import {
MediaReplaceFlow,
useBlockProps,
store as blockEditorStore,
+ __experimentalGetElementClassName,
__experimentalUseBorderProps as useBorderProps,
+ RichText,
} from '@wordpress/block-editor';
import { __, sprintf } from '@wordpress/i18n';
-import { upload } from '@wordpress/icons';
+import { createBlock, getDefaultBlockName } from '@wordpress/blocks';
+import { upload, caption as captionIcon } from '@wordpress/icons';
import { store as noticesStore } from '@wordpress/notices';
+import { useEffect, useState, useCallback } from '@wordpress/element';
+import { usePrevious } from '@wordpress/compose';
/**
* Internal dependencies
@@ -47,6 +53,8 @@ export default function PostFeaturedImageEdit( {
clientId,
attributes,
setAttributes,
+ isSelected,
+ insertBlocksAfter,
context: { postId, postType: postTypeSlug, queryId },
} ) {
const isDescendentOfQueryLoop = Number.isFinite( queryId );
@@ -59,6 +67,7 @@ export default function PostFeaturedImageEdit( {
sizeSlug,
rel,
linkTarget,
+ caption,
} = attributes;
const [ featuredImage, setFeaturedImage ] = useEntityProp(
'postType',
@@ -67,6 +76,32 @@ export default function PostFeaturedImageEdit( {
postId
);
+ const prevCaption = usePrevious( caption );
+ const [ showCaption, setShowCaption ] = useState( true );
+ // We need to show the caption when changes come from
+ // history navigation(undo/redo).
+ useEffect( () => {
+ if ( caption && ! prevCaption ) {
+ setShowCaption( true );
+ }
+ }, [ caption, prevCaption ] );
+
+ // Focus the caption when we click to add one.
+ const captionRef = useCallback(
+ ( node ) => {
+ if ( node && ! caption ) {
+ node.focus();
+ }
+ },
+ [ caption ]
+ );
+
+ useEffect( () => {
+ if ( ! isSelected && ! caption ) {
+ setShowCaption( false );
+ }
+ }, [ isSelected, caption ] );
+
const { media, postType } = useSelect(
( select ) => {
const { getMedia, getPostType } = select( coreStore );
@@ -83,6 +118,10 @@ export default function PostFeaturedImageEdit( {
);
const mediaUrl = getMediaSourceUrlBySizeSlug( media, sizeSlug );
+ const mediaLibraryCaption = !! media?.caption?.rendered
+ ? media?.caption?.rendered
+ : '';
+
const imageSizes = useSelect(
( select ) => select( blockEditorStore ).getSettings().imageSizes,
[]
@@ -130,8 +169,35 @@ export default function PostFeaturedImageEdit( {
createErrorNotice( message, { type: 'snackbar' } );
};
+ // Displays the caption when it is not editable.
+ const DisplayFigCaption = () => (
+
+ );
+
const controls = (
<>
+
+ {
+ setShowCaption( ! showCaption );
+ if ( showCaption && caption ) {
+ setAttributes( { caption: undefined } );
+ }
+ } }
+ icon={ captionIcon }
+ isPressed={ showCaption }
+ label={
+ showCaption
+ ? __( 'Remove caption' )
+ : __( 'Add caption' )
+ }
+ />
+
{ controls }
-
+
+
+ { showCaption && }
>
);
}
@@ -214,14 +281,15 @@ export default function PostFeaturedImageEdit( {
setAttributes={ setAttributes }
imageSizeOptions={ imageSizeOptions }
/>
-
+
+ { showCaption && }
+
>
);
}
@@ -293,6 +361,7 @@ export default function PostFeaturedImageEdit( {
* - Is not inside a query loop
* Then display the image and the image replacement option.
*/
+
return (
<>
{ controls }
@@ -319,6 +388,32 @@ export default function PostFeaturedImageEdit( {
setAttributes={ setAttributes }
clientId={ clientId }
/>
+ { showCaption &&
+ ! isDescendentOfQueryLoop &&
+ ( ! RichText.isEmpty( caption ) || isSelected ) && (
+
+ setAttributes( { caption: value } )
+ }
+ inlineToolbar
+ __unstableOnSplitAtEnd={ () =>
+ insertBlocksAfter(
+ createBlock( getDefaultBlockName() )
+ )
+ }
+ />
+ ) }
+ { showCaption && isDescendentOfQueryLoop && (
+
+ ) }
>
);
diff --git a/packages/block-library/src/post-featured-image/index.php b/packages/block-library/src/post-featured-image/index.php
index 6cb4110ee000e..0d4f1d8c33675 100644
--- a/packages/block-library/src/post-featured-image/index.php
+++ b/packages/block-library/src/post-featured-image/index.php
@@ -25,10 +25,12 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
the_post();
}
- $is_link = isset( $attributes['isLink'] ) && $attributes['isLink'];
- $size_slug = isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : 'post-thumbnail';
- $attr = get_block_core_post_featured_image_border_attributes( $attributes );
- $overlay_markup = get_block_core_post_featured_image_overlay_element_markup( $attributes );
+ $is_link = isset( $attributes['isLink'] ) && $attributes['isLink'];
+ $size_slug = isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : 'post-thumbnail';
+ $attr = get_block_core_post_featured_image_border_attributes( $attributes );
+ $overlay_markup = get_block_core_post_featured_image_overlay_element_markup( $attributes );
+ $caption = isset( $attributes['caption'] ) ? $attributes['caption'] : '';
+ $display_caption = isset( $attributes['displayCaption'] ) ? $attributes['displayCaption'] : '';
if ( $is_link ) {
if ( get_the_title( $post_ID ) ) {
@@ -80,6 +82,13 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
$featured_image = $featured_image . $overlay_markup;
}
+ $image_caption = '';
+ if ( $caption ) {
+ $image_caption = '' . $caption . '';
+ } elseif ( $display_caption ) {
+ $image_caption = '' . get_the_post_thumbnail_caption() . '';
+ }
+
$aspect_ratio = ! empty( $attributes['aspectRatio'] )
? esc_attr( safecss_filter_attr( 'aspect-ratio:' . $attributes['aspectRatio'] ) ) . ';'
: '';
@@ -94,7 +103,7 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
} else {
$wrapper_attributes = get_block_wrapper_attributes( array( 'style' => $aspect_ratio . $width . $height ) );
}
- return "";
+ return "";
}
/**
diff --git a/test/integration/fixtures/blocks/core__post-featured-image.json b/test/integration/fixtures/blocks/core__post-featured-image.json
index 158007533a3f2..9acaf77f4c260 100644
--- a/test/integration/fixtures/blocks/core__post-featured-image.json
+++ b/test/integration/fixtures/blocks/core__post-featured-image.json
@@ -7,7 +7,8 @@
"scale": "cover",
"rel": "",
"linkTarget": "_self",
- "dimRatio": 0
+ "dimRatio": 0,
+ "displayCaption": false
},
"innerBlocks": []
}