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

Implements support for block type filter #47

Merged
merged 11 commits into from
Apr 7, 2023
5 changes: 5 additions & 0 deletions .changeset/lovely-doors-hammer.md
Copy link
Contributor

Choose a reason for hiding this comment

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

Not sure what happened here, but theses changes should already be in main. Maybe a rebase is needed?

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wpengine/wp-graphql-content-blocks": patch
---

Warn the user if they downloaded the source code .zip instead of the production ready .zip file
5 changes: 5 additions & 0 deletions .changeset/thick-pumpkins-roll.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wpengine/wp-graphql-content-blocks": minor
---

Add support for querying blocks per post type
2 changes: 1 addition & 1 deletion includes/Blocks/CoreImage.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
class CoreImage extends Block {

protected ?array $additional_block_attributes = array(
'className' => array(
'cssClassName' => array(
theodesp marked this conversation as resolved.
Show resolved Hide resolved
'type' => 'string',
'selector' => 'figure',
'source' => 'attribute',
Expand Down
28 changes: 20 additions & 8 deletions includes/Data/ContentBlocksResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ final class ContentBlocksResolver {
*
* @param mixed $node The node we are resolving.
* @param array $args GraphQL query args to pass to the connection resolver.
* @param array $allowed_block_names The list of allowed block names to filter.
*/
public static function resolve_content_blocks( $node, $args ) {
public static function resolve_content_blocks( $node, $args, $allowed_block_names = array() ) {
$content = null;
if ( $node instanceof Post ) {

Expand Down Expand Up @@ -49,8 +50,7 @@ public static function resolve_content_blocks( $node, $args ) {
if ( empty( $parsed_blocks ) ) {
return array();
}

// Filter out blocks that have no name
// 1st Level filtering of blocks that have no name
$parsed_blocks = array_filter(
$parsed_blocks,
function ( $parsed_block ) {
Expand All @@ -59,17 +59,29 @@ function ( $parsed_block ) {
ARRAY_FILTER_USE_BOTH
);

// 1st Level assigning of unique id's
$parsed_blocks = array_map(
function ( $parsed_block ) {
$parsed_block['clientId'] = uniqid();
return $parsed_block;
},
$parsed_blocks
);

// Flatten block list here if requested or if 'flat' value is not selected (default)
if ( !isset( $args['flat'] ) || 'true' == $args['flat'] ) {
return self::flatten_block_list( $parsed_blocks );
if ( ! isset( $args['flat'] ) || 'true' == $args['flat'] ) {
$parsed_blocks = self::flatten_block_list( $parsed_blocks );
}

// Final level of filtering out blocks not in the allowed list
if ( ! empty( $allowed_block_names ) ) {
$parsed_blocks = array_filter(
$parsed_blocks,
function ( $parsed_block ) use ( $allowed_block_names ) {
return isset( $parsed_block['blockName'] ) && in_array( $parsed_block['blockName'], $allowed_block_names, TRUE);
},
ARRAY_FILTER_USE_BOTH
);
}
return $parsed_blocks;
}
Expand All @@ -89,12 +101,12 @@ private static function flatten_block_list( $blocks ) {
* Flattens a block and it's inner blocks into a single while attaching unique clientId's
*/
private static function flatten_inner_blocks( $block ) {
$result = array();
$result = array();
$block['clientId'] = isset( $block['clientId'] ) ? $block['clientId'] : uniqid();
array_push( $result, $block );
foreach ( $block['innerBlocks'] as $child ) {
$child['parentClientId'] = $block['clientId'];
$result = array_merge( $result, self::flatten_inner_blocks( $child ) );
$result = array_merge( $result, self::flatten_inner_blocks( $child ) );
}
return $result;
}
Expand Down
149 changes: 54 additions & 95 deletions includes/Registry/Registry.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
use WPGraphQL\ContentBlocks\Interfaces\OnInit;
use WPGraphQL\ContentBlocks\Type\Scalar\Scalar;
use WPGraphQL\ContentBlocks\Type\InterfaceType\EditorBlockInterface;
use WPGraphQL\ContentBlocks\Type\InterfaceType\PostTypeBlockInterface;
use WPGraphQL\ContentBlocks\Type\ObjectType\UnknownBlock;
use WPGraphQL\ContentBlocks\Utilities\WPHelpers;
use WPGraphQL\Registry\TypeRegistry;
use WPGraphQL\Utils\Utils;

Expand All @@ -18,7 +21,6 @@
*/
final class Registry implements OnInit {


/**
* @var TypeRegistry
*/
Expand Down Expand Up @@ -51,56 +53,68 @@ public function __construct( TypeRegistry $type_registry, $block_type_registry )
* @throws Exception
*/
public function OnInit() {
EditorBlockInterface::register_type( $this->type_registry );
( new Scalar() )->OnInit();
$this->pass_blocks_to_context();
$this->register_interface_types();
$this->register_scalar_types();
$this->register_block_types();
$this->register_unknown_block();
$this->add_block_fields_to_schema();
UnknownBlock::register_type();
}

/**
* Registers the UnknownBlock in the instance a block is not defined
* in the registry.
*
*/
public function register_unknown_block() {
register_graphql_object_type(
'UnknownBlock',
array(
'description' => __( 'A block used for resolving blocks not found in the WordPress registry', 'wp-graphql-content-blocks' ),
'interfaces' => array( 'EditorBlock' ),
'eagerlyLoadType' => true,
'fields' => array(
'name' => array(
'type' => 'String',
'description' => __( 'The name of the block', 'wp-graphql-content-blocks' ),
'resolve' => function () {
return 'UnknownBlock';
}
),
),
)
);
}

/**
* This adds the WP Block Registry to AppContext
* Register Interface types to the GraphQL Schema
*
* @return void
*/
public function pass_blocks_to_context() {
add_filter( 'graphql_app_context_config', array( $this, 'load_registered_editor_blocks' ) );
protected function register_interface_types() {
Copy link
Member Author

Choose a reason for hiding this comment

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

All logic is contained in this method.

// First register the NodeWithEditorBlocks interface by default
EditorBlockInterface::register_type( $this->type_registry );

// Then try to register both NodeWithEditorBlocks and NodeWith[PostType]Blocks per post type
$supported_post_types = WPHelpers::get_supported_post_types();
if ( empty( $supported_post_types ) ) {
return;
}
register_graphql_interfaces_to_types( array( 'NodeWithEditorBlocks' ), $supported_post_types );
$post_id = -1;
// For each Post type
foreach ( $supported_post_types as $post_type ) {
// Normalize the post type name
$type_name = strtolower( $post_type );

// retrieve a block_editor_context for the current post type
$block_editor_context = WPHelpers::get_block_editor_context( $type_name, $post_id-- );

// Fetch the list of allowed blocks for the current post type
$supported_blocks_for_post_type = get_allowed_block_types( $block_editor_context );

// If there is a list of supported blocks for current post type
if ( is_array( $supported_blocks_for_post_type ) ) {
// Register an [PostType]Block type for the blocks using that post type
PostTypeBlockInterface::register_type( $type_name, $supported_blocks_for_post_type, $this->type_registry );

// Normalize the list of supported block names
$block_names = array_map(
function( $supported_block ) {
$block_name = preg_replace( '/\//', '', lcfirst( ucwords( $supported_block, '/' ) ) );
return \WPGraphQL\Utils\Utils::format_type_name( $block_name );
},
$supported_blocks_for_post_type
);
// Register [PostType]Block type to allowed block names
register_graphql_interfaces_to_types( array( $type_name . 'Block' ), $block_names );

// Register the `NodeWith[PostType]Blocks` Interface to the post type
register_graphql_interfaces_to_types( array( 'NodeWith' . $post_type . 'Blocks' ), array( $type_name ) );
}
}//end foreach
}

/**
* Loads registered_blocks into the app context config
* Register Scalar types to the GraphQL Schema
*
* @return object
* @return void
*/
public function load_registered_editor_blocks( $config ) {
$config['registered_editor_blocks'] = $this->registered_blocks;
return $config;
protected function register_scalar_types() {
( new Scalar() )->OnInit();
}

/**
Expand All @@ -109,7 +123,7 @@ public function load_registered_editor_blocks( $config ) {
* @return void
*/
protected function register_block_types() {
$this->registered_blocks = $this->block_type_registry->get_all_registered();
$this->registered_blocks = $this->block_type_registry->get_all_registered();

if ( empty( $this->registered_blocks ) || ! is_array( $this->registered_blocks ) ) {
return;
Expand Down Expand Up @@ -145,59 +159,4 @@ protected function register_block_type( WP_Block_Type $block ) {
new Block( $block, $this );
}
}

/**
* Adds Block Fields to the WPGraphQL Schema
*
* @return void
*/
public function add_block_fields_to_schema() {
$supported_post_types = $this->get_supported_post_types();
// If there are no supported post types, early return
if ( empty( $supported_post_types ) ) {
return;
}

// Register the `NodeWithEditorBlocks` Interface to the supported post types
register_graphql_interfaces_to_types( array( 'NodeWithEditorBlocks' ), $supported_post_types );
}

/**
* Gets Block Editor supported post types
*
* @return array<string>
*/
public function get_supported_post_types() {
$supported_post_types = array();
// Get Post Types that are set to Show in GraphQL and Show in REST
// If it doesn't show in REST, it's not block-editor enabled
$block_editor_post_types = get_post_types(
array(
'show_in_graphql' => true,
'show_in_rest' => true,
),
'objects'
);

if ( empty( $block_editor_post_types ) || ! is_array( $block_editor_post_types ) ) {
return;
}

// Iterate over the post types
foreach ( $block_editor_post_types as $block_editor_post_type ) {

// If the post type doesn't support the editor, it's not block-editor enabled
if ( ! post_type_supports( $block_editor_post_type->name, 'editor' ) ) {
continue;
}

if ( ! isset( $block_editor_post_type->graphql_single_name ) ) {
continue;
}

$supported_post_types[] = Utils::format_type_name( $block_editor_post_type->graphql_single_name );
}

return $supported_post_types;
}
}
16 changes: 7 additions & 9 deletions includes/Type/InterfaceType/EditorBlockInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace WPGraphQL\ContentBlocks\Type\InterfaceType;

use Exception;
use GraphQL\Type\Definition\ResolveInfo;
use WP_Block_Type_Registry;
use WPGraphQL\AppContext;
use WPGraphQL\Registry\TypeRegistry;
use WPGraphQL\Utils\Utils;
Expand All @@ -15,16 +15,14 @@
* @package WPGraphQL\ContentBlocks
*/
final class EditorBlockInterface {


/**
* @param array $block The block being resolved
* @param AppContext $context The AppContext
* @param array $block The block being resolved.
* @param AppContext $context The AppContext.
*
* @return mixed WP_Block_Type|null
*/
public static function get_block( array $block, AppContext $context ) {
$registered_blocks = $context->config['registered_editor_blocks'];
$registered_blocks = WP_Block_Type_Registry::get_instance()->get_all_registered();

if ( ! isset( $block['blockName'] ) ) {
return null;
Expand All @@ -38,7 +36,7 @@ public static function get_block( array $block, AppContext $context ) {
}

/**
* @param TypeRegistry $type_registry
* @param WPGraphQL\Registry\TypeRegistry $type_registry The TypeRegistry.
*
* @throws Exception
*/
Expand Down Expand Up @@ -74,14 +72,14 @@ public static function register_type( TypeRegistry $type_registry ) {
'eagerlyLoadType' => true,
'description' => __( 'Blocks that can be edited to create content and layouts', 'wp-graphql-content-blocks' ),
'fields' => array(
'clientId' => array(
'clientId' => array(
'type' => 'String',
'description' => __( 'The id of the Block', 'wp-graphql-content-blocks' ),
'resolve' => function ( $block ) {
return isset( $block['clientId'] ) ? $block['clientId'] : uniqid();
},
),
'parentClientId' => array(
'parentClientId' => array(
'type' => 'String',
'description' => __( 'The parent id of the Block', 'wp-graphql-content-blocks' ),
'resolve' => function ( $block ) {
Expand Down