diff --git a/.changeset/calm-socks-battle.md b/.changeset/calm-socks-battle.md new file mode 100644 index 00000000..e71a4bbd --- /dev/null +++ b/.changeset/calm-socks-battle.md @@ -0,0 +1,40 @@ +--- +"@wpengine/wp-graphql-content-blocks": minor +--- + +Adds support for resolving and returning related term items as a `terms` connection for the CorePostTerms block along with `taxonomy` connection. +Adds support for resolving and returning the `prefix` and `suffix` items within the correspondent fields of the CorePostTerms block. + +```graphql +query TestPostTerms($uri: String! = "test-terms") { + nodeByUri(uri: $uri) { + id + uri + ... on NodeWithPostEditorBlocks { + editorBlocks { + __typename + ... on CorePostTerms { + prefix + suffix + taxonomy { + __typename + node { + __typename + id + name + } + } + terms { + __typename + nodes { + __typename + id + name + } + } + } + } + } + } +} +``` \ No newline at end of file diff --git a/includes/Blocks/CorePostTerms.php b/includes/Blocks/CorePostTerms.php new file mode 100644 index 00000000..86db4293 --- /dev/null +++ b/includes/Blocks/CorePostTerms.php @@ -0,0 +1,104 @@ +register_fields(); + $this->register_connections(); + } + + /** + * Registers custom fields for the block. + */ + private function register_fields(): void { + register_graphql_fields( + $this->type_name, + [ + 'prefix' => [ + 'type' => 'String', + 'description' => __( 'Prefix to display before the post terms', 'wp-graphql-content-blocks' ), + 'resolve' => static fn ( $block ) => isset( $block['attrs']['prefix'] ) ? (string) $block['attrs']['prefix'] : null, + ], + 'suffix' => [ + 'type' => 'String', + 'description' => __( 'Suffix to display after the post terms', 'wp-graphql-content-blocks' ), + 'resolve' => static fn ( $block ) => isset( $block['attrs']['suffix'] ) ? (string) $block['attrs']['suffix'] : null, + ], + ] + ); + } + + /** + * Registers a list of terms field for the block. + * + * @return void + * @throws \Exception + */ + protected function register_connections() { + // Register connection to terms. + register_graphql_connection( + [ + 'fromType' => $this->type_name, + 'toType' => 'TermNode', + 'fromFieldName' => 'terms', + 'resolve' => static function ( $block, array $args, AppContext $context, $info ) { + $taxonomy = $block['attrs']['term'] ?? null; + if ( empty( $taxonomy ) ) { + return null; + } + + $post_id = get_the_ID(); + if ( ! $post_id ) { + return null; + } + + $args['where']['objectIds'] = $post_id; + $resolver = new TermObjectConnectionResolver( $block, $args, $context, $info, $taxonomy ); + + return $resolver->get_connection(); + }, + ] + ); + + // Register connection to the taxonomy. + register_graphql_connection( + [ + 'fromType' => $this->type_name, + 'toType' => 'Taxonomy', + 'fromFieldName' => 'taxonomy', + 'oneToOne' => true, + 'resolve' => static function ( $block, array $args, AppContext $context, $info ) { + $taxonomy = $block['attrs']['term'] ?? null; + if ( empty( $taxonomy ) ) { + return null; + } + + $resolver = new TaxonomyConnectionResolver( $block, $args, $context, $info ); + $resolver->set_query_arg( 'name', $taxonomy ); + + return $resolver->one_to_one()->get_connection(); + }, + ] + ); + } +} diff --git a/tests/unit/CorePostTermsTest.php b/tests/unit/CorePostTermsTest.php new file mode 100644 index 00000000..74411c0c --- /dev/null +++ b/tests/unit/CorePostTermsTest.php @@ -0,0 +1,132 @@ +post_id = wp_insert_post( + [ + 'post_title' => 'Test Terms', + 'post_name' => 'test-terms', + 'post_content' => '', + 'post_status' => 'publish', + ] + ); + + $this->post_uri = get_permalink($this->post_id); + + \WPGraphQL::clear_schema(); + } + + public function tearDown(): void { + wp_delete_post($this->post_id, true); + \WPGraphQL::clear_schema(); + + parent::tearDown(); + } + + /** + * Get the updated GraphQL query for the CorePostTerms block. + */ + public function query(): string { + return ' + query TestPostTerms($uri: String! = "test-terms") { + nodeByUri(uri: $uri) { + id + uri + ... on NodeWithPostEditorBlocks { + editorBlocks { + __typename + ... on CorePostTerms { + prefix + suffix + taxonomy { + __typename + node { + __typename + id + name + } + } + terms { + __typename + nodes { + __typename + id + name + } + } + } + } + } + } + } + '; + } + + /** + * Test that the CorePostTerms block retrieves attributes, taxonomy, and terms correctly. + */ + public function test_retrieve_core_post_terms(): void { + $block_content = ''; + + wp_update_post( + [ + 'ID' => $this->post_id, + 'post_content' => $block_content, + ] + ); + + $variables = [ 'uri' => 'test-terms' ]; + $query = $this->query(); + $actual = graphql(compact('query', 'variables')); + + $node = $actual['data']['nodeByUri']; + + $this->assertArrayHasKey('editorBlocks', $node); + $this->assertCount(1, $node['editorBlocks']); + + $block = $node['editorBlocks'][0]; + + $this->assertEquals('CorePostTerms', $block['__typename']); + $this->assertEquals('Before', $block['prefix']); + $this->assertEquals('After', $block['suffix']); + + $this->assertArrayHasKey('taxonomy', $block); + $this->assertArrayHasKey('node', $block['taxonomy']); + $this->assertArrayHasKey('__typename', $block['taxonomy']['node']); + $this->assertArrayHasKey('id', $block['taxonomy']['node']); + $this->assertArrayHasKey('name', $block['taxonomy']['node']); + + $this->assertArrayHasKey('terms', $block); + $this->assertArrayHasKey('nodes', $block['terms']); + $this->assertIsArray($block['terms']['nodes']); + $this->assertEquals('CorePostTermsToTermNodeConnection', $block['terms']['__typename']); + $this->assertEquals('Category', $block['terms']['nodes'][0]['__typename']); + + $this->assertArrayHasKey('taxonomy', $block); + $this->assertArrayHasKey('node', $block['taxonomy']); + $this->assertIsArray($block['taxonomy']['node']); + $this->assertEquals('CorePostTermsToTaxonomyConnectionEdge', $block['taxonomy']['__typename']); + $this->assertEquals('category', $block['taxonomy']['node']['name']); + + + } +}