@wordpress/block-library
Version:
Block library for the WordPress editor.
218 lines (202 loc) • 5.61 kB
JavaScript
/**
* External dependencies
*/
import { isUndefined, pickBy } from 'lodash';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import {
Component,
Fragment,
RawHTML,
} from '@wordpress/element';
import {
PanelBody,
Placeholder,
QueryControls,
RangeControl,
Spinner,
ToggleControl,
Toolbar,
} from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch';
import { addQueryArgs } from '@wordpress/url';
import { __ } from '@wordpress/i18n';
import { dateI18n, format, __experimentalGetSettings } from '@wordpress/date';
import {
InspectorControls,
BlockAlignmentToolbar,
BlockControls,
} from '@wordpress/block-editor';
import { withSelect } from '@wordpress/data';
/**
* Module Constants
*/
const CATEGORIES_LIST_QUERY = {
per_page: -1,
};
const MAX_POSTS_COLUMNS = 6;
class LatestPostsEdit extends Component {
constructor() {
super( ...arguments );
this.state = {
categoriesList: [],
};
this.toggleDisplayPostDate = this.toggleDisplayPostDate.bind( this );
}
componentWillMount() {
this.isStillMounted = true;
this.fetchRequest = apiFetch( {
path: addQueryArgs( `/wp/v2/categories`, CATEGORIES_LIST_QUERY ),
} ).then(
( categoriesList ) => {
if ( this.isStillMounted ) {
this.setState( { categoriesList } );
}
}
).catch(
() => {
if ( this.isStillMounted ) {
this.setState( { categoriesList: [] } );
}
}
);
}
componentWillUnmount() {
this.isStillMounted = false;
}
toggleDisplayPostDate() {
const { displayPostDate } = this.props.attributes;
const { setAttributes } = this.props;
setAttributes( { displayPostDate: ! displayPostDate } );
}
render() {
const { attributes, setAttributes, latestPosts } = this.props;
const { categoriesList } = this.state;
const { displayPostDate, align, postLayout, columns, order, orderBy, categories, postsToShow } = attributes;
const inspectorControls = (
<InspectorControls>
<PanelBody title={ __( 'Latest Posts Settings' ) }>
<QueryControls
{ ...{ order, orderBy } }
numberOfItems={ postsToShow }
categoriesList={ categoriesList }
selectedCategoryId={ categories }
onOrderChange={ ( value ) => setAttributes( { order: value } ) }
onOrderByChange={ ( value ) => setAttributes( { orderBy: value } ) }
onCategoryChange={ ( value ) => setAttributes( { categories: '' !== value ? value : undefined } ) }
onNumberOfItemsChange={ ( value ) => setAttributes( { postsToShow: value } ) }
/>
<ToggleControl
label={ __( 'Display post date' ) }
checked={ displayPostDate }
onChange={ this.toggleDisplayPostDate }
/>
{ postLayout === 'grid' &&
<RangeControl
label={ __( 'Columns' ) }
value={ columns }
onChange={ ( value ) => setAttributes( { columns: value } ) }
min={ 2 }
max={ ! hasPosts ? MAX_POSTS_COLUMNS : Math.min( MAX_POSTS_COLUMNS, latestPosts.length ) }
required
/>
}
</PanelBody>
</InspectorControls>
);
const hasPosts = Array.isArray( latestPosts ) && latestPosts.length;
if ( ! hasPosts ) {
return (
<Fragment>
{ inspectorControls }
<Placeholder
icon="admin-post"
label={ __( 'Latest Posts' ) }
>
{ ! Array.isArray( latestPosts ) ?
<Spinner /> :
__( 'No posts found.' )
}
</Placeholder>
</Fragment>
);
}
// Removing posts from display should be instant.
const displayPosts = latestPosts.length > postsToShow ?
latestPosts.slice( 0, postsToShow ) :
latestPosts;
const layoutControls = [
{
icon: 'list-view',
title: __( 'List View' ),
onClick: () => setAttributes( { postLayout: 'list' } ),
isActive: postLayout === 'list',
},
{
icon: 'grid-view',
title: __( 'Grid View' ),
onClick: () => setAttributes( { postLayout: 'grid' } ),
isActive: postLayout === 'grid',
},
];
const dateFormat = __experimentalGetSettings().formats.date;
return (
<Fragment>
{ inspectorControls }
<BlockControls>
<BlockAlignmentToolbar
value={ align }
onChange={ ( nextAlign ) => {
setAttributes( { align: nextAlign } );
} }
/>
<Toolbar controls={ layoutControls } />
</BlockControls>
<ul
className={ classnames( this.props.className, {
'is-grid': postLayout === 'grid',
'has-dates': displayPostDate,
[ `columns-${ columns }` ]: postLayout === 'grid',
} ) }
>
{ displayPosts.map( ( post, i ) => {
const titleTrimmed = post.title.rendered.trim();
return (
<li key={ i }>
<a href={ post.link } target="_blank" rel="noreferrer noopener">
{ titleTrimmed ? (
<RawHTML>
{ titleTrimmed }
</RawHTML>
) :
__( '(Untitled)' )
}
</a>
{ displayPostDate && post.date_gmt &&
<time dateTime={ format( 'c', post.date_gmt ) } className="wp-block-latest-posts__post-date">
{ dateI18n( dateFormat, post.date_gmt ) }
</time>
}
</li>
);
} ) }
</ul>
</Fragment>
);
}
}
export default withSelect( ( select, props ) => {
const { postsToShow, order, orderBy, categories } = props.attributes;
const { getEntityRecords } = select( 'core' );
const latestPostsQuery = pickBy( {
categories,
order,
orderby: orderBy,
per_page: postsToShow,
}, ( value ) => ! isUndefined( value ) );
return {
latestPosts: getEntityRecords( 'postType', 'post', latestPostsQuery ),
};
} )( LatestPostsEdit );