Closed lukecarbis closed 5 years ago
Yeah, that's a good idea. I've heard requests for this also.
In terms of how a PHP API should be structured, here are some options.
ACF uses a single large configuration array, and provides two helper functions. Here's an example of how this might look in Block Lab.
block_lab_add_block(
array(
'name' => 'example-block',
'title' => __( 'Example Block' ),
'icon' => 'sentiment_satisfied_alt',
'category' => 'common',
'keywords => array(
'foo',
'bar',
),
fields = array(
array(
'name' => 'first',
'label' => __( 'First Name' ),
'control' => 'text',
'help' => __( 'Type your first name here' ),
),
),
)
);
block_lab_add_field(
array(
'block' => 'example-block',
'name' => 'last',
'label' => __( 'Last Name' ),
'control' => 'text',
)
);
Gravity Forms uses a similar approach, but with a class (GFAPI
), and instead of a configuration array, it requests an instantiated Form
object. Translating this to Block Lab, it would look something like:
$block = new Block();
$block->from_array(
'name' => 'example-block',
'title' => __( 'Example Block' ),
'icon' => 'sentiment_satisfied_alt',
'category' => 'common',
'keywords => array(
'foo',
'bar',
),
'fields' => array(
'first' => array(
'name' => 'first',
'label' => __( 'First Name' ),
'control' => 'text,
'type' => 'string',
'order' => 1,
),
),
);
block_lab()->api->register_block( $block );
block_lab()->api->register_field(
$block,
array(
'name' => 'last',
'label' => __( 'Last Name' ),
'control' => 'text,
'type' => 'string',
'order' => 2,
),
);
The method above actually nearly works as is. It's just the block_lab()->api()
part that doesn't yet exist (there's nothing stopping you from actually instantiating a block using the method above right now). Given this, all we would need to do, technically, is add a filter to Blocks\Loader->retrieve_blocks()
.
function add_my_example_block( $blocks ) {
$example_block = new Block();
$example_block->from_array(
'name' => 'example-block',
'title' => __( 'Example Block' ),
'icon' => 'sentiment_satisfied_alt',
'category' => 'common',
'keywords => array(
'foo',
'bar',
),
'fields' => array(
'first' => array(
'name' => 'first',
'label' => __( 'First Name' ),
'control' => 'text,
'type' => 'string',
'order' => 1,
),
'last' => array(
'name' => 'last',
'label' => __( 'Last Name' ),
'control' => 'text,
'type' => 'string',
'order' => 1,
),
),
);
$blocks[] = $example_block;
return $blocks;
}
add_filter( 'block_lab_blocks', 'add_my_example_block' );
Just in case it isn't clear, this third method literally requires a single line of code to be added.
ACF Builder is a custom PHP API for quickly building out ACF field groups. People like it because it is very descriptive. It could work alongside any of the approaches above, as all it does is outputs a config array.
One of the key aspects of this approach is that the Builder would make opinionated assumptions for default values. For example, the block slug, if not specified, would be auto-generated.
Here's how a similar approach could work with Block Lab:
// You could optionally provide a config array for icon, category, etc. as the second argument.
$example_block = new block_lab()->builder( __( 'Example Block' ) );
$example_block
->add_text( __( 'First Name' ) )
->add_text( __( 'Last Name' ), array( 'name => 'last' ) )
->add_image( __( 'Profile Photo' ) )
->add_URL( __( 'Website' ) );
// We could use this with option 1 (Helper functions, with config array).
block_lab_add_block( $example_block->build() );
// Or we could use this with option 2 (Class based, with config array).
block_lab()->api->register_block( $example_block->build() );
// Or with option 3 (Filter based).
add_filter( 'block_lab_blocks', function( $blocks ) {
// In this case we could have the build method return an instantiated Block.
$blocks[] = $example_block->build();
} );
// Or just on its own.
$example_block->register();
Thanks for reading! Which do you think is the best path forward?
I'm more familiar with the style of Option 1, so I'd lean that way, but it comes down to which is better really. My experience is limited. :)
I do like the idea of the Builder
alongside. It would be interesting to get insight on how widely used/appreciated that method is.
@RobStino What about if it was just the builder, standalone? No helper functions. Would work like this:
$example_block = new block_lab()->builder(
__( 'Example Block' ),
array( 'category' => 'formatting' )
);
$example_block
->add_text( __( 'First Name' ) )
->add_text( __( 'Last Name' ), array( 'name => 'last' ) )
->add_image( __( 'Profile Photo' ) )
->add_url( __( 'Website' ) )
->register();
Or do you prefer the helper functions:
$example_block = new block_lab()->builder(
__( 'Example Block' ),
array( 'category' => 'formatting' )
);
$example_block
->add_text( __( 'First Name' ) )
->add_text( __( 'Last Name' ), array( 'name => 'last' ) )
->add_image( __( 'Profile Photo' ) )
->add_url( __( 'Website' ) );
block_lab_add_block( $example_block->build() );
Hi @lukecarbis, Wow, what a great writeup!
Option 1 (helper function) looks really good to me, and maybe option 4 after that.
I think option 1 would be the most similar to existing 'registration' functions in WordPress:
Options 2 and 3 aren't bad, but they expose internals, like the Block class:
$block = new Block_Lab\BlocksBlock();
...and its method from_array().
@lukecarbis I think I like the helper functions. But I could learn new things if they're considered better. :) It probably comes down to:
Late on the party, but besides ACF they're plugins like @CMB2 if you're looking for nice API for inspiration/reference. 😎
Hi @marsjaninzmarsa, Thanks for checking this out 😄
Block Lab now has a PHP API for registering blocks: https://github.com/getblocklab/block-lab/pull/434#issue-320112300
A feature request I hear a lot is a way of programatically adding new blocks, using PHP to define them.
For example:
Inspired by this and this.