Make WordPress Core

Opened 2 months ago

Last modified 8 weeks ago

#62705 new feature request

Block Bindings: Expose UI options for the source from the server

Reported by: cbravobernal's profile cbravobernal Owned by:
Milestone: 6.8 Priority: normal
Severity: normal Version: 6.5
Component: Editor Keywords: has-patch
Focuses: Cc:

Description (last modified by cbravobernal)

This ticket was mentioned in PR #7987 on WordPress/wordpress-develop by @cbravobernal.
Trac ticket: https://core.trac.wordpress.org/ticket/62705

## What?
I'm experimenting if it is possible to add sources to the UI just by defining them on the server side. It will need a PR in Gutenberg to be landed.

This registration:

register_block_bindings_source(
                        'bbe/now-date',
                        array(
                                'label'              => __( 'Current date', 'custom-bindings' ),
                                'get_value_callback' => function ( array $source_args, $block_instance ) {
                                        return gmdate( $source_args['key'] );
                                },
                                'fields'             =>
                                        array(
                                                'Y-m-d H:i:s' => array(
                                                        'type'  => 'string',
                                                        'value' => 'Y-m-d H:i:s',
                                                ),
                                                'D'           => array(
                                                        'type'  => 'string',
                                                        'value' => 'D',
                                                ),
                                        ),
                        )
                );

will return:

https://github.com/user-attachments/assets/0e08f37c-829a-46c9-880c-511453bc20d4

We are using keys as the source arguments to decide the format. It's an approach I'm not 100% comfortable with. We may need to update the JS API.
https://github.com/user-attachments/assets/71246745-a02f-432c-b6b0-69157bdccec4

https://github.com/user-attachments/assets/60f7934a-e772-457f-8be7-f9ca32fd1a1e

Change History (5)


2 months ago
#1

  • Keywords has-patch added

#2 @cbravobernal
2 months ago

  • Description modified (diff)

@cbravobernal commented on PR #7987:


2 months ago
#3

What I don't like of this approach is that only the key is needed to render the frontend. The value could be anything, and that anything would be shown on the frontend if you don't tweak it with getValueson the editor. Something like:

register_block_bindings_source(
                        'bbe/now-date',
                        array(
                                'label'              => __( 'Current date', 'custom-bindings' ),
                                'get_value_callback' => function ( array $source_args, $block_instance ) {
                                        return gmdate( $source_args['key'] );
                                },
                                'fields'             =>
                                        array(
                                                'Y-m-d H:i:s' => array(
                                                        'type'  => 'string',
                                                        'value' => 'i don\'t use it',
                                                ),
                                                'D'           => array(
                                                        'type'  => 'string',
                                                        'value' => 'i don\'t use it',
                                                ),
                                        ),
                        )
                );

Would still render this on the editor:

<p></p>


<p></p>

And this would be the UI:
https://github.com/user-attachments/assets/e6a6b93c-a948-4b46-b79d-9dc13b3a003b

#4 @gziolo
8 weeks ago

  • Component changed from General to Editor
  • Milestone changed from Awaiting Review to 6.8
  • Summary changed from Block Bindings: Try fields registration on server. to Block Bindings: Expose UI options for the source from the server
  • Type changed from enhancement to feature request
  • Version set to 6.5

Based on the existing prototypes, I would like to better understand what information does the UI need to present all options defined on the server and set the args in the block attribute's metadata?

To start with an example included in the ticket, the key used in the source seems introduce a layer of indirection. In theory the only thing that the source might need to display on the frontend is the format of the data:

<!-- wp:paragraph {"metadata":{"bindings":{"content":{"source":"bbe/now-date","args":{"format":"D"}}}}} -->
<p></p>
<!-- /wp:paragraph -->

In effect, when the option gets selected from the Attributes UI in the sidebar, then the "args" need to get saved for the block. Ideally, that information is already provided from the server:

<?php
$source_ui_option_day = array(
    'args' => array(
        'format' => 'D',
    ),
);

Next, we need a label to present the option in the UI:

<?php
$source_ui_option_day = array(
    'label' => __( 'Day of the week', 'bbe' ),
    'args'  => array(
        'format' => 'D',
    ),
);

The type is used in the UI to filter the options based on the matching type defined for the attributes, in effect we need to provide it, too. Could we assume the default is string?

<?php
$source_ui_option_day = array(
    'label' => __( 'Day of the week', 'bbe' ),
    'type'  => 'string', // 'datetime` in the future?
    'args'  => array(
        'format' => 'D',
    ),
);

The last missing element would be the preview of the data, in this case it could work pretty well:

<?php
$source_ui_option_day = array(
    'label'  => __( 'Day of the week', 'bbe' ),
    'type'   => 'string', // 'datetime` in the future?
    'value' => gmdate( 'D' ),
    'args'   => array(
        'format' => 'D',
    ),
);

What else the UI might need?

The last step would be the registration. Overall, we should take into account performance considerations as these UI options are only needed in the editor. There is some prior work for block variations that triggered refactoring in WordPress core to use a callback so the code is executed only when really necessary (dev note for context). Even in this example, we could avoid computations like the gmdate function call if the source wants to use some logic:

<?php
register_block_bindings_source(
    'bbe/now-date',
    array(
        'label'                          => __( 'Current date', 'bbe' ),
        'get_value_callback'  => function ( array $source_args, $block_instance ) {
             if ( empty( $source_args['format'] ) || 'D' !== $source_args['format'] ) {
                 return '';
             }
             return gmdate( $source_args['format'] );
        },
        'ui_options_callback' => function() {
            return array(
                array(
                    'label'  => __( 'Day of the week', 'bbe' ),
                    'type'   => 'string', // 'datetime` in the future?
                    'value' => gmdate( 'D' ),
                    'args'   => array(
                        'format' => 'D',
                    ),
                )
            );
        }
    )
);

All the nomenclature is up for debate. I wanted to share my current understanding of how it could work so there is an universal way for all sources to integrate into the existing Attributes panel in the block editor's sidbear.

Last edited 8 weeks ago by gziolo (previous) (diff)

#5 @cbravobernal
8 weeks ago

What I've seen in most of approaches of Block Bindings is that ´$source_argskey?´ is the variable guiding the frontend rendered content.

In post meta, the list is showing all the different values that ´key´ may have. And interacting with them within the UI will set that ´key´ value. Taking that into account, an example of what the user may need with dates could be this one:

array(
	'label'              => __( 'Current dates', 'custom-bindings' ),
	'get_value_callback' => function ( array $source_args, $block_instance ) {
		switch ( $source_args['key'] ) {
			case 'y_m_d':
				return gmdate( 'Y M D' );
			case 'y_m_d_h_i_s':
				return gmdate( 'Y M D h i s' );
			default:
				return gmdate( 'Y M D h i s' );
			}
		},
		'args'               => array(
			'y_m_d'       => array(
				'type'  => 'string',
				'label' => __( 'Y M D', 'custom-bindings' ),
				'value' => gmdate( 'Y M D' ),
			),
			'y_m_d_h_i_s' => array(
				'type'  => 'string',
				'label' => __( 'Y M D h i s', 'custom-bindings' ),
				'value' => gmdate( 'Y M D h i s' ),
			),
		),
	),

I think we should define what we want on that UI, should we instead choose between different ´args´? Should we just focus on allowing defining just argskeys?

In the last case, ´label´ would show the format, and value would show an example of what will be rendered on the frontend.

https://private-user-images.githubusercontent.com/37012961/397721788-89c17078-eb37-4f41-ac37-bf23a86305f9.png

Could we assume the default is string?

I think we could assume it. In a future, as you mention, could accept number, bool, dateformat, etc.

I agree with all the requirements you mention. I think the debate should be if we want to allow setting different args via the UI, or we just want to focus on the arg key value. If we want to set different args, we may need to update the internals of post meta right now.

Note: See TracTickets for help on using tickets.