Skip to content

Commit

Permalink
Allow contents of Paragraph to be "connected" to a meta custom field (#…
Browse files Browse the repository at this point in the history
…53247)

* Add custom fields experimental setting

* Add connections experimental setting, block inspector control and block attributes

* Add "connections" block attribute and get the meta field

* Get rid of a phpcs warning

* Update attribute acces and source definition

Changed the attribute access from `$block_type->attributes` to `$block['attrs']`. Also updated attribute 'source' value from 'meta' to 'meta_fields'. These changes have been applied in both `blocks.php` and block attributes declaration in `block.json`.

* Updated the 'connections' property to include 'attributes'

* Add `attributes` to TextControl value

* Add `attributes` to TextControl value

* Wrap the PHP code in experimental flag

* Update parens

* Return early if there is no support for connections

* Updated block type checks

Rearranged the block type checks. Now, the code first checks if a given block is in the accepted types list (Paragraph and Image) and then it checks if the block type is null. This is a slight revamp of the existing checks for block support and block type acceptance.

* Updated experimental blocks logic

- Removed unused test functions.
- Update the comment above the tag name query in the `custom-sources` to clarify future improvements for
supporting more block types.

* Add a comment in meta.php

* Update comment

* Clear the paragraph if meta value is cleared

* Use placeholders instead of content

* Update names of HTML processor instances in meta.php

* Add extra comments

* Rephrase the placeholder comment

* Check if current block is a paragraph or image

* Abstract the attribute name to use for the connection

* rename `connections` to `__experimentalConnections`

* Do not export `addAttribute()` or `withInspectorControl()`

* Renamed '__experimentalConnections' to 'connections' in block settings

* Renamed '__experimentalConnections' to 'connections' in block settings

* Remove `connections` attribute from block.json

* Renamed '__experimentalConnections' to 'connections' in block settings

* Remove `get_updated_html() . ''` in meta.php

* Add an allowlist of blocks/attributes

* Refactor blocks.php & custom sources

- Separate the "connections" into own file.
- Move the code that renders the HTML using the meta fields back into blocks.php

* Remove trailing comma?

* Update naming:
- "custom sources" -> connection sources
- use "block connections" consistently

---------

Co-authored-by: Carlos Bravo <carlos.bravo@automattic.com>
  • Loading branch information
michalczaplinski and cbravobernal committed Aug 9, 2023
1 parent 621b21b commit fffaab7
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 0 deletions.
104 changes: 104 additions & 0 deletions lib/experimental/blocks.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,107 @@ function gutenberg_register_metadata_attribute( $args ) {
return $args;
}
add_filter( 'register_block_type_args', 'gutenberg_register_metadata_attribute' );


$gutenberg_experiments = get_option( 'gutenberg-experiments' );
if ( $gutenberg_experiments && array_key_exists( 'gutenberg-connections', $gutenberg_experiments ) ) {
/**
* Renders the block meta attributes.
*
* @param string $block_content Block Content.
* @param array $block Block attributes.
* @param WP_Block $block_instance The block instance.
*/
function gutenberg_render_block_connections( $block_content, $block, $block_instance ) {
$connection_sources = require __DIR__ . '/connection-sources/index.php';
$block_type = $block_instance->block_type;

// Allowlist of blocks that support block connections.
// Currently, we only allow the following blocks and attributes:
// - Paragraph: content.
// - Image: url.
$blocks_attributes_allowlist = array(
'core/paragraph' => array( 'content' ),
'core/image' => array( 'url' ),
);

// Whitelist of the block types that support block connections.
// Currently, we only allow the Paragraph and Image blocks to use block connections.
if ( ! in_array( $block['blockName'], array_keys( $blocks_attributes_allowlist ), true ) ) {
return $block_content;
}

// If for some reason, the block type is not found, skip it.
if ( null === $block_type ) {
return $block_content;
}

// If the block does not have support for block connections, skip it.
if ( ! block_has_support( $block_type, array( '__experimentalConnections' ), false ) ) {
return $block_content;
}

// Get all the attributes that have a connection.
$connected_attributes = _wp_array_get( $block['attrs'], array( 'connections', 'attributes' ), false );
if ( ! $connected_attributes ) {
return $block_content;
}

foreach ( $connected_attributes as $attribute_name => $attribute_value ) {

// If the attribute is not in the allowlist, skip it.
if ( ! in_array( $attribute_name, $blocks_attributes_allowlist[ $block['blockName'] ], true ) ) {
continue;
}

// If the source value is not "meta_fields", skip it because the only supported
// connection source is meta (custom fields) for now.
if ( 'meta_fields' !== $attribute_value['source'] ) {
continue;
}

// If the attribute does not have a source, skip it.
if ( ! isset( $block_type->attributes[ $attribute_name ]['source'] ) ) {
continue;
}

// If the attribute does not specify the name of the custom field, skip it.
if ( ! isset( $attribute_value['value'] ) ) {
continue;
}

// Get the content from the connection source.
$custom_value = $connection_sources[ $attribute_value['source'] ](
$block_instance,
$attribute_value['value']
);

$tags = new WP_HTML_Tag_Processor( $block_content );
$found = $tags->next_tag(
array(
// TODO: In the future, when blocks other than Paragraph and Image are
// supported, we should build the full query from CSS selector.
'tag_name' => $block_type->attributes[ $attribute_name ]['selector'],
)
);
if ( ! $found ) {
return $block_content;
};
$tag_name = $tags->get_tag();
$markup = "<$tag_name>$custom_value</$tag_name>";
$updated_tags = new WP_HTML_Tag_Processor( $markup );
$updated_tags->next_tag();

// Get all the attributes from the original block and add them to the new markup.
$names = $tags->get_attribute_names_with_prefix( '' );
foreach ( $names as $name ) {
$updated_tags->set_attribute( $name, $tags->get_attribute( $name ) );
}

return $updated_tags->get_updated_html();
}

return $block_content;
}
add_filter( 'render_block', 'gutenberg_render_block_connections', 10, 3 );
}
15 changes: 15 additions & 0 deletions lib/experimental/connection-sources/index.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php
/**
* Connection sources that block attributes can be connected to.
*
* @package gutenberg
*/

return array(
'name' => 'meta',
'meta_fields' => function ( $block_instance, $meta_field ) {
// We should probably also check if the meta field exists but for now it's okay because
// if it doesn't, `get_post_meta()` will just return an empty string.
return get_post_meta( $block_instance->context['postId'], $meta_field, true );
},
);
1 change: 1 addition & 0 deletions packages/block-library/src/paragraph/block.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"description": "Start with the basic building block of all narrative.",
"keywords": [ "text" ],
"textdomain": "default",
"usesContext": [ "postId" ],
"attributes": {
"align": {
"type": "string"
Expand Down

0 comments on commit fffaab7

Please sign in to comment.