Skip to content

Commit

Permalink
Post Featured Image: Add a useFirstImageFromPost attribute (#56573)
Browse files Browse the repository at this point in the history
* Post Featured Image: Add a useFirstImageFromPost attribute

* Add a comment and remove the toggle

* PHPCS

* only load image if there is post content

* use a regex to improve performance

* don't update the value that comes from the useSelect

* update snapshots

* simplify regex
  • Loading branch information
scruffian authored Jan 4, 2024
1 parent 15b6981 commit 5e02c30
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 3 deletions.
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,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:** aspectRatio, customGradient, customOverlayColor, dimRatio, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, width
- **Attributes:** aspectRatio, customGradient, customOverlayColor, dimRatio, gradient, height, isLink, linkTarget, overlayColor, rel, scale, sizeSlug, useFirstImageFromPost, width

## Post Navigation Link

Expand Down
4 changes: 4 additions & 0 deletions packages/block-library/src/post-featured-image/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@
},
"customGradient": {
"type": "string"
},
"useFirstImageFromPost": {
"type": "boolean",
"default": false
}
},
"usesContext": [ "postId", "postType", "queryId" ],
Expand Down
33 changes: 32 additions & 1 deletion packages/block-library/src/post-featured-image/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
store as blockEditorStore,
__experimentalUseBorderProps as useBorderProps,
} from '@wordpress/block-editor';
import { useMemo } from '@wordpress/element';
import { __, sprintf } from '@wordpress/i18n';
import { upload } from '@wordpress/icons';
import { store as noticesStore } from '@wordpress/notices';
Expand Down Expand Up @@ -64,14 +65,44 @@ export default function PostFeaturedImageEdit( {
sizeSlug,
rel,
linkTarget,
useFirstImageFromPost,
} = attributes;
const [ featuredImage, setFeaturedImage ] = useEntityProp(

const [ storedFeaturedImage, setFeaturedImage ] = useEntityProp(
'postType',
postTypeSlug,
'featured_media',
postId
);

// Fallback to post content if no featured image is set.
// This is needed for the "Use first image from post" option.
const [ postContent ] = useEntityProp(
'postType',
postTypeSlug,
'content',
postId
);

const featuredImage = useMemo( () => {
if ( storedFeaturedImage ) {
return storedFeaturedImage;
}

if ( ! useFirstImageFromPost ) {
return;
}

const imageOpener =
/<!--\s+wp:(?:core\/)?image\s+(?<attrs>{(?:(?:[^}]+|}+(?=})|(?!}\s+\/?-->).)*)?}\s+)?-->/.exec(
postContent
);
const imageId =
imageOpener?.groups?.attrs &&
JSON.parse( imageOpener.groups.attrs )?.id;
return imageId;
}, [ storedFeaturedImage, useFirstImageFromPost, postContent ] );

const { media, postType, postPermalink } = useSelect(
( select ) => {
const { getMedia, getPostType, getEditedEntityRecord } =
Expand Down
31 changes: 31 additions & 0 deletions packages/block-library/src/post-featured-image/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,40 @@ function render_block_core_post_featured_image( $attributes, $content, $block )
}

$featured_image = get_the_post_thumbnail( $post_ID, $size_slug, $attr );

// Get the first image from the post.
if ( $attributes['useFirstImageFromPost'] && ! $featured_image ) {
$content_post = get_post( $post_ID );
$content = $content_post->post_content;
$processor = new WP_HTML_Tag_Processor( $content );

/*
* Transfer the image tag from the post into a new text snippet.
* Because the HTML API doesn't currently expose a way to extract
* HTML substrings this is necessary as a workaround. Of note, this
* is different than directly extracting the IMG tag:
* - If there are duplicate attributes in the source there will only be one in the output.
* - If there are single-quoted or unquoted attributes they will be double-quoted in the output.
* - If there are named character references in the attribute values they may be replaced with their direct code points. E.g. `&hellip;` becomes `…`.
* In the future there will likely be a mechanism to copy snippets of HTML from
* one document into another, via the HTML Processor's `get_outer_html()` or
* equivalent. When that happens it would be appropriate to replace this custom
* code with that canonical code.
*/
if ( $processor->next_tag( 'img' ) ) {
$tag_html = new WP_HTML_Tag_Processor( '<img>' );
$tag_html->next_tag();
foreach ( $processor->get_attribute_names_with_prefix( '' ) as $name ) {
$tag_html->set_attribute( $name, $processor->get_attribute( $name ) );
}
$featured_image = $tag_html->get_updated_html();
}
}

if ( ! $featured_image ) {
return '';
}

if ( $is_link ) {
$link_target = $attributes['linkTarget'];
$rel = ! empty( $attributes['rel'] ) ? 'rel="' . esc_attr( $attributes['rel'] ) . '"' : '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
"scale": "cover",
"rel": "",
"linkTarget": "_self",
"dimRatio": 0
"dimRatio": 0,
"useFirstImageFromPost": false
},
"innerBlocks": []
}
Expand Down

0 comments on commit 5e02c30

Please sign in to comment.