Skip to content

Commit

Permalink
Add "Latest Posts" Block (#870)
Browse files Browse the repository at this point in the history
* Add initial scaffolding for REST API Latest Posts block

* Load 5 latest posts into unordered list

* Refactor to `latest-posts` instead of `rest-api-latest-posts`

* Move data fetchers to data.js file

Props @mtias for the suggestion

* Refactor edit() to render a React component

Fixes the issue of having to use `attributes` to store the latest posts and is also nicer.

* Add poststoshow attribute with a default value 5

* Add server-side rendering

I also had to rename the block from core/latest-posts to
core/latestposts since I think there's a bug in the server-side matcher
-- it ignores block comments with hyphens: #882

* Use defaultProps to initialize postsToShow

* Add various fixes according to the review

* Fix linting errors

* Rebase and fix eslint/WP coding standards

* Add fn which loads server-side rendering of blocks

This was lost in last rebase

* Avoid small render* functions and put the whole rendering in render

* Add full post content fixture

* Abort the latest posts query if component is unmounted before response

* Import __ from i18n instead of using wp.i18n.__

* Use class prop instead of React state to store posts request

* Add basic posts to show attribute validation
  • Loading branch information
lamosty committed Jun 8, 2017
1 parent e6e7f14 commit e94c30d
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 0 deletions.
1 change: 1 addition & 0 deletions blocks/api/categories.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const categories = [
{ slug: 'formatting', title: __( 'Formatting' ) },
{ slug: 'embed', title: __( 'Embed' ) },
{ slug: 'layout', title: __( 'Layout Blocks' ) },
{ slug: 'rest-api', title: __( 'REST API Blocks' ) },
];

/**
Expand Down
1 change: 1 addition & 0 deletions blocks/library/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ import './pullquote';
import './table';
import './preformatted';
import './code';
import './latest-posts';
19 changes: 19 additions & 0 deletions blocks/library/latest-posts/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Returns a Promise with the latest posts or an error on failure.
*
* @param {Number} postsToShow Number of posts to display.
*
* @returns {wp.api.collections.Posts} Returns a Promise with the latest posts.
*/
export function getLatestPosts( postsToShow = 5 ) {
const postsCollection = new wp.api.collections.Posts();

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

return posts;
}

74 changes: 74 additions & 0 deletions blocks/library/latest-posts/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* WordPress dependencies
*/
import { Placeholder } from 'components';
import { __ } from 'i18n';

/**
* Internal dependencies
*/
import { registerBlockType } from '../../api';
import { getLatestPosts } from './data.js';

registerBlockType( 'core/latestposts', {
title: __( 'Latest Posts' ),

icon: 'list-view',

category: 'rest-api',

defaultAttributes: {
poststoshow: 5,
},

edit: class extends wp.element.Component {
constructor() {
super( ...arguments );

const { poststoshow } = this.props.attributes;

this.state = {
latestPosts: [],
};

this.latestPostsRequest = getLatestPosts( poststoshow );

this.latestPostsRequest
.then( latestPosts => this.setState( { latestPosts } ) );
}

render() {
const { latestPosts } = this.state;

if ( ! latestPosts.length ) {
return (
<Placeholder
icon="update"
label={ __( 'Loading latest posts, please wait' ) }
>
</Placeholder>
);
}

return (
<div className="blocks-latest-posts">
<ul>
{ latestPosts.map( ( post, i ) =>
<li key={ i }><a href={ post.link }>{ post.title.rendered }</a></li>
) }
</ul>
</div>
);
}
},

componentWillUnmount() {
if ( this.latestPostsRequest.state() === 'pending' ) {
this.latestPostsRequest.abort();
}
},

save() {
return null;
},
} );
60 changes: 60 additions & 0 deletions blocks/library/latest-posts/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php
/**
* Server-side rendering of the `core/latest-posts` block.
*
* @package gutenberg
*/

/**
* Renders the `core/latest-posts` block on server.
*
* @param array $attributes The block attributes.
*
* @return string Returns the post content with latest posts added.
*/
function gutenberg_block_core_latest_posts( $attributes ) {
$posts_to_show = 5;

if ( array_key_exists( 'poststoshow', $attributes ) ) {
$posts_to_show_attr = $attributes['poststoshow'];

// Basic attribute validation.
if (
is_numeric( $posts_to_show_attr ) &&
$posts_to_show_attr > 0 &&
$posts_to_show_attr < 100
) {
$posts_to_show = $attributes['poststoshow'];
}
}

$recent_posts = wp_get_recent_posts( array(
'numberposts' => $posts_to_show,
'post_status' => 'publish',
) );

$posts_content = '';

foreach ( $recent_posts as $post ) {
$post_id = $post['ID'];
$post_permalink = get_permalink( $post_id );
$post_title = get_the_title( $post_id );

$posts_content .= "<li><a href='{$post_permalink}'>{$post_title}</a></li>\n";
}

$block_content = <<<CONTENT
<div class="blocks-latest-posts">
<ul>
{$posts_content}
</ul>
</div>
CONTENT;

return $block_content;
}

register_block_type( 'core/latestposts', array(
'render' => 'gutenberg_block_core_latest_posts',
) );
2 changes: 2 additions & 0 deletions blocks/test/fixtures/core-latestposts.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- wp:core/latestposts poststoshow="5" --><!-- /wp:core/latestposts -->

9 changes: 9 additions & 0 deletions blocks/test/fixtures/core-latestposts.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[
{
"uid": "_uid_0",
"name": "core/latestposts",
"attributes": {
"poststoshow": 5
}
}
]
2 changes: 2 additions & 0 deletions blocks/test/fixtures/core-latestposts.serialized.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<!-- wp:core/latestposts poststoshow="5" --><!-- /wp:core/latestposts -->

2 changes: 2 additions & 0 deletions gutenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
* @package gutenberg
*/

define( 'GUTENBERG__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );

require_once dirname( __FILE__ ) . '/lib/blocks.php';
require_once dirname( __FILE__ ) . '/lib/client-assets.php';
require_once dirname( __FILE__ ) . '/lib/i18n.php';
Expand Down
11 changes: 11 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
die( 'Silence is golden.' );
}

define( 'GUTENBERG__BLOCKS_LIBRARY_DIR', GUTENBERG__PLUGIN_DIR . 'blocks/library' );

$wp_registered_blocks = array();

/**
Expand Down Expand Up @@ -128,3 +130,12 @@ function do_blocks( $content ) {
return $new_content;
}
add_filter( 'the_content', 'do_blocks', 10 ); // BEFORE do_shortcode().

/**
* Loads the server-side rendering of blocks. If your block supports
* server-side rendering, add it here.
*/
function gutenberg_load_blocks_server_side_rendering() {
require_once GUTENBERG__BLOCKS_LIBRARY_DIR . '/latest-posts/index.php';
}
add_action( 'init', 'gutenberg_load_blocks_server_side_rendering' );

0 comments on commit e94c30d

Please sign in to comment.