Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add "Latest Posts" Block #870

Merged
merged 18 commits into from Jun 8, 2017
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions blocks/api/categories.js
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
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
@@ -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;
}

75 changes: 75 additions & 0 deletions blocks/library/latest-posts/index.js
@@ -0,0 +1,75 @@
/**
* 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: [],
latestPostsRequest: getLatestPosts( poststoshow ),
};

this.state.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() {
const { latestPostsRequest } = this.state;

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

save() {
return null;
},
} );
51 changes: 51 additions & 0 deletions blocks/library/latest-posts/index.php
@@ -0,0 +1,51 @@
<?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 = $attributes['poststoshow'];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there is no sanitization or validation of block attributes (yet), it should probably be done here, ensuring it is a number and that it is greater than 0, but less than (maybe) 100.

See also #886 (comment)

}

$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
@@ -0,0 +1,2 @@
<!-- wp:core/latestposts poststoshow="5" --><!-- /wp:core/latestposts -->

9 changes: 9 additions & 0 deletions blocks/test/fixtures/core-latestposts.json
@@ -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
@@ -0,0 +1,2 @@
<!-- wp:core/latestposts poststoshow="5" --><!-- /wp:core/latestposts -->

2 changes: 2 additions & 0 deletions gutenberg.php
Expand Up @@ -9,6 +9,8 @@
* @package gutenberg
*/

define( 'GUTENBERG__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These defines are duplicating code already in place elsewhere:

/**
* Retrieves the root plugin path.
*
* @return string Root path to the gutenberg plugin.
*
* @since 0.1.0
*/
function gutenberg_dir_path() {
return plugin_dir_path( dirname( __FILE__ ) );
}

The GUTENBERG__ (double underscore) convention is unique to the constants introduced here; others in the codebase do not use this convention. It seems unnecessary to me.

I don't have a preference on whether this is done as a function or constants (the function is pretty fast), but it needs to be consistent in approach and naming.

Also, gutenberg.php should contain the bare minimum necessary to initialize the plugin, because it is going to be rewritten during the build process. These defines should probably happen in a new lib/constants.php or similar.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I didn't notice that, my bad.

In a new PR, I'll fix those things.

Thanks!


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
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' );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are a few other issues here, not least that npm run package-plugin is currently broken because this file was not added to the plugin zip package. I'll open a PR to try to fix.