Skip to content

Commit

Permalink
Block Library: Add Query block. (#22199)
Browse files Browse the repository at this point in the history
* Lib: Support forcing non dynamic renders in WP_Block.

* Block Editor: Support live block previews in BlockPreview.

* Block Library: Add query block.

* Query Block: Add query toolbar with per_page control.

* Components: Fix toolbar CSS selectors.

* Query Block: Unfocus posts on Query block blur.

* Query Block: Add pagination on the edit side.

* Query Block: Add pagination on the front end side.

* Block Library: Break Query block into multiple sub-blocks.

* Query Block: Support Post Content blocks.

* Query Block: Add translations and icon.

* Update packages/block-library/src/query-pagination/index.php

Co-authored-by: Andrew Duthie <andrew@andrewduthie.com>

* Update packages/block-library/src/query-pagination/index.php

Co-authored-by: Andrew Duthie <andrew@andrewduthie.com>

* Lib: Wrap the new block render parameter in an options array.

* E2E Tests: Add fixtures.

* Query Block: Refactor variable names.

Co-authored-by: Andrew Duthie <andrew@andrewduthie.com>
  • Loading branch information
epiqueras and aduth authored May 13, 2020
1 parent daf51e9 commit b58eb66
Show file tree
Hide file tree
Showing 35 changed files with 675 additions and 12 deletions.
3 changes: 3 additions & 0 deletions lib/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ function gutenberg_reregister_core_block_types() {
'post-tags.php' => 'core/post-tags',
'site-title.php' => 'core/site-title',
'template-part.php' => 'core/template-part',
'query.php' => 'core/query',
'query-loop.php' => 'core/query-loop',
'query-pagination.php' => 'core/query-pagination',
)
);
}
Expand Down
30 changes: 22 additions & 8 deletions lib/class-wp-block.php
Original file line number Diff line number Diff line change
Expand Up @@ -169,19 +169,33 @@ public function __get( $name ) {
/**
* Generates the render output for the block.
*
* @param array $options {
* Optional options object.
*
* @type bool $dynamic Defaults to 'true'. Optionally set to false to avoid using the block's render_callback.
* }
*
* @return string Rendered block output.
*/
public function render() {
public function render( $options = array() ) {
global $post;

$is_dynamic = $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
$options = array_replace(
array(
'dynamic' => true,
),
$options
);

$is_dynamic = $options['dynamic'] && $this->name && null !== $this->block_type && $this->block_type->is_dynamic();
$block_content = '';

$index = 0;
foreach ( $this->inner_content as $chunk ) {
$block_content .= is_string( $chunk ) ?
$chunk :
$this->inner_blocks[ $index++ ]->render();
if ( ! $options['dynamic'] || empty( $this->block_type->skip_inner_blocks ) ) {
$index = 0;
foreach ( $this->inner_content as $chunk ) {
$block_content .= is_string( $chunk ) ?
$chunk :
$this->inner_blocks[ $index++ ]->render();
}
}

if ( $is_dynamic ) {
Expand Down
15 changes: 11 additions & 4 deletions packages/block-editor/src/components/block-preview/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import { memo, useMemo } from '@wordpress/element';
* Internal dependencies
*/
import BlockEditorProvider from '../provider';
import LiveBlockPreview from './live';
import AutoHeightBlockPreview from './auto';

export function BlockPreview( {
blocks,
__experimentalPadding = 0,
viewportWidth = 700,
__experimentalLive = false,
__experimentalOnClick,
} ) {
const settings = useSelect( ( select ) =>
select( 'core/block-editor' ).getSettings()
Expand All @@ -29,10 +32,14 @@ export function BlockPreview( {
}
return (
<BlockEditorProvider value={ renderedBlocks } settings={ settings }>
<AutoHeightBlockPreview
viewportWidth={ viewportWidth }
__experimentalPadding={ __experimentalPadding }
/>
{ __experimentalLive ? (
<LiveBlockPreview onClick={ __experimentalOnClick } />
) : (
<AutoHeightBlockPreview
viewportWidth={ viewportWidth }
__experimentalPadding={ __experimentalPadding }
/>
) }
</BlockEditorProvider>
);
}
Expand Down
24 changes: 24 additions & 0 deletions packages/block-editor/src/components/block-preview/live.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* WordPress dependencies
*/
import { Disabled } from '@wordpress/components';

/**
* Internal dependencies
*/
import BlockList from '../block-list';

export default function LiveBlockPreview( { onClick } ) {
return (
<div
tabIndex={ 0 }
role="button"
onClick={ onClick }
onKeyPress={ onClick }
>
<Disabled>
<BlockList />
</Disabled>
</div>
);
}
6 changes: 6 additions & 0 deletions packages/block-library/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ import * as socialLink from './social-link';
// Full Site Editing Blocks
import * as siteTitle from './site-title';
import * as templatePart from './template-part';
import * as query from './query';
import * as queryLoop from './query-loop';
import * as queryPagination from './query-pagination';
import * as postTitle from './post-title';
import * as postContent from './post-content';
import * as postAuthor from './post-author';
Expand Down Expand Up @@ -197,6 +200,9 @@ export const __experimentalRegisterExperimentalCoreBlocks =
? [
siteTitle,
templatePart,
query,
queryLoop,
queryPagination,
postTitle,
postContent,
postAuthor,
Expand Down
5 changes: 5 additions & 0 deletions packages/block-library/src/query-loop/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "core/query-loop",
"category": "layout",
"context": [ "queryId", "query" ]
}
63 changes: 63 additions & 0 deletions packages/block-library/src/query-loop/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* WordPress dependencies
*/
import { useState, useMemo } from '@wordpress/element';
import { useSelect } from '@wordpress/data';
import {
BlockContextProvider,
InnerBlocks,
BlockPreview,
} from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { useQueryContext } from '../query';

const TEMPLATE = [ [ 'core/post-title' ], [ 'core/post-content' ] ];
export default function QueryLoopEdit( { clientId, context: { query } } ) {
const [ { page } ] = useQueryContext();
const [ activeBlockContext, setActiveBlockContext ] = useState();

const { posts, blocks } = useSelect(
( select ) => ( {
posts: select( 'core' ).getEntityRecords( 'postType', 'post', {
...query,
offset: query.per_page * ( page - 1 ) + query.offset,
page,
} ),
blocks: select( 'core/block-editor' ).getBlocks( clientId ),
} ),
[ query, page, clientId ]
);

const blockContexts = useMemo(
() =>
posts?.map( ( post ) => ( {
postType: post.type,
postId: post.id,
} ) ),
[ posts ]
);
return blockContexts
? blockContexts.map( ( blockContext ) => (
<BlockContextProvider
key={ blockContext.postId }
value={ blockContext }
>
{ blockContext ===
( activeBlockContext || blockContexts[ 0 ] ) ? (
<InnerBlocks template={ TEMPLATE } />
) : (
<BlockPreview
blocks={ blocks }
__experimentalLive
__experimentalOnClick={ () =>
setActiveBlockContext( blockContext )
}
/>
) }
</BlockContextProvider>
) )
: null;
}
28 changes: 28 additions & 0 deletions packages/block-library/src/query-loop/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';
import { loop } from '@wordpress/icons';

/**
* Internal dependencies
*/
import metadata from './block.json';
import edit from './edit';
import save from './save';

const { name } = metadata;
export { metadata, name };

export const settings = {
title: __( 'Query Loop' ),
icon: loop,
parent: [ 'core/query' ],
supports: {
inserter: false,
reusable: false,
html: false,
},
edit,
save,
};
58 changes: 58 additions & 0 deletions packages/block-library/src/query-loop/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php
/**
* Server-side rendering of the `core/query-loop` block.
*
* @package WordPress
*/

/**
* Renders the `core/query-loop` block on the server.
*
* @param array $attributes Block attributes.
* @param string $content Block default content.
* @param WP_Block $block Block instance.
*
* @return string Returns the output of the query, structured using the layout defined by the block's inner blocks.
*/
function render_block_core_query_loop( $attributes, $content, $block ) {
$page_key = 'query-' . $block->context['queryId'] . '-page';
$page = empty( $_GET[ $page_key ] ) ? 1 : filter_var( $_GET[ $page_key ], FILTER_VALIDATE_INT );
$posts = get_posts(
array(
'post_type' => 'post',
'posts_per_page' => $block->context['query']['per_page'],
'offset' => $block->context['query']['per_page'] * ( $page - 1 ) + $block->context['query']['offset'],
)
);

$content = '';
foreach ( $posts as $post ) {
$content .= (
new WP_Block(
$block->parsed_block,
array_merge(
$block->available_context ? $block->available_context : array(),
array(
'postType' => $post->post_type,
'postId' => $post->ID,
)
)
)
)->render( array( 'dynamic' => false ) );
}
return $content;
}

/**
* Registers the `core/query-loop` block on the server.
*/
function register_block_core_query_loop() {
register_block_type_from_metadata(
__DIR__ . '/query-loop',
array(
'render_callback' => 'render_block_core_query_loop',
'skip_inner_blocks' => true,
)
);
}
add_action( 'init', 'register_block_core_query_loop' );
8 changes: 8 additions & 0 deletions packages/block-library/src/query-loop/save.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* WordPress dependencies
*/
import { InnerBlocks } from '@wordpress/block-editor';

export default function QueryLoopSave() {
return <InnerBlocks.Content />;
}
5 changes: 5 additions & 0 deletions packages/block-library/src/query-pagination/block.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"name": "core/query-pagination",
"category": "layout",
"context": [ "queryId", "query" ]
}
52 changes: 52 additions & 0 deletions packages/block-library/src/query-pagination/edit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/**
* WordPress dependencies
*/
import { Button, ButtonGroup } from '@wordpress/components';
import { chevronLeft, chevronRight } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import { useQueryContext } from '../query';

export default function QueryPaginationEdit( {
context: {
query: { pages },
},
} ) {
const [ { page }, setQueryContext ] = useQueryContext();

let previous;
if ( page > 1 ) {
previous = (
<Button
isPrimary
icon={ chevronLeft }
onClick={ () => setQueryContext( { page: page - 1 } ) }
>
{ __( 'Previous' ) }
</Button>
);
}
let next;
if ( page < pages ) {
next = (
<Button
isPrimary
icon={ chevronRight }
onClick={ () => setQueryContext( { page: page + 1 } ) }
>
{ __( 'Next' ) }
</Button>
);
}
return previous || next ? (
<ButtonGroup>
{ previous }
{ next }
</ButtonGroup>
) : (
__( 'No pages to paginate.' )
);
}
24 changes: 24 additions & 0 deletions packages/block-library/src/query-pagination/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import metadata from './block.json';
import edit from './edit';

const { name } = metadata;
export { metadata, name };

export const settings = {
title: __( 'Query Pagination' ),
parent: [ 'core/query' ],
supports: {
inserter: false,
reusable: false,
html: false,
},
edit,
};
Loading

0 comments on commit b58eb66

Please sign in to comment.