Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference-guides/core-blocks.md
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ Display a list of your most recent posts. ([Source](https://github.com/WordPress

- **Name:** core/latest-posts
- **Category:** widgets
- **Supports:** align, anchor, color (background, gradients, link, text), interactivity (clientNavigation), spacing (margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Supports:** align, anchor, color (background, gradients, link, text), interactivity (clientNavigation), layout, spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~html~~
- **Attributes:** addLinkToFeaturedImage, categories, columns, displayAuthor, displayFeaturedImage, displayPostContent, displayPostContentRadio, displayPostDate, excerptLength, featuredImageAlign, featuredImageSizeHeight, featuredImageSizeSlug, featuredImageSizeWidth, order, orderBy, postLayout, postsToShow, selectedAuthor

## List
Expand Down
9 changes: 8 additions & 1 deletion packages/block-library/src/latest-posts/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"anchor": true,
"align": true,
"html": false,
"layout": true,
"color": {
"gradients": true,
"link": true,
Expand All @@ -97,7 +98,13 @@
},
"spacing": {
"margin": true,
"padding": true
"padding": true,
"blockGap": {
"__experimentalDefault": "1.25em"
},
"__experimentalDefaultControls": {
"blockGap": true
}
},
"typography": {
"fontSize": true,
Expand Down
1 change: 0 additions & 1 deletion packages/block-library/src/latest-posts/constants.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export const MIN_EXCERPT_LENGTH = 10;
export const MAX_EXCERPT_LENGTH = 100;
export const MAX_POSTS_COLUMNS = 6;
export const DEFAULT_EXCERPT_LENGTH = 55;
64 changes: 56 additions & 8 deletions packages/block-library/src/latest-posts/deprecated.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,75 @@
*/
import metadata from './block.json';

const { attributes } = metadata;
const attributes = {
...metadata.attributes,
layout: {
type: 'object',
},
};

const migrateCategories = ( oldAttributes ) => {
if (
! oldAttributes.categories ||
'string' !== typeof oldAttributes.categories
) {
return oldAttributes;
}

// This needs the full category object, not just the ID.
return {
...oldAttributes,
categories: [ { id: Number( oldAttributes.categories ) } ],
};
};

const migratePostLayout = ( oldAttributes ) => {
const { postLayout, columns, layout, ...attributesWithoutLegacyLayout } =
oldAttributes;

if ( layout || ! postLayout ) {
return oldAttributes;
}

return {
...attributesWithoutLegacyLayout,
layout: {
type: postLayout === 'grid' ? 'grid' : 'default',
...( postLayout === 'grid' && columns && { columnCount: columns } ),
},
};
};

export default [
{
attributes: {
...attributes,
categories: {
type: 'string',
type: [ 'array', 'string' ],
},
},
supports: {
align: true,
html: false,
layout: true,
},
migrate: ( oldAttributes ) =>
migratePostLayout( migrateCategories( oldAttributes ) ),
isEligible: ( { layout, postLayout } ) => ! layout && postLayout,
save: () => null,
},
{
attributes: {
...attributes,
categories: {
type: 'string',
},
},
migrate: ( oldAttributes ) => {
// This needs the full category object, not just the ID.
return {
...oldAttributes,
categories: [ { id: Number( oldAttributes.categories ) } ],
};
supports: {
align: true,
html: false,
},
migrate: migrateCategories,
isEligible: ( { categories } ) =>
categories && 'string' === typeof categories,
save: () => null,
Expand Down
76 changes: 33 additions & 43 deletions packages/block-library/src/latest-posts/edit.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ import { createInterpolateElement } from '@wordpress/element';
import {
MIN_EXCERPT_LENGTH,
MAX_EXCERPT_LENGTH,
MAX_POSTS_COLUMNS,
DEFAULT_EXCERPT_LENGTH,
} from './constants';
import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
Expand Down Expand Up @@ -105,7 +104,7 @@ function getCurrentAuthor( post ) {
return post._embedded?.author?.[ 0 ];
}

function Controls( { attributes, setAttributes, postCount } ) {
function Controls( { attributes, setAttributes } ) {
const {
postsToShow,
order,
Expand All @@ -117,8 +116,6 @@ function Controls( { attributes, setAttributes, postCount } ) {
displayPostContent,
displayPostDate,
displayAuthor,
postLayout,
columns,
excerptLength,
featuredImageAlign,
featuredImageSizeSlug,
Expand Down Expand Up @@ -473,7 +470,6 @@ function Controls( { attributes, setAttributes, postCount } ) {
postsToShow: 5,
categories: undefined,
selectedAuthor: undefined,
columns: 3,
} )
}
dropdownMenuProps={ dropdownMenuProps }
Expand Down Expand Up @@ -523,41 +519,16 @@ function Controls( { attributes, setAttributes, postCount } ) {
selectedAuthorId={ selectedAuthor }
/>
</ToolsPanelItem>

{ postLayout === 'grid' && (
<ToolsPanelItem
hasValue={ () => columns !== 3 }
label={ __( 'Columns' ) }
onDeselect={ () =>
setAttributes( {
columns: 3,
} )
}
isShownByDefault
>
<RangeControl
__next40pxDefaultSize
label={ __( 'Columns' ) }
value={ columns }
onChange={ ( value ) =>
setAttributes( { columns: value } )
}
min={ 2 }
max={
! postCount
? MAX_POSTS_COLUMNS
: Math.min( MAX_POSTS_COLUMNS, postCount )
}
required
/>
</ToolsPanelItem>
) }
</ToolsPanel>
</>
);
}

export default function LatestPostsEdit( { attributes, setAttributes } ) {
export default function LatestPostsEdit( {
attributes,
setAttributes,
__unstableLayoutClassNames,
} ) {
const instanceId = useInstanceId( LatestPostsEdit );

const {
Expand All @@ -571,6 +542,7 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
displayPostContent,
displayPostDate,
displayAuthor,
layout,
postLayout,
columns,
excerptLength,
Expand All @@ -580,6 +552,11 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
featuredImageSizeHeight,
addLinkToFeaturedImage,
} = attributes;
const { type: savedLayoutType, minimumColumnWidth } = layout || {};
const layoutType =
savedLayoutType || ( postLayout === 'grid' ? 'grid' : 'default' );
const columnCount =
layout?.columnCount ?? ( ! savedLayoutType ? columns : undefined ) ?? 3;
const { latestPosts } = useSelect(
( select ) => {
const { getEntityRecords } = select( coreStore );
Expand Down Expand Up @@ -626,18 +603,20 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
<Controls
attributes={ attributes }
setAttributes={ setAttributes }
postCount={ latestPosts?.length ?? 0 }
/>
</InspectorControls>
);

const blockProps = useBlockProps( {
className: clsx( {
className: clsx( __unstableLayoutClassNames, {
'wp-block-latest-posts__list': true,
'is-grid': postLayout === 'grid',
'is-grid': layoutType === 'grid',
'has-dates': displayPostDate,
'has-author': displayAuthor,
[ `columns-${ columns }` ]: postLayout === 'grid',
[ `columns-${ columnCount }` ]:
layoutType === 'grid' && columnCount,
'has-native-responsive-grid':
layoutType === 'grid' && columnCount && minimumColumnWidth,
} ),
} );

Expand All @@ -662,18 +641,29 @@ export default function LatestPostsEdit( { attributes, setAttributes } ) {
? latestPosts.slice( 0, postsToShow )
: latestPosts;

const setDisplayLayout = ( newDisplayLayout ) =>
setAttributes( {
layout: { ...layout, ...newDisplayLayout },
postLayout: undefined,
columns: undefined,
} );

const layoutControls = [
{
icon: list,
title: _x( 'List view', 'Latest posts block display setting' ),
onClick: () => setAttributes( { postLayout: 'list' } ),
isActive: postLayout === 'list',
onClick: () => setDisplayLayout( { type: 'default' } ),
isActive: layoutType === 'default' || layoutType === 'constrained',
},
{
icon: grid,
title: _x( 'Grid view', 'Latest posts block display setting' ),
onClick: () => setAttributes( { postLayout: 'grid' } ),
isActive: postLayout === 'grid',
onClick: () =>
setDisplayLayout( {
type: 'grid',
columnCount,
} ),
isActive: layoutType === 'grid',
},
];

Expand Down
17 changes: 14 additions & 3 deletions packages/block-library/src/latest-posts/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -200,12 +200,23 @@ function render_block_core_latest_posts( $attributes ) {

remove_filter( 'excerpt_length', 'block_core_latest_posts_get_excerpt_length', 20 );

$layout = $attributes['layout'] ?? array();
$legacy_layout_type = (
isset( $attributes['postLayout'] ) &&
'grid' === $attributes['postLayout']
) ? 'grid' : 'default';
$layout_type = $layout['type'] ?? $legacy_layout_type;
$column_count = $layout['columnCount'] ?? ( $attributes['columns'] ?? null );

$classes = array( 'wp-block-latest-posts__list' );
if ( isset( $attributes['postLayout'] ) && 'grid' === $attributes['postLayout'] ) {
if ( 'grid' === $layout_type ) {
$classes[] = 'is-grid';
}
if ( isset( $attributes['columns'] ) && 'grid' === $attributes['postLayout'] ) {
$classes[] = 'columns-' . $attributes['columns'];
if ( 'grid' === $layout_type && ! empty( $column_count ) ) {
$classes[] = sanitize_title( 'columns-' . $column_count );
}
if ( 'grid' === $layout_type && ! empty( $column_count ) && ! empty( $layout['minimumColumnWidth'] ) ) {
$classes[] = 'has-native-responsive-grid';
}
if ( isset( $attributes['displayPostDate'] ) && $attributes['displayPostDate'] ) {
$classes[] = 'has-dates';
Expand Down
14 changes: 12 additions & 2 deletions packages/block-library/src/latest-posts/style.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@use "@wordpress/base-styles/breakpoints" as *;
@use "@wordpress/base-styles/mixins" as *;

.wp-block-latest-posts {
Expand All @@ -21,7 +22,9 @@
}
}

&.is-grid {
// These rules no longer apply to blocks using layout support, but should
// be kept for backwards compatibility.
&.is-grid:not(.is-layout-grid) {
display: flex;
flex-wrap: wrap;

Expand All @@ -33,7 +36,7 @@

@include break-small {
@for $i from 2 through 6 {
&.columns-#{ $i } li {
&.columns-#{ $i }:not(.is-layout-grid) li {
width: calc((100% / #{$i}) - 1.25em + (1.25em / #{$i}));

&:nth-child(#{ $i }n) {
Expand All @@ -44,6 +47,13 @@
}
}

@media (max-width: $break-small) {
// Temporary specificity bump until "wp-container" layout specificity is revisited.
.wp-block-latest-posts-is-layout-grid[class*="columns-"]:not(.has-native-responsive-grid) {
grid-template-columns: 1fr;
}
}

:root {
:where(.wp-block-latest-posts.is-grid) {
padding: 0;
Expand Down
38 changes: 38 additions & 0 deletions packages/block-library/src/latest-posts/test/deprecated.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Internal dependencies
*/
import deprecated from '../deprecated';

describe( 'Latest Posts deprecations', () => {
it( 'migrates legacy grid layout attributes to layout support attributes', () => {
const migratedAttributes = deprecated[ 0 ].migrate( {
postLayout: 'grid',
columns: 4,
postsToShow: 3,
} );

expect( migratedAttributes ).toEqual( {
layout: {
type: 'grid',
columnCount: 4,
},
postsToShow: 3,
} );
} );

it( 'preserves the legacy categories migration while migrating layout', () => {
const migratedAttributes = deprecated[ 0 ].migrate( {
categories: '7',
postLayout: 'grid',
columns: 2,
} );

expect( migratedAttributes ).toEqual( {
categories: [ { id: 7 } ],
layout: {
type: 'grid',
columnCount: 2,
},
} );
} );
} );
Loading
Loading