diff --git a/lib/client-assets.php b/lib/client-assets.php index 192875b53f337c..b0e2f7ed77c4f4 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -677,3 +677,24 @@ function gutenberg_extend_block_editor_preload_paths( $preload_paths, $post ) { return $preload_paths; } add_filter( 'block_editor_preload_paths', 'gutenberg_extend_block_editor_preload_paths', 10, 2 ); + +/** + * Extends block editor settings to include a list of image dimensions per size. + * + * @param array $settings Default editor settings. + * + * @return array Filtered editor settings. + */ +function gutenberg_extend_settings_image_dimensions( $settings ) { + $image_dimensions = array(); + $all_sizes = wp_get_registered_image_subsizes(); + foreach ( $settings['imageSizes'] as $size ) { + $key = $size['slug']; + if ( isset( $all_sizes[ $key ] ) ) { + $image_dimensions[ $key ] = $all_sizes[ $key ]; + } + } + $settings['imageDimensions'] = $image_dimensions; + return $settings; +} +add_filter( 'block_editor_settings', 'gutenberg_extend_settings_image_dimensions' ); diff --git a/packages/block-library/src/latest-posts/edit.js b/packages/block-library/src/latest-posts/edit.js index 018f1ba8e51ae4..709cd052e68fa9 100644 --- a/packages/block-library/src/latest-posts/edit.js +++ b/packages/block-library/src/latest-posts/edit.js @@ -1,7 +1,7 @@ /** * External dependencies */ -import { isUndefined, pickBy } from 'lodash'; +import { get, isUndefined, pickBy } from 'lodash'; import classnames from 'classnames'; /** @@ -9,6 +9,7 @@ import classnames from 'classnames'; */ import { Component, RawHTML } from '@wordpress/element'; import { + BaseControl, PanelBody, Placeholder, QueryControls, @@ -22,7 +23,12 @@ import apiFetch from '@wordpress/api-fetch'; import { addQueryArgs } from '@wordpress/url'; import { __ } from '@wordpress/i18n'; import { dateI18n, format, __experimentalGetSettings } from '@wordpress/date'; -import { InspectorControls, BlockControls } from '@wordpress/block-editor'; +import { + InspectorControls, + BlockAlignmentToolbar, + BlockControls, + __experimentalImageSizeControl as ImageSizeControl, +} from '@wordpress/block-editor'; import { withSelect } from '@wordpress/data'; /** @@ -63,9 +69,17 @@ class LatestPostsEdit extends Component { } render() { - const { attributes, setAttributes, latestPosts } = this.props; + const { + attributes, + setAttributes, + imageSizeOptions, + latestPosts, + defaultImageWidth, + defaultImageHeight, + } = this.props; const { categoriesList } = this.state; const { + displayFeaturedImage, displayPostContentRadio, displayPostContent, displayPostDate, @@ -76,6 +90,10 @@ class LatestPostsEdit extends Component { categories, postsToShow, excerptLength, + featuredImageAlign, + featuredImageSizeSlug, + featuredImageSizeWidth, + featuredImageSizeHeight, } = attributes; const inspectorControls = ( @@ -130,6 +148,62 @@ class LatestPostsEdit extends Component { /> + + + setAttributes( { displayFeaturedImage: value } ) + } + /> + { displayFeaturedImage && ( + <> + { + const newAttrs = {}; + if ( value.hasOwnProperty( 'width' ) ) { + newAttrs.featuredImageSizeWidth = + value.width; + } + if ( value.hasOwnProperty( 'height' ) ) { + newAttrs.featuredImageSizeHeight = + value.height; + } + setAttributes( newAttrs ); + } } + slug={ featuredImageSizeSlug } + width={ featuredImageSizeWidth } + height={ featuredImageSizeHeight } + imageWidth={ defaultImageWidth } + imageHeight={ defaultImageHeight } + imageSizeOptions={ imageSizeOptions } + onChangeImage={ ( value ) => + setAttributes( { + featuredImageSizeSlug: value, + featuredImageSizeWidth: undefined, + featuredImageSizeHeight: undefined, + } ) + } + /> + + + { __( 'Image Alignment' ) } + + + setAttributes( { + featuredImageAlign: value, + } ) + } + controls={ [ 'left', 'center', 'right' ] } + isCollapsed={ false } + /> + + + ) } + + + { displayFeaturedImage && ( +
+ { imageSourceUrl && ( + + ) } +
+ ) } { - const { postsToShow, order, orderBy, categories } = props.attributes; - const { getEntityRecords } = select( 'core' ); + const { + featuredImageSizeSlug, + postsToShow, + order, + orderBy, + categories, + } = props.attributes; + const { getEntityRecords, getMedia } = select( 'core' ); + const { getSettings } = select( 'core/block-editor' ); + const { imageSizes, imageDimensions } = getSettings(); const latestPostsQuery = pickBy( { categories, @@ -325,7 +430,37 @@ export default withSelect( ( select, props ) => { }, ( value ) => ! isUndefined( value ) ); + + const posts = getEntityRecords( 'postType', 'post', latestPostsQuery ); + const imageSizeOptions = imageSizes + .filter( ( { slug } ) => slug !== 'full' ) + .map( ( { name, slug } ) => ( { value: slug, label: name } ) ); + return { - latestPosts: getEntityRecords( 'postType', 'post', latestPostsQuery ), + defaultImageWidth: imageDimensions[ featuredImageSizeSlug ].width, + defaultImageHeight: imageDimensions[ featuredImageSizeSlug ].height, + imageSizeOptions, + latestPosts: ! Array.isArray( posts ) + ? posts + : posts.map( ( post ) => { + if ( post.featured_media ) { + const image = getMedia( post.featured_media ); + let url = get( + image, + [ + 'media_details', + 'sizes', + featuredImageSizeSlug, + 'source_url', + ], + null + ); + if ( ! url ) { + url = get( image, 'source_url', null ); + } + return { ...post, featuredImageSourceUrl: url }; + } + return post; + } ), }; } )( LatestPostsEdit ); diff --git a/packages/block-library/src/latest-posts/index.php b/packages/block-library/src/latest-posts/index.php index 5d05fb92181814..86706bd2b23a3d 100644 --- a/packages/block-library/src/latest-posts/index.php +++ b/packages/block-library/src/latest-posts/index.php @@ -30,12 +30,41 @@ function render_block_core_latest_posts( $attributes ) { $list_items_markup = ''; foreach ( $recent_posts as $post ) { + $list_items_markup .= '
  • '; + + if ( $attributes['displayFeaturedImage'] && has_post_thumbnail( $post ) ) { + $image_style = ''; + if ( isset( $attributes['featuredImageSizeWidth'] ) ) { + $image_style .= sprintf( 'max-width:%spx;', $attributes['featuredImageSizeWidth'] ); + } + if ( isset( $attributes['featuredImageSizeHeight'] ) ) { + $image_style .= sprintf( 'max-height:%spx;', $attributes['featuredImageSizeHeight'] ); + } + + $image_classes = 'wp-block-latest-posts__featured-image'; + if ( isset( $attributes['featuredImageAlign'] ) ) { + $image_classes .= ' align' . $attributes['featuredImageAlign']; + } + + $list_items_markup .= sprintf( + '
    %2$s
    ', + $image_classes, + get_the_post_thumbnail( + $post, + $attributes['featuredImageSizeSlug'], + array( + 'style' => $image_style, + ) + ) + ); + } + $title = get_the_title( $post ); if ( ! $title ) { $title = __( '(no title)' ); } $list_items_markup .= sprintf( - '
  • %2$s', + '%2$s', esc_url( get_permalink( $post ) ), $title ); @@ -164,6 +193,26 @@ function register_block_core_latest_posts() { 'type' => 'string', 'default' => 'date', ), + 'displayFeaturedImage' => array( + 'type' => 'boolean', + 'default' => false, + ), + 'featuredImageAlign' => array( + 'type' => 'string', + 'enum' => array( 'left', 'center', 'right' ), + ), + 'featuredImageSizeSlug' => array( + 'type' => 'string', + 'default' => 'thumbnail', + ), + 'featuredImageSizeWidth' => array( + 'type' => 'number', + 'default' => null, + ), + 'featuredImageSizeHeight' => array( + 'type' => 'number', + 'default' => null, + ), ), 'render_callback' => 'render_block_core_latest_posts', ) diff --git a/packages/block-library/src/latest-posts/style.scss b/packages/block-library/src/latest-posts/style.scss index 9bfbbad503e964..66d23a4c721177 100644 --- a/packages/block-library/src/latest-posts/style.scss +++ b/packages/block-library/src/latest-posts/style.scss @@ -9,6 +9,10 @@ } &.wp-block-latest-posts__list { list-style: none; + + li { + clear: both; + } } &.is-grid { display: flex; @@ -40,3 +44,22 @@ margin-top: $grid-size; margin-bottom: $grid-size-large; } + +.wp-block-latest-posts__featured-image { + img { + height: auto; + width: auto; + } + &.alignleft { + /*rtl:ignore*/ + margin-right: 1em; + } + &.alignright { + /*rtl:ignore*/ + margin-left: 1em; + } + &.aligncenter { + margin-bottom: 1em; + text-align: center; + } +} diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 600ab00a3d4892..c08379f93e3bc4 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -106,6 +106,7 @@ class EditorProvider extends Component { 'hasFixedToolbar', 'hasPermissionsToManageWidgets', 'imageSizes', + 'imageDimensions', 'isRTL', 'maxWidth', 'styles',