diff --git a/docs/reference-guides/core-blocks.md b/docs/reference-guides/core-blocks.md
index 27182a0f87eadf..735d75237618f9 100644
--- a/docs/reference-guides/core-blocks.md
+++ b/docs/reference-guides/core-blocks.md
@@ -546,7 +546,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), color (~~background~~, ~~text~~), spacing (margin, padding), ~~html~~
-- **Attributes:** height, isLink, linkTarget, rel, scale, sizeSlug, width
+- **Attributes:** customGradient, customOverlayColor, dimRatio, 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 dd5956a4f9290a..1072c7576d6454 100644
--- a/packages/block-library/src/post-featured-image/block.json
+++ b/packages/block-library/src/post-featured-image/block.json
@@ -32,6 +32,22 @@
"linkTarget": {
"type": "string",
"default": "_self"
+ },
+ "overlayColor": {
+ "type": "string"
+ },
+ "customOverlayColor": {
+ "type": "string"
+ },
+ "dimRatio": {
+ "type": "number",
+ "default": 0
+ },
+ "gradient": {
+ "type": "string"
+ },
+ "customGradient": {
+ "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 e95c8c2253dc4b..1cdc0d0fd32ebe 100644
--- a/packages/block-library/src/post-featured-image/edit.js
+++ b/packages/block-library/src/post-featured-image/edit.js
@@ -33,6 +33,7 @@ import { store as noticesStore } from '@wordpress/notices';
* Internal dependencies
*/
import DimensionControls from './dimension-controls';
+import Overlay from './overlay';
const ALLOWED_MEDIA_TYPES = [ 'image' ];
@@ -170,7 +171,14 @@ function PostFeaturedImageDisplay( {
return (
<>
{ controls }
-
{ placeholder() }
+
+ { placeholder() }
+
+
>
);
}
@@ -247,7 +255,14 @@ function PostFeaturedImageDisplay( {
) }
-
+
>
);
}
@@ -267,6 +282,11 @@ export default function PostFeaturedImageEdit( props ) {
withIllustration={ true }
style={ borderProps.style }
/>
+
);
}
diff --git a/packages/block-library/src/post-featured-image/editor.scss b/packages/block-library/src/post-featured-image/editor.scss
index be7b9a9dafa53b..c52d14f44f7a6c 100644
--- a/packages/block-library/src/post-featured-image/editor.scss
+++ b/packages/block-library/src/post-featured-image/editor.scss
@@ -1,85 +1,92 @@
// Provide special styling for the placeholder.
// @todo: this particular minimal style of placeholder could be componentized further.
-.wp-block-post-featured-image.wp-block-post-featured-image {
- // Style the placeholder.
- .wp-block-post-featured-image__placeholder,
- .components-placeholder {
- justify-content: center;
- align-items: center;
- padding: 0;
-
- // Hide the upload button, as it's also available in the media library.
- .components-form-file-upload {
- display: none;
- }
+.wp-block-post-featured-image {
+ .block-editor-media-placeholder {
+ z-index: 1; // Need to put it above the overlay so the upload button works.
+ backdrop-filter: none; // Removes background blur so the overlay's actual color is visible.
+ }
- // Style the upload button.
- .components-button.components-button {
- padding: 0;
- display: flex;
+ &.wp-block-post-featured-image {
+ // Style the placeholder.
+ .wp-block-post-featured-image__placeholder,
+ .components-placeholder {
justify-content: center;
align-items: center;
- width: $grid-unit-60;
- height: $grid-unit-60;
- border-radius: 50%;
- position: relative;
- background: var(--wp-admin-theme-color);
- border-color: var(--wp-admin-theme-color);
- border-style: solid;
- color: $white;
+ padding: 0;
- > svg {
- color: inherit;
+ // Hide the upload button, as it's also available in the media library.
+ .components-form-file-upload {
+ display: none;
}
- }
- // Show default placeholder height when not resized.
- min-height: 200px;
+ // Style the upload button.
+ .components-button.components-button {
+ padding: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: $grid-unit-60;
+ height: $grid-unit-60;
+ border-radius: 50%;
+ position: relative;
+ background: var(--wp-admin-theme-color);
+ border-color: var(--wp-admin-theme-color);
+ border-style: solid;
+ color: $white;
- // The following override the default placeholder styles that remove
- // its border so that a user selection for border color or width displays
- // a visual border.
- &:where(.has-border-color) {
- border-style: solid;
- }
- &:where([style*="border-top-color"]) {
- border-top-style: solid;
- }
- &:where([style*="border-right-color"]) {
- border-right-style: solid;
- }
- &:where([style*="border-bottom-color"]) {
- border-bottom-style: solid;
- }
- &:where([style*="border-left-color"]) {
- border-left-style: solid;
- }
+ > svg {
+ color: inherit;
+ }
+ }
- &:where([style*="border-width"]) {
- border-style: solid;
- }
- &:where([style*="border-top-width"]) {
- border-top-style: solid;
- }
- &:where([style*="border-right-width"]) {
- border-right-style: solid;
- }
- &:where([style*="border-bottom-width"]) {
- border-bottom-style: solid;
- }
- &:where([style*="border-left-width"]) {
- border-left-style: solid;
+ // Show default placeholder height when not resized.
+ min-height: 200px;
+
+ // The following override the default placeholder styles that remove
+ // its border so that a user selection for border color or width displays
+ // a visual border.
+ &:where(.has-border-color) {
+ border-style: solid;
+ }
+ &:where([style*="border-top-color"]) {
+ border-top-style: solid;
+ }
+ &:where([style*="border-right-color"]) {
+ border-right-style: solid;
+ }
+ &:where([style*="border-bottom-color"]) {
+ border-bottom-style: solid;
+ }
+ &:where([style*="border-left-color"]) {
+ border-left-style: solid;
+ }
+
+ &:where([style*="border-width"]) {
+ border-style: solid;
+ }
+ &:where([style*="border-top-width"]) {
+ border-top-style: solid;
+ }
+ &:where([style*="border-right-width"]) {
+ border-right-style: solid;
+ }
+ &:where([style*="border-bottom-width"]) {
+ border-bottom-style: solid;
+ }
+ &:where([style*="border-left-width"]) {
+ border-left-style: solid;
+ }
}
- }
- // Provide a minimum size for the placeholder when resized.
- // Note, this should be as small as we can afford it, and exists only
- // to ensure there's room for the upload button.
- &[style*="height"] .components-placeholder {
- min-height: $grid-unit-60;
- min-width: $grid-unit-60;
- height: 100%;
- width: 100%;
+ // Provide a minimum size for the placeholder when resized.
+ // Note, this should be as small as we can afford it, and exists only
+ // to ensure there's room for the upload button.
+ &[style*="height"] .components-placeholder {
+ min-height: $grid-unit-60;
+ min-width: $grid-unit-60;
+ height: 100%;
+ width: 100%;
+ }
}
}
diff --git a/packages/block-library/src/post-featured-image/index.php b/packages/block-library/src/post-featured-image/index.php
index 5e7ed6f70332de..931d87c0265c10 100644
--- a/packages/block-library/src/post-featured-image/index.php
+++ b/packages/block-library/src/post-featured-image/index.php
@@ -19,10 +19,11 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
}
$post_ID = $block->context['postId'];
- $is_link = isset( $attributes['isLink'] ) && $attributes['isLink'];
- $size_slug = isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : 'post-thumbnail';
- $post_title = trim( strip_tags( get_the_title( $post_ID ) ) );
- $attr = get_block_core_post_featured_image_border_attributes( $attributes );
+ $is_link = isset( $attributes['isLink'] ) && $attributes['isLink'];
+ $size_slug = isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : 'post-thumbnail';
+ $post_title = trim( strip_tags( get_the_title( $post_ID ) ) );
+ $attr = get_block_core_post_featured_image_border_attributes( $attributes );
+ $overlay_markup = get_block_core_post_featured_image_overlay_element_markup( $attributes );
if ( $is_link ) {
$attr['alt'] = $post_title;
@@ -36,13 +37,22 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
if ( $is_link ) {
$link_target = $attributes['linkTarget'];
$rel = ! empty( $attributes['rel'] ) ? 'rel="' . esc_attr( $attributes['rel'] ) . '"' : '';
- $featured_image = sprintf( '%4$s', get_the_permalink( $post_ID ), esc_attr( $link_target ), $rel, $featured_image );
+ $featured_image = sprintf(
+ '%4$s%5$s',
+ get_the_permalink( $post_ID ),
+ esc_attr( $link_target ),
+ $rel,
+ $featured_image,
+ $overlay_markup
+ );
+ } else {
+ $featured_image = $featured_image . $overlay_markup;
}
$has_width = ! empty( $attributes['width'] );
$has_height = ! empty( $attributes['height'] );
if ( ! $has_height && ! $has_width ) {
- return "";
+ return "";
}
if ( $has_width ) {
@@ -57,7 +67,78 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
$featured_image = str_replace( 'src=', 'style="' . esc_attr( $image_styles ) . '" src=', $featured_image );
}
- return "";
+ return "";
+}
+
+/**
+ * Generate markup for the HTML element that will be used for the overlay.
+ *
+ * @param array $attributes Block attributes.
+ *
+ * @return string HTML markup in string format.
+ */
+function get_block_core_post_featured_image_overlay_element_markup( $attributes ) {
+ $has_dim_background = isset( $attributes['dimRatio'] ) && $attributes['dimRatio'];
+ $has_gradient = isset( $attributes['gradient'] ) && $attributes['gradient'];
+ $has_custom_gradient = isset( $attributes['customGradient'] ) && $attributes['customGradient'];
+ $has_solid_overlay = isset( $attributes['overlayColor'] ) && $attributes['overlayColor'];
+ $has_custom_overlay = isset( $attributes['customOverlayColor'] ) && $attributes['customOverlayColor'];
+ $class_names = array(
+ 'wp-block-post-featured-image__overlay',
+ );
+ $styles_properties = array();
+
+ if ( ! $has_dim_background ) {
+ return '';
+ }
+
+ // Generate required classes for the element.
+ if ( $has_dim_background ) {
+ $class_names[] = 'has-background-dim';
+ $class_names[] = "has-background-dim-{$attributes['dimRatio']}";
+ }
+
+ if ( $has_solid_overlay ) {
+ $class_names[] = "has-{$attributes['overlayColor']}-background-color";
+ }
+
+ if ( $has_gradient || $has_custom_gradient ) {
+ $class_names[] = 'has-background-gradient';
+ }
+
+ if ( $has_gradient ) {
+ $class_names[] = "has-{$attributes['gradient']}-gradient-background";
+ }
+
+ // Generate required CSS properties and their values.
+ if ( ! empty( $attributes['style']['border']['radius'] ) ) {
+ $styles_properties['border-radius'] = $attributes['style']['border']['radius'];
+ }
+
+ if ( ! empty( $attributes['style']['border']['width'] ) ) {
+ $styles_properties['border-width'] = $attributes['style']['border']['width'];
+ }
+
+ if ( $has_custom_gradient ) {
+ $styles_properties['background-image'] = $attributes['customGradient'];
+ }
+
+ if ( $has_custom_overlay ) {
+ $styles_properties['background-color'] = $attributes['customOverlayColor'];
+ }
+
+ $styles = '';
+
+ foreach ( $styles_properties as $style_attribute => $style_attribute_value ) {
+ $styles .= "{$style_attribute}: $style_attribute_value; ";
+ }
+
+ return sprintf(
+ '',
+ esc_attr( implode( ' ', $class_names ) ),
+ esc_attr( trim( $styles ) )
+ );
+
}
/**
diff --git a/packages/block-library/src/post-featured-image/overlay.js b/packages/block-library/src/post-featured-image/overlay.js
new file mode 100644
index 00000000000000..572cef64801e76
--- /dev/null
+++ b/packages/block-library/src/post-featured-image/overlay.js
@@ -0,0 +1,118 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import {
+ RangeControl,
+ __experimentalToolsPanelItem as ToolsPanelItem,
+} from '@wordpress/components';
+import {
+ InspectorControls,
+ withColors,
+ __experimentalColorGradientSettingsDropdown as ColorGradientSettingsDropdown,
+ __experimentalUseGradient,
+ __experimentalUseMultipleOriginColorsAndGradients as useMultipleOriginColorsAndGradients,
+ __experimentalUseBorderProps as useBorderProps,
+} from '@wordpress/block-editor';
+import { compose } from '@wordpress/compose';
+import { __ } from '@wordpress/i18n';
+
+/**
+ * Internal dependencies
+ */
+import { dimRatioToClass } from './utils';
+
+const Overlay = ( {
+ clientId,
+ attributes,
+ setAttributes,
+ overlayColor,
+ setOverlayColor,
+} ) => {
+ const { dimRatio } = attributes;
+ const { gradientClass, gradientValue, setGradient } =
+ __experimentalUseGradient();
+ const colorGradientSettings = useMultipleOriginColorsAndGradients();
+
+ const borderProps = useBorderProps( attributes );
+ const overlayStyles = {
+ backgroundColor: overlayColor.color,
+ backgroundImage: gradientValue,
+ ...borderProps.style,
+ };
+
+ return (
+ <>
+
+
+ ( {
+ overlayColor: undefined,
+ customOverlayColor: undefined,
+ gradient: undefined,
+ customGradient: undefined,
+ } ),
+ },
+ ] }
+ panelId={ clientId }
+ { ...colorGradientSettings }
+ />
+ dimRatio !== undefined }
+ label={ __( 'Overlay opacity' ) }
+ onDeselect={ () => setAttributes( { dimRatio: 0 } ) }
+ resetAllFilter={ () => ( {
+ dimRatio: 0,
+ } ) }
+ isShownByDefault
+ panelId={ clientId }
+ >
+
+ setAttributes( {
+ dimRatio: newDimRatio,
+ } )
+ }
+ min={ 0 }
+ max={ 100 }
+ step={ 10 }
+ required
+ />
+
+
+ >
+ );
+};
+
+export default compose( [
+ withColors( { overlayColor: 'background-color' } ),
+] )( Overlay );
diff --git a/packages/block-library/src/post-featured-image/style.scss b/packages/block-library/src/post-featured-image/style.scss
index 7af2f5331c82cd..d4cfbc7273638f 100644
--- a/packages/block-library/src/post-featured-image/style.scss
+++ b/packages/block-library/src/post-featured-image/style.scss
@@ -16,4 +16,26 @@
&.alignfull img {
width: 100%;
}
+
+ .wp-block-post-featured-image__overlay {
+ &.has-background-dim {
+ position: absolute;
+ inset: 0;
+ background-color: $black;
+
+ @at-root .wp-block-post-featured-image {
+ position: relative;
+ }
+ }
+
+ &.has-background-gradient {
+ background-color: transparent;
+ }
+
+ @for $i from 0 through 10 {
+ &.has-background-dim-#{ $i * 10 } {
+ opacity: $i * 0.1;
+ }
+ }
+ }
}
diff --git a/packages/block-library/src/post-featured-image/utils.js b/packages/block-library/src/post-featured-image/utils.js
new file mode 100644
index 00000000000000..94dfc5410a84ab
--- /dev/null
+++ b/packages/block-library/src/post-featured-image/utils.js
@@ -0,0 +1,12 @@
+/**
+ * Generates the opacity/dim class based on given number.
+ *
+ * @param {number} ratio Dim/opacity number.
+ *
+ * @return {string} Generated class.
+ */
+export function dimRatioToClass( ratio ) {
+ return ratio === undefined
+ ? null
+ : 'has-background-dim-' + 10 * Math.round( ratio / 10 );
+}
diff --git a/test/integration/fixtures/blocks/core__post-featured-image.json b/test/integration/fixtures/blocks/core__post-featured-image.json
index 7086665089d638..29a7ccbe5c65ab 100644
--- a/test/integration/fixtures/blocks/core__post-featured-image.json
+++ b/test/integration/fixtures/blocks/core__post-featured-image.json
@@ -3,6 +3,7 @@
"name": "core/post-featured-image",
"isValid": true,
"attributes": {
+ "dimRatio": 0,
"isLink": false,
"scale": "cover",
"rel": "",