Skip to content

Commit

Permalink
Implemented query panel in latest posts block. (#3198)
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgefilipecosta authored Dec 14, 2017
1 parent e421572 commit d94d742
Show file tree
Hide file tree
Showing 9 changed files with 277 additions and 33 deletions.
8 changes: 7 additions & 1 deletion blocks/library/latest-posts/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,21 @@
* Returns a Promise with the latest posts or an error on failure.
*
* @param {Number} postsToShow Number of posts to display.
* @param {String} order Whether to sort in ascending or descending order: 'asc'|'desc'.
* @param {String} orderBy Post parameter by which to sort posts.
* @param {String} categories The terms assigned to the post in the category taxonomy.
*
* @returns {wp.api.collections.Posts} Returns a Promise with the latest posts.
*/
export function getLatestPosts( postsToShow = 5 ) {
export function getLatestPosts( postsToShow, order, orderBy, categories ) {
const postsCollection = new wp.api.collections.Posts();

const posts = postsCollection.fetch( {
data: {
per_page: postsToShow,
order,
orderby: orderBy,
categories,
},
} );

Expand Down
54 changes: 22 additions & 32 deletions blocks/library/latest-posts/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,14 @@ import './editor.scss';
import './style.scss';
import { registerBlockType } from '../../api';
import { getLatestPosts } from './data.js';
import QueryPanel from '../../query-panel';
import InspectorControls from '../../inspector-controls';
import TextControl from '../../inspector-controls/text-control';
import ToggleControl from '../../inspector-controls/toggle-control';
import RangeControl from '../../inspector-controls/range-control';
import BlockDescription from '../../block-description';
import BlockControls from '../../block-controls';
import BlockAlignmentToolbar from '../../block-alignment-toolbar';

const MIN_POSTS = 1;
const MAX_POSTS = 100;
const MAX_POSTS_COLUMNS = 6;

registerBlockType( 'core/latest-posts', {
Expand All @@ -48,15 +46,14 @@ registerBlockType( 'core/latest-posts', {
edit: class extends Component {
constructor() {
super( ...arguments );
this.changePostsToShow = this.changePostsToShow.bind( this );

const { postsToShow } = this.props.attributes;

this.state = {
latestPosts: null,
};

this.latestPostsRequest = getLatestPosts( postsToShow );
const { postsToShow, order, orderBy, categories } = this.props.attributes;

this.latestPostsRequest = getLatestPosts( postsToShow, order, orderBy, categories );

this.latestPostsRequest
.then( latestPosts => this.setState( { latestPosts } ) );
Expand All @@ -72,40 +69,41 @@ registerBlockType( 'core/latest-posts', {
}

componentWillReceiveProps( nextProps ) {
const { postsToShow: postToShowCurrent } = this.props.attributes;
const { postsToShow: postToShowNext } = nextProps.attributes;
const { setAttributes } = this.props;

if ( postToShowCurrent === postToShowNext ) {
const shouldRefetch = [ 'postsToShow', 'order', 'orderBy', 'categories' ].some(
( queryKey ) => this.props.attributes[ queryKey ] !== nextProps.attributes[ queryKey ]
);
if ( ! shouldRefetch ) {
return;
}

if ( postToShowNext >= MIN_POSTS && postToShowNext <= MAX_POSTS ) {
this.latestPostsRequest = getLatestPosts( postToShowNext );
const { postsToShow, order, orderBy, categories } = nextProps.attributes;

this.latestPostsRequest
.then( latestPosts => this.setState( { latestPosts } ) );
this.latestPostsRequest = getLatestPosts( postsToShow, order, orderBy, categories );

setAttributes( { postsToShow: postToShowNext } );
}
}

changePostsToShow( postsToShow ) {
const { setAttributes } = this.props;
setAttributes( { postsToShow: parseInt( postsToShow, 10 ) || 0 } );
this.latestPostsRequest
.then( latestPosts => this.setState( { latestPosts } ) );
}

render() {
const { latestPosts } = this.state;
const { attributes, focus, setAttributes } = this.props;
const { displayPostDate, align, layout, columns, postsToShow } = attributes;
const { displayPostDate, align, layout, columns, order, orderBy, categories, postsToShow } = attributes;

const inspectorControls = focus && (
<InspectorControls key="inspector">
<BlockDescription>
<p>{ __( 'Shows a list of your site\'s most recent posts.' ) }</p>
</BlockDescription>
<h3>{ __( 'Latest Posts Settings' ) }</h3>
<QueryPanel
{ ...{ order, orderBy } }
numberOfItems={ postsToShow }
category={ 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 }
Expand All @@ -120,14 +118,6 @@ registerBlockType( 'core/latest-posts', {
max={ Math.min( MAX_POSTS_COLUMNS, latestPosts.length ) }
/>
}
<TextControl
label={ __( 'Number of posts to show' ) }
type="number"
min={ MIN_POSTS }
max={ MAX_POSTS }
value={ postsToShow }
onChange={ ( value ) => this.changePostsToShow( value ) }
/>
</InspectorControls>
);

Expand Down
14 changes: 14 additions & 0 deletions blocks/library/latest-posts/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ function gutenberg_render_block_core_latest_posts( $attributes ) {
$recent_posts = wp_get_recent_posts( array(
'numberposts' => $attributes['postsToShow'],
'post_status' => 'publish',
'order' => $attributes['order'],
'orderby' => $attributes['orderBy'],
'category' => $attributes['categories'],
) );

$list_items_markup = '';
Expand Down Expand Up @@ -64,6 +67,9 @@ function gutenberg_render_block_core_latest_posts( $attributes ) {

register_block_type( 'core/latest-posts', array(
'attributes' => array(
'categories' => array(
'type' => 'string',
),
'postsToShow' => array(
'type' => 'number',
'default' => 5,
Expand All @@ -84,6 +90,14 @@ function gutenberg_render_block_core_latest_posts( $attributes ) {
'type' => 'string',
'default' => 'center',
),
'order' => array(
'type' => 'string',
'default' => 'desc',
),
'orderBy' => array(
'type' => 'string',
'default' => 'date',
),
),
'render_callback' => 'gutenberg_render_block_core_latest_posts',
) );
31 changes: 31 additions & 0 deletions blocks/query-panel/category-select.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* External dependencies
*/
import { get } from 'lodash';

/**
* WordPress dependencies
*/
import { buildTermsTree } from '@wordpress/utils';
import { withAPIData } from '@wordpress/components';

/**
* Internal dependencies
*/
import TermTreeSelect from '../term-tree-select';

function CategorySelect( { label, noOptionLabel, categories, selectedCategory, onChange } ) {
const termsTree = buildTermsTree( get( categories, 'data', {} ) );
return (
<TermTreeSelect
{ ...{ label, noOptionLabel, onChange, termsTree } }
selectedTerm={ selectedCategory }
/>
);
}

const applyWithAPIData = withAPIData( () => ( {
categories: '/wp/v2/categories',
} ) );

export default applyWithAPIData( CategorySelect );
89 changes: 89 additions & 0 deletions blocks/query-panel/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* External dependencies
*/
import { noop } from 'lodash';

/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import CategorySelect from './category-select';
import RangeControl from '../inspector-controls/range-control';
import SelectControl from '../inspector-controls/select-control';

const DEFAULT_MIN_ITEMS = 1;
const DEFAULT_MAX_ITEMS = 100;

export default function QueryPanel( {
category,
numberOfItems,
order,
orderBy,
maxItems = DEFAULT_MAX_ITEMS,
minItems = DEFAULT_MIN_ITEMS,
onCategoryChange,
onNumberOfItemsChange,
onOrderChange = noop,
onOrderByChange = noop,
} ) {
return [
( onOrderChange || onOrderByChange ) && (
<SelectControl
key="query-panel-select"
label={ __( 'Order by' ) }
value={ `${ orderBy }/${ order }` }
options={ [
{
label: __( 'Newest to Oldest' ),
value: 'date/desc',
},
{
label: __( 'Oldest to Newest' ),
value: 'date/asc',
},
{
/* translators: label for ordering posts by title in ascending order */
label: __( 'A → Z' ),
value: 'title/asc',
},
{
/* translators: label for ordering posts by title in descending order */
label: __( 'Z → A' ),
value: 'title/desc',
},
] }
onChange={ ( value ) => {
const [ newOrderBy, newOrder ] = value.split( '/' );
if ( newOrder !== order ) {
onOrderChange( newOrder );
}
if ( newOrderBy !== orderBy ) {
onOrderByChange( newOrderBy );
}
} }
/>
),
onCategoryChange && (
<CategorySelect
key="query-panel-category-select"
label={ __( 'Category' ) }
noOptionLabel={ __( 'All' ) }
selectedCategory={ category }
onChange={ onCategoryChange }
/> ),
onNumberOfItemsChange && (
<RangeControl
key="query-panel-range-control"
label={ __( 'Number of items' ) }
value={ numberOfItems }
onChange={ onNumberOfItemsChange }
min={ minItems }
max={ maxItems }
/>
),
];
}
32 changes: 32 additions & 0 deletions blocks/term-tree-select/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* External dependencies
*/
import { unescape as unescapeString, repeat, flatMap, compact } from 'lodash';

/**
* Internal dependencies
*/
import SelectControl from '../inspector-controls/select-control';

function getSelectOptions( terms, level = 0 ) {
return flatMap( terms, ( term ) => [
{
value: term.id,
label: repeat( '\u00A0', level * 3 ) + unescapeString( term.name ),
},
...getSelectOptions( term.children, level + 1 ),
] );
}

export default function TermTreeSelect( { termsTree, label, noOptionLabel, selectedTerm, onChange } ) {
const options = compact( [
noOptionLabel && { value: '', label: noOptionLabel },
...getSelectOptions( termsTree ),
] );
return (
<SelectControl
{ ...{ label, options, onChange } }
value={ selectedTerm }
/>
);
}
1 change: 1 addition & 0 deletions utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ export { decodeEntities };

export * from './blob-cache';
export * from './mediaupload';
export * from './terms';

export { viewPort };
27 changes: 27 additions & 0 deletions utils/terms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* External dependencies
*/
import { groupBy } from 'lodash';

/**
* Returns terms in a tree form
ª
* @param {Array} flatTerms Array of terms in flat format.
* @return {Array} Array of terms in tree format.
*/
export function buildTermsTree( flatTerms ) {
const termsByParent = groupBy( flatTerms, 'parent' );
const fillWithChildren = ( terms ) => {
return terms.map( ( term ) => {
const children = termsByParent[ term.id ];
return {
...term,
children: children && children.length ?
fillWithChildren( children ) :
[],
};
} );
};

return fillWithChildren( termsByParent[ '0' ] || [] );
}
Loading

0 comments on commit d94d742

Please sign in to comment.