AdvancedCustomFields / acf

Advanced Custom Fields
http://advancedcustomfields.com/
871 stars 181 forks source link

Introducing the ACF PRO Block Versioning Developer Preview #654

Closed lgladdy closed 2 years ago

lgladdy commented 2 years ago

Introducing the ACF PRO Block Versioning Developer Preview

[Update 3, 20th July 2022] We've released a forth developer preview build with some further bug fixes, you can find the details of those further changes here.

[Update 2, 27th June 2022] We've released a third developer preview build, you can find the details of those further changes here.

[Update 9th June 2022] We've released a second developer preview build, you can find details of the further changes in that release here.

In the last few releases of WordPress, Gutenberg has made significant changes to all aspects of the block editor and block registration, and many of you have raised issues and feature requests to improve ACF Blocks with those improvements.

For our next release of ACF, we’re aiming to bring some key new features to ACF Blocks to take advantage of those new features from Gutenberg, as well as improving existing blocks. We’re releasing a preview build today, early in our development cycle, so we can get your feedback and bug reports early in development.

You can download this preview (tagged as 6.0.0-alpha1) from your account now. This build is ACF PRO 5.12.2 with the following changes:

Block.json support

Since WordPress 5.8, WordPress has supported - and recommended - that blocks are registered through a JSON configuration file. All of the WordPress Block Documentation was migrated to only show block.json configuration objects, and it became confusing for users to know what WordPress configuration options were usable in ACF PRO. This build introduces support for block.json registration of blocks with ACF.

For blocks registered through a block.json file, you can mark them as ACF Blocks by adding a new ACF configuration key to the JSON file, which contains the ACF specific configuration, for example:

{
    "name": "all-fields-block",
    "title": "All Fields Test Block",
    "description": "All fields test block",
    "style": "file:./all-fields-block.css",
    "category": "theme",
    "icon": "admin-comments",
    "apiVersion": 2,
    "keywords": [
        "test",
        "quote"
    ],
    "acf": {
        "mode": "preview",
        "renderTemplate": "all-fields-block.php"
    },
    "styles": [
        { "name": "default", "label": "Default", "isDefault": true },
        { "name": "red", "label": "Red" },
        { "name": "green", "label": "Green" },
        { "name": "blue", "label": "Blue" }
    ],
    "supports": {
        "align": true,
        "anchor": true,
        "alignContent": false,
        "color": {
            "text": true,
            "background": true,
            "link": true
        },
        "alignText": true,
        "spacing": {
            "margin": [
                "top",
                "bottom"
            ],
            "padding": true
        },
        "typography": {
            "lineHeight": true,
            "fontSize": true
        },
        "fullHeight": true
    },
    "attributes": {
        "backgroundColor": {
            "type": "string",
            "default": "purple"
        }
    },
    "example": {
        "attributes": {
            "data": {
                "text": "This is an example text field",
                "text_area": "This is an example text area field"
            }
        }
    }
}

You then need to use the standard WordPress block registration function register_block_type, rather than acf_register_block_type:

register_block_type( 'path/to/folder/containing/block.json' );

If you don't specify a namespace for your block like in our example above: "name": "all-fields-block",, ACF will automatically add it if it is an ACF block to become the equivalent of "name": "acf/all-fields-block",

Upon release, this new method of registering blocks will become the recommended way to register a block, replacing the acf_register_block_type function.

The renderTemplate property should either be a full path to the template file, or relative to the location of the JSON file.

WordPress uses a camelCase format inside JSON files, and ACF adopts that too. Configuration keys such as render_template when used in acf_register_block_type need to be renderTemplate when used in JSON, likewise align_content and full_height should be alignContent and fullHeight for example. All previous configuration objects are supported, except for enqueue_style, enqueue_script and enqueue_assets for the following reason:

Asset Loading

When ACF Blocks was first introduced, it supported enqueueing block specific assets before WordPress had native support. Recent (and upcoming) updates to Gutenberg will require these assets to be loaded using specific WordPress asset configuration keys such as editorScript, script, editorStyle and style.

WordPress 5.9 users who use Block Styles may have noticed that the ACF registration of styles was not applied to those previews, which is why all ACF Block users should migrate their blocks to use those WordPress provided methods of asset loading.

The previous methods of asset loading in ACF Blocks will continue to work for the time being in acf_register_block_type, but as WordPress continues to make changes across releases we expect that to stop working.

Block ID removal

This release of ACF will remove saved block IDs from ACF Blocks. This means you can easily copy and paste blocks, simplify your post type templates or block patterns, or duplicate blocks without having any issues where block IDs clash.

We’re hoping this change is transparent to users, and any existing blocks will have their block IDs removed the first time they’re edited after installing this build. We’ll still generate a $block['id'] for your templates as we know some users use that for element IDs, but the format of those IDs will change, and may be duplicated if you have multiple blocks on the same page with the exact same data (similar to how block IDs are the same inside a query loop block now)

Because of this, if you want to downgrade to ACF 5.12 after installing this build, you may experience warnings in your templates until you edit a block if you are relying on $block['id'] in a template without checking if it exists.

Block Versioning

One of the issues we’ve had with ACF Blocks development is that we haven’t been able to react to new Gutenberg features as fast as we’d like due to the requirement to maintain backwards compatibility with blocks created potentially as far back as WordPress 5.3.

This release of ACF brings block versioning, meaning we can make backwards compatibility breaking changes whenever necessary, allowing users to opt in to them to enable new features.

A new blockVersion (inside the ACF key in block.json) or acf_block_version (if using acf_register_block_type) key is now supported. For blocks registered via block.json, this defaults to 2, and for acf_register_block_type, this defaults to 1.

For now, the only change between the two versions is the way <InnerBlocks /> markup is rendered. If you use block version 2 (which requires WordPress 5.8+), the container markup when using InnerBlocks will match between backend and frontend rendering, with any inner blocks wrapped in a new (and single level) <div class="acf-inner-blocks-container"></div> element. This can help make your CSS layouts easier, as you can be sure both render views have the same markup.

Block Registry Standardization

In previous versions of ACF PRO, a lightweight shim of the block configuration was registered in PHP, and then the full configuration registered in JS.

In this build of ACF the full block configuration is now saved in the WordPress PHP Block Registry. This makes it easier for you to access details of the block configuration in your templates or render callback should you wish.

Block Bug Fixes

We’ve fixed a few reported bugs with ACF Blocks in this build as well. For example, content after <InnerBlocks /> will now render correctly without the need to wrap it in another div, and alignText will now always default to the WordPress default of left rather than an empty string.

Wrap up

We hope you’ll take the time to test this build of ACF - we’re particularly interested in feedback on how your upgrades go to make sure there are no issues with the block ID removal system.

Please leave any comments, bugs or feedback here on this GitHub issue. We’ve left a few debug console messages in this build to try and help us detect any issues with block preloading or rendering, so screenshots of your browser console will likely be especially useful with any bug reports!

JiveDig commented 2 years ago

This is great news, thanks for the hard work thus far! I have a few quick questions that will likely help others test as well.

  1. Can we see an example of loading/enqueuing assets the new way?
  2. Is this new way only relevant when registering blocks via JSON?

I can't wait to test out the v2 markup changes :)

lgladdy commented 2 years ago

@JiveDig

  1. Sure! You can see an example in the block.json above on how to include assets, and more details on the WordPress docs (as you can pass in a script/style handle if you've already registered it).

Specifically:

"style": "file:./all-fields-block.css",

That's loading a file called "all-fields-block.css" in the same folder as the block.json whenever the block is added to a page.

  1. That's actually a good question - and I took a quick look at the WordPress core code for register_block_type_from_metadata which is the function it uses internally, and it looks like the functions for that are exclusive to that function which isn't executed for the old way. So I think the answer is no. Edit: Turns out, this will work - but you need to pass a script or style handle that has previously been registered outside of the block.

I'll look into this a bit deeper to see if we can manually add support for it, but that might not be possible for other reasons that is specific to the block.json loading.

JiveDig commented 2 years ago

Okay great, thanks.

  1. Duh! I looked too quickly and was looking for the word register, enqueue, or asset, not "style" or "script".
  2. We have some complex blocks with field groups registered in PHP. I'm not super clear on how to convert them to JSON and still register the fields in PHP for those blocks, but I'll dive in a bit ASAP.
lgladdy commented 2 years ago

@JiveDig Yeh - we definitely will get migration guides and such in the release documentation. Let me know if you need any help though. For my own dev test blocks I actually just copy/pasted the PHP array and converted it to JSON format, but you could always do:

echo json_encode($block_configuration_array, JSON_PRETTY_PRINT);
die();

to get the start point out from the PHP code for the old way!

JiveDig commented 2 years ago

I got ya. I was thinking acf_add_local_field_group() was also moving to JSON somehow. Registering the actual block in JSON will be an easy conversion. Registering field groups in JSON would definitely not be fun :)

CreativeDive commented 2 years ago

@lgladdy oh wow, a lot of changes. I will need some time to test all of this changes. But here is my first feedback. I have created this issue https://github.com/AdvancedCustomFields/acf/issues/655

It seems this is already fixed by the new alpha version. The field values are now present :-)

CreativeDive commented 2 years ago

@lgladdy it seems there is something broken with the default alignText change to left.

I have registered a block like this:

acf_register_block_type(
    array(
        'name' => 'button',
        'title' => __('Buttons', 'wphave'),
        ...
        'align_text' => 'left', // --> Optional default value
        'supports' => array(
            'align_text' => true, // --> Enable the text alignment control
            ...
        ),
        ...
    )
);

In a specific post I have used this block and the align_text was set to center.

Before the new alpha version, everything looks good with the alignment. After using the new alpha now this align_text is set to left. But before it was saved to center.

It seems there is something wrong and should be improved.

CreativeDive commented 2 years ago

@lgladdy For now, the change from removing block IDs looks good. The block IDs no longer exist.

I have copied some ACF blocks and made changes to each copied block and it seems there are no longer issues with the field values was set to a wrong block.

But this issue https://github.com/AdvancedCustomFields/acf/issues/605 is still there:

https://user-images.githubusercontent.com/31563167/168228690-fffc7dc7-5c81-46fb-be4e-348e71d0a80e.mp4

It only works properly after the post has been saved and reloaded. But not if the block was only inserted after copying. Then correct field changes are not present.

Is there any hope to get this fixed?

CreativeDive commented 2 years ago

@lgladdy this issue https://github.com/AdvancedCustomFields/acf/issues/650 is fixed by using the new alpha. Thank you.

CreativeDive commented 2 years ago

@lgladdy the $block var still contains the "id" attribute:

error_log(print_r($block,true));

...
[id] => block_b11dfd57e4d7a1b736e8632b9b0fcbca
...

This id is no longer used for allocating ACF blocks. Thank you! But will this attribute remain in the $block var in the future?

lgladdy commented 2 years ago

@lgladdy the $block var still contains the "id" attribute:

error_log(print_r($block,true));

...
[id] => block_b11dfd57e4d7a1b736e8632b9b0fcbca
...

This id is no longer used for allocating ACF blocks. Thank you! But will this attribute remain in the $block var in the future?

Yup - the block ID is just a hash of the attributes, but we need to keep $block['id'] there for backwards compatibility reasons with users templates. We don't want to start firing warnings because they're using it for element IDs!

lgladdy commented 2 years ago

@lgladdy it seems there is something broken with the default alignText change to left.

I have registered a block like this:

acf_register_block_type(
  array(
      'name' => 'button',
      'title' => __('Buttons', 'wphave'),
      ...
      'align_text' => 'left', // --> Optional default value
      'supports' => array(
          'align_text' => true, // --> Enable the text alignment control
          ...
      ),
      ...
  )
);

In a specific post I have used this block and the align_text was set to center.

Before the new alpha version, everything looks good with the alignment. After using the new alpha now this align_text is set to left. But before it was saved to center.

It seems there is something wrong and should be improved.

Thanks, I'll look into this one. This is probably because we also turned "align_text" into "alignText"; our upgrade code probably picked up the default value over the set value and didn't change it.

CreativeDive commented 2 years ago

@lgladdy The "Block Versioning" is a very good idea to handle the issue with the block markup. Thank you!

I can confirm the markup for inner blocks is now more simple than before:

Block version 1:

<div class="block-editor-inner-blocks">
<div class="block-editor-block-list__layout" data-is-drop-zone="true">
... innerBlocks ...
</div>
</div>

Block version 2:

<div class="acf-inner-blocks-container block-editor-block-list__layout" data-is-drop-zone="true">
... innerBlocks ...
</div>

This looks good and is the first way in the right direction. Thank you.

But we can't wait for the complete change to make the ACF block markup more simple also for the ACF block itself. :-)

Here is another question to the markup. It seems there is no way to remove the <div class="acf-inner-blocks-container container completely, right?

I asking because, CSS selectors like ".my-acf-block > .my-inner-item" dosen't work if there is the <div class="acf-inner-blocks-container between this elements.

BUT, only ONE additional ACF container is better than a lot of additional ACF containers.

With only one additional ACF container it's more easier to the handle this thing by ".my-acf-block > .acf-inner-blocks-container > .my-inner-item".

lgladdy commented 2 years ago

@lgladdy For now, the change from removing block IDs looks good. The block IDs no longer exist.

I have copied some ACF blocks and made changes to each copied block and it seems there are no longer issues with the field values was set to a wrong block.

But this issue #605 is still there:

May-13-2022.08-58-41.mp4

It only works properly after the post has been saved and reloaded. But not if the block was only inserted after copying. Then correct field changes are not present.

Is there any hope to get this fixed?

Could you remake this video with console open too? For this test, we're logging all the internal IDs (which WordPress handles now) along with all the requests that take place to the renderer, so we should be able to figure out what's happening; but this does point to it being a Gutenberg bug now WordPress is responsible for handling block IDs.

lgladdy commented 2 years ago

@lgladdy The "Block Versioning" is a very good idea to handle the issue with the block markup. Thank you!

I can confirm the markup for inner blocks is now more simple than before:

Block version 1:

<div class="block-editor-inner-blocks">
<div class="block-editor-block-list__layout" data-is-drop-zone="true">
... innerBlocks ...
</div>
</div>

Block version 2:

<div class="acf-inner-blocks-container block-editor-block-list__layout" data-is-drop-zone="true">
... innerBlocks ...
</div>

This looks good and is the first way in the right direction. Thank you.

But we can't wait for the complete change to make the ACF block markup more simple also for the ACF block itself. :-)

Here is another question to the markup. It seems there is no way to remove the <div class="acf-inner-blocks-container container completely, right?

I asking because, CSS selectors like ".my-acf-block > .my-inner-item" dosen't work if there is the <div class="acf-inner-blocks-container between this elements.

BUT, only ONE additional ACF container is better than a lot of additional ACF containers.

With only one additional ACF container it's more easier to the handle this thing by ".my-acf-block > .acf-inner-blocks-container > .my-inner-item".

Honestly, I don't think we'll get any simpler than we have now, until WordPress introduce new features (like they did which let us fix the <InnerBlocks /> markup, which was useInnerBlockProps. WordPress needs all those wrappers around the main block in order to support all the toolbars and things for now - and I suspect there is little value for them to do that as for the overwhelming majority of cases, the current setup is fine.

As for removing the container, nope - that's not possible for the same reasons. Gutenberg (via React) uses the container to know where things can be dragged/dropped etc, and where the "Add New" buttons should appear etc.

CreativeDive commented 2 years ago

@lgladdy I like the new way to register ACF block in the Block.json way. I will test this soon.

CreativeDive commented 2 years ago

Honestly, I don't think we'll get any simpler than we have now, until WordPress introduce new features (like they did which let us fix the markup, which was useInnerBlockProps. WordPress needs all those wrappers around the main block in order to support all the toolbars and things for now - and I suspect there is little value for them to do that as for the overwhelming majority of cases, the current setup is fine.

As for removing the container, nope - that's not possible for the same reasons. Gutenberg (via React) uses the container to know where things can be dragged/dropped etc, and where the "Add New" buttons should appear etc.

@lgladdy Yes, that's what I thought. I think we can deal with that. Because now, in this case, it's just a container.

What is still missing is the markup simplification for the ACF block itself.

CreativeDive commented 2 years ago

Could you remake this video with console open too? For this test, we're logging all the internal IDs (which WordPress handles now) along with all the requests that take place to the renderer, so we should be able to figure out what's happening; but this does point to it being a Gutenberg bug now WordPress is responsible for handling block IDs.

https://user-images.githubusercontent.com/31563167/168238011-601e11a4-41a6-487b-a68f-1b811af0b026.mp4

@lgladdy Here is the full log of the console:

Bildschirmfoto 2022-05-13 um 09 54 32 Bildschirmfoto 2022-05-13 um 09 54 48 Bildschirmfoto 2022-05-13 um 09 55 20

I hope this is helping you.

CreativeDive commented 2 years ago

Thanks, I'll look into this one. This is probably because we also turned "align_text" into "alignText"; our upgrade code probably picked up the default value over the set value and didn't change it.

@lgladdy ok, this means we have to change nothing here right?

CreativeDive commented 2 years ago

@lgladdy Currently I'm trying to test the new feature to load ACF blocks via the block.json file, but I'm having trouble with the script assets:

Using "style": "file:./acf-block-style.css" is working fine.

Using "script": "file:./acf-block.js" is not working.

I get the following message.

register_block_script_handle was called incorrectly. The asset file for the "script" defined in "acf/documentation-menu" block definition is missing. Please see Debugging in WordPress for more information. (This message was added in version 5.5.0.)

This JS file exists and the path is correct. What is wrong here?

CreativeDive commented 2 years ago

@lgladdy I want to ask you if acf_register_block_type() will supported in the future? You wrote:

The previous methods of asset loading in ACF Blocks will continue to work for the time being in acf_register_block_type, but as WordPress continues to make changes across releases we expect that to stop working.

I have worked out that both methods should be supported:

  1. For a large amount of blocks it's very easy to manage blocks via acf_register_block_type() in one file. --> For a large amount (like 80+) of blocks using block.json you have to 80+ files to manage. A lot.

  2. Using acf_register_block_type() allows me to use PHP variables. E.g. for block icons, I use a function like get_svg_icon('arrow'), to load custom icons to my ACF blocks. --> This is more difficult by using block.json

  3. I have custom post types, which represents some parts of section of the website. I my case I don't use the default FSE of WordPress. I have an own way to provide FSE with own post types. Also loading assets I use an own way. --> I'm not sure if the WordPress default assets loading is supporting blocks that comes not from the default "the_content". Maybe the asset loading system of WordPress is not working in cases like this.

  4. Adding blocks in PHP via acf_register_block_type() is more user friendly than using block.json.

  5. It seems loading multiple script assets using block.json is not possible, do you have an hint for me how we can load multiple styles and scripts using block.json?

"script": "file:assets/js/script_1.js",
"script": "file:assets/js/script_2.js"
  1. A other thing is the translation of text strings. I use "Poedit" to create language files. At the moment I think it's not possible to find text string inside a block.json file for "Poedit" to translate this strings. This is one more thing why using block.json is more difficult.

In other words, acf_register_block_type() should be supported in the future, because using this way can have advantages.

CreativeDive commented 2 years ago

@lgladdy I was wondering if a solution would make sense for ACF to automatically create a block.json file for each block using acf_register_block_type()?

lgladdy commented 2 years ago

@lgladdy I want to ask you if acf_register_block_type() will supported in the future? You wrote:

The previous methods of asset loading in ACF Blocks will continue to work for the time being in acf_register_block_type, but as WordPress continues to make changes across releases we expect that to stop working.

I have worked out that both methods should be supported:

  1. For a large amount of blocks it's very easy to manage blocks via acf_register_block_type() in one file. --> For a large amount (like 80+) of blocks using block.json you have to 80+ files to manage. A lot.
  2. Using acf_register_block_type() allows me to use PHP variables. E.g. for block icons, I use a function like get_svg_icon('arrow'), to load custom icons to my ACF blocks. --> This is more difficult by using block.json
  3. I have custom post types, which represents some parts of section of the website. I my case I don't use the default FSE of WordPress. I have an own way to provide FSE with own post types. Also loading assets I use an own way. --> I'm not sure if the WordPress default assets loading is supporting blocks that comes not from the default "the_content". Maybe the asset loading system of WordPress is not working in cases like this.

You'd likely need to look into the WordPress source here to see what filters/action it fires at each point you're looking to do something custom. We've found that there does tend to be filters and actions at most sensible points, so it should be possible!

  1. Adding blocks in PHP via acf_register_block_type() is more user friendly than using block.json.
  2. It seems loading multiple script assets using block.json is not possible, do you have an hint for me how we can load multiple styles and scripts using block.json?
"script": "file:assets/js/script_1.js",
"script": "file:assets/js/script_2.js"

This is dependant on WordPress's support for it, you can see that by each line of their documentation at https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/ or the block schema. Currently script does not support being an array, so you'd need to concat your scripts together. Other enqueues do support it, from various versions of WordPress.

In other words, acf_register_block_type() should be supported in the future, because using this way can have advantages.

We'll support it as long as WordPress does - which should be for the foreseeable future, but you're likely going to notice things like asset enqueuing breaking before that support goes, as the WordPress enqueue system for blocks doesn't work unless you use block.json. We'll investigate if we can backport it into acf_register_block_type, but that might not be possible.

You may also miss out of new features that WordPress brings, as it's starting to put code exclusively in the block.json parsing functions.

Remember, this change is dictated by WordPress rather than us. There are filters you can use to modify block.json too if you wanted to use PHP functions to set things like svg icons.

lgladdy commented 2 years ago

@lgladdy Currently I'm trying to test the new feature to load ACF blocks via the block.json file, but I'm having trouble with the script assets:

Using "style": "file:./acf-block-style.css" is working fine.

Using "script": "file:./acf-block.js" is not working.

I get the following message.

register_block_script_handle was called incorrectly. The asset file for the "script" defined in "acf/documentation-menu" block definition is missing. Please see Debugging in WordPress for more information. (This message was added in version 5.5.0.)

This JS file exists and the path is correct. What is wrong here?

I'll take a look at this - that looks sensible to me, unless there's another acf-block.js on the include path, or something is modifying the include paths.

CreativeDive commented 2 years ago

@lgladdy

I'll take a look at this - that looks sensible to me, unless there's another acf-block.js on the include path, or something is modifying the include paths.

There exists no other script like this. I have tried to load the script directly in the block directory or to load in a sub folder of the block directly. Each time I will get this notice.

By investigating this:

$filter_metadata_registration = function( $settings, $metadata ) {
    error_log(print_r($settings,true));
    return $settings;
};
add_filter( 'block_type_metadata_settings', $filter_metadata_registration, 10, 2 );

register_block_type_from_metadata( __DIR__ );

I can see the 'script' attribute is empty.

CreativeDive commented 2 years ago

@lgladdy

We'll support it as long as WordPress does - which should be for the foreseeable future, but you're likely going to notice things like asset enqueuing breaking before that support goes, as the WordPress enqueue system for blocks doesn't work unless you use block.json. We'll investigate if we can backport it into acf_register_block_type, but that might not be possible.

You may also miss out of new features that WordPress brings, as it's starting to put code exclusively in the block.json parsing functions.

Remember, this change is dictated by WordPress rather than us. There are filters you can use to modify block.json too if you wanted to use PHP functions to set things like svg icons.

Yes it seems the filter block_type_metadata_settings could make it possible to set a custom icon via PHP. This should be working.

For now, in some cases it seems using block.json make a lot of things more difficult than before. Especially if you have a large amount of blocks.

A other thing is the translation of text strings. I use "Poedit" to create language files. At the moment I think it's not possible to find text string inside a block.json file for "Poedit" to translate this strings. This is one more thing why using block.json is more difficult.

CreativeDive commented 2 years ago

In the WordPress way it's possible to register a block like:

register_block_type(
    'my-custom-blocks/calendar',
    array(
        'attributes' => array(
            'align' => array(
                'type' => 'string',
                'enum' => array( 'left', 'center', 'right', 'wide', 'full' ),
            ),
            'day' => array(
                'type' => 'integer',
            ),
            'month' => array(
                'type' => 'integer',
            ),
            'year' => array(
                'type' => 'integer',
            ),
        ),
        'render_callback' => 'render_block_my_custom_blocks_calendar',
        'editor_script'   => 'calendar-editor-js',
        'editor_style'    => 'calendar-editor-css',
        'script'          => 'calendar-frontend-js',
        'style'           => 'calendar-frontend-css',

    )
);

@lgladdy do you know if you use the way above, if this definition is overwriting the content of the block.json file if exists? Or is the JSON content preferred to the way above to register_block_type()? Are both methods supported by WordPress in the future or is the block.json way the only one?

I asking this, because if using register_block_type() is doing the same like have a block.json file, ACF could use a wrapper function and everything can work like before with acf_register_block_type()?

lgladdy commented 2 years ago

In the WordPress way it's possible to register a block like:

register_block_type(
    'my-custom-blocks/calendar',
    array(
        'attributes' => array(
            'align' => array(
                'type' => 'string',
                'enum' => array( 'left', 'center', 'right', 'wide', 'full' ),
            ),
            'day' => array(
                'type' => 'integer',
            ),
            'month' => array(
                'type' => 'integer',
            ),
            'year' => array(
                'type' => 'integer',
            ),
        ),
        'render_callback' => 'render_block_my_custom_blocks_calendar',
        'editor_script'   => 'calendar-editor-js',
        'editor_style'    => 'calendar-editor-css',
        'script'          => 'calendar-frontend-js',
        'style'           => 'calendar-frontend-css',

    )
);

@lgladdy do you know if you use the way above, if this definition is overwriting the content of the block.json file if exists? Or is the JSON content preferred to the way above to register_block_type()? Are both methods supported by WordPress in the future or is the block.json way the only one?

I asking this, because if using register_block_type() is doing the same like have a block.json file, ACF could use a wrapper function and everything can work like before with acf_register_block_type()?

This will either register a second block if you use a different name, or throw an exception that the block name already exists. It won't be possible to "extend" a block.json block that way. WordPress supports passing a PHP array into register_block_type, but as you've probably seen, all the WordPress block documentation doesn't mention it anymore, which is why we're changing to match that.

Also, the script and style in that method should (in theory) do nothing, as they only work in block.json. Scratch that bit - so long as you pass an already registered script or style handle, it will be enqueued.

CreativeDive commented 2 years ago

This will either register a second block if you use a different name, or throw an exception that the block name already exists. It won't be possible to "extend" a block.json block that way. WordPress support supports register_block_type, but as you've probably seen, all the block.json documentation doesn't mention it.

Also, the script and style in that method should (in theory) do nothing, as they only work in block.json.

@lgladdy ok, this sounds like register_block_type() is no 1:1 alternative way to block.json? Because conditionally assets loading is not possible with register_block_type()?

I asking this because, if register_block_type() is a 1:1 alternative way to block.json, it would be possible for ACF to use register_block_type() instead of block.json.

lgladdy commented 2 years ago

This will either register a second block if you use a different name, or throw an exception that the block name already exists. It won't be possible to "extend" a block.json block that way. WordPress support supports register_block_type, but as you've probably seen, all the block.json documentation doesn't mention it. Also, the script and style in that method should (in theory) do nothing, as they only work in block.json.

@lgladdy ok, this sounds like register_block_type() is no 1:1 alternative way to block.json? Because conditionally assets loading is not possible with register_block_type()?

I asking this because, if register_block_type() is a 1:1 alternative way to block.json, it would be possible for ACF to use register_block_type() instead of block.json.

register_block_type() is already used by ACF. Your example above is "the old way" of doing things, and it's how ACF has worked since blocks was first released. All acf_register_block_type does is let ACF add it's bits to the array then pass it through.

CreativeDive commented 2 years ago

@lgladdy ok, but why it's not possible to do this in the same way with acf_register_block_type instead of using block.json?

Yes I can understand that enqueue_style and enqueue_script of acf_register_block_type are outdated. But if register_block_type() is an 1:1 alternative solution toblock.json (I don't know if this is the case), why we can't things like this:

acf_register_block_type(
    array(
        'apiVersion'      => 2,
        'render_callback' => 'render_block_my_custom_blocks_calendar',
        'editor_script'   => 'calendar-editor-js',
        'editor_style'    => 'calendar-editor-css',
        'script'          => 'calendar-frontend-js',
        'style'           => 'calendar-frontend-css',

        ...

        'name' => 'documentation-menu',
        'title' => __('Documentation Menu', 'wphave-documentation'),
        'description' => '',
        'icon' => wphave_svg_icon( 'wphave_batch', $block_foreground ),
        'category' => 'theme-template',
        'keywords' => array( 'documentation', 'menu', 'links' ),
        'mode' => 'preview',
        'post_types' => array('wphave-templates'), // <-- This block is only visible for "wphave-templates" post type
        'supports' => array(
            'align' => array( 'left', 'right', 'wide', 'full' ),
            'mode' => true,
            'multiple' => true,
            'anchor' => true,
        ),
        'render_template' => wphave_documentation_dir( 'inc/acf-blocks/documentation-menu/documentation-menu.php' ),
    )
);

This would make things like custom icons or translation of text string a lot of easier for us.

lgladdy commented 2 years ago

@lgladdy ok, but why it's not possible to do this in the same way with acf_register_block_type instead of using block.json?

You can, it just won't be the recommended way of registering blocks, matching WordPress.

CreativeDive commented 2 years ago

@lgladdy ok now it's clear for me. Thank you.

CreativeDive commented 2 years ago

@lgladdy to my issue above by using block.json:

If I doing this:

{
    "name": "documentation-menu",
    "title": "Documentation Menu",
    "description": "List all pages of the documentation post type in a navigation.",
    "category": "theme-template",
    "icon": "admin-comments",
    "apiVersion": 2,
    "keywords": [
        "documentation",
        "menu",
        "links"
    ],
    "textdomain": "wphave-documentation",
    "acf": {
        "mode": "preview",
        "renderTemplate": "documentation-menu.php"
    },
    "supports": {
        "align":  {
            "left": true,
            "right": true,
            "wide": true,
            "full": true
        },
        "anchor": true,
        "alignContent": false,
        "alignText": false,
        "multiple": true        
    },
    "style": "file:./documentation-menu.css",
    "script": "/Users/martinjost/Sites/localhost/wphave_dev/wp-content/plugins/wphave-documentation/inc/acf-blocks/documentation-menu/assets/js/documentation-menu.js"
}

The script is successfully loaded by entering the absolute path.

Using "script": "file:assets/js/documentation-menu.js" located in sub folder is not working. Or Using "script": "file:./documentation-menu.js" located in the directory itself is not working.

Instead using "script": "assets/js/documentation-menu.js" without file: prefix is working.

lgladdy commented 2 years ago

@lgladdy to my issue above by using block.json:

Just FYI, This is all handled by WordPress, so if this isn't working, it's likely a WordPress bug or because something else is modifying scripts in actions or filters. The WordPress documentation on this is here: https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#wpdefinedasset

Still, we'll test this and make sure it's working properly!

CreativeDive commented 2 years ago

Here an example (maybe useful for others here), how we could solve things with translatable text strings and custom icons if we use the block.json feature:

$filter_metadata_registration = function( $settings, $metadata ) {

    $block_foreground = '#2271b1';

    $acf_block_meta = array(
        'acf_block_name_1' => array(
            'title' => __('Block Name 1', 'text-domain'),
            'description' => __('Block Description 1', 'text-domain'),
            'icon' => wphave_svg_icon( 'wphave_batch', $block_foreground ),
        ),
        'acf_block_name_2' => array(
            'title' => __('Block Name 2', 'text-domain'),
            'description' => __('Block Description 2', 'text-domain'),
            'icon' => wphave_svg_icon( 'wphave_batch', $block_foreground ),
        )
    );

    $block_name = isset( $metadata['name'] ) ? $metadata['name'] : '';

    foreach( $acf_block_meta as $acf_block_name => $meta ) {

        if( $block_name === 'acf/' . $acf_block_name ) {
            $settings['title'] = $meta['title'];
            $settings['description'] = $meta['description'];
            $settings['icon'] = $meta['icon'];
        }   

    }

    return $settings;

};

add_filter( 'block_type_metadata_settings', $filter_metadata_registration, 10, 2 );

register_block_type_from_metadata( __DIR__ );

Code is not tested, but should working. This filter should allow us to overwrite block attributes before the block data is ready processed.

lgladdy commented 2 years ago

WordPress has native support for translations of block.json files, so you shouldn't need to do anything complex like that above to translate a description. That said, the documentation on how this is performed is a little lacking. I'll make a note for us to write something up on this subject before release.

CreativeDive commented 2 years ago

@lgladdy I'm not sure in the case of translation. The way to use tools like "Poedit" is a way of many devs to provide language files. Tools like "Poedit" searching for things like __('Block Description 2', 'text-domain') to create a list of text string which can translate in a .po file.

I think it's currently not possible for "Poedit" to assign text string inside a block.json file for translation, right? Or am I wrong?

CreativeDive commented 2 years ago

@lgladdy I wondering why ACF is saving the field keys in the block data instead of the field names like before? I'm not sure if this is related to the new alpha version, but it's a change to versions before.

Before:

"data" : { "field_name" : "value" }

After:

"data" : { "field_5e7e6559127b5" : "value" }

If have noticed this, because I have cases to get a ACF block setting in this way:

function wphave_get_block_setting( $block_name, $option_name, $post_id = '', $content = '' ) {

    $blocks = wphave_get_blocks_content( $post_id );

    if( ! $blocks ) {
        // Block not found
        return false;
    }

    foreach( $blocks as $block ) {

        if( $block['blockName'] !== $block_name ) {
            continue;   
        }           

        if( isset( $block['attrs']['data'][$option_name] ) ) {
            return $block['attrs']['data'][$option_name];
        }

    }

    return false;

}

I could extend this function in the following way and now it's working again:

function wphave_get_block_setting( $block_name, $option_name, $post_id = '', $content = '' ) {

    $blocks = wphave_get_blocks_content( $post_id );

    if( ! $blocks ) {
        // Block not found
        return false;
    }

    foreach( $blocks as $block ) {

        if( $block['blockName'] !== $block_name ) {
            continue;   
        }           

        if( isset( $block['attrs']['data'][$option_name] ) ) {
            return $block['attrs']['data'][$option_name];
        }

        /*
        * ! Note: Since ACF save the field key instead of the field name,
        * we have to search the correct field key by field name in the data attributes
        */

        $field = acf_get_field( $option_name );
        $field_key = isset( $field['key'] ) ? $field['key'] : '';

        if( $field_key ) {
            return $block['attrs']['data'][$field_key];
        }

    }

    return false;

}

But I want to ask you why this change is necessary? It's a little bit easier to read the block content, if the data provides field names instead of field keys.

lgladdy commented 2 years ago

@lgladdy I wondering why ACF is saving the field keys in the block data instead of the field names like before? I'm not sure if this is related to the new alpha version, but it's a change to versions before.

I'll check this out. We've not noticed this in our testing, and blocks are using the field names as usual.

<!-- wp:acf/all-fields-block {"name":"acf/all-fields-block","data":{"text":"text","_text":"field_61efe0de48bff","text_area":"area","_text_area":"field_61efe0e648c00","date":"20220401","_date":"field_62027c8a7c42a","image":"","_image":"field_621619f5a25ac"},"mode":"preview","alignText":"left","className":"is-style-red"} /-->
CreativeDive commented 2 years ago

@lgladdy thank you. I have used the "Copy all content" button and the result is this:

<!-- wp:acf/header-with-inner-blocks {"name":"acf/header-with-inner-blocks","data":{"field_5e7e6559127b5":"fullscreen","field_5e7e65591980e":"","field_5e7e6ac56d710":{"field_5e7e6ac56d710_field_5c82ba9ff79f9":"bgcolor","field_5e7e6ac56d710_field_5a075cd7f03e6":"#7598C8","field_5e7e6ac56d710_field_57f565b0f7907":"none","field_5e7e6ac56d710_field_5c82c38d81e9d":"none","field_5e7e6ac56d710_field_59b63ce9dd1c5":"1","field_5e7e6ac56d710_field_5d00cfdd5ba78":"0"},"field_60d2ef956dc77" ...

CreativeDive commented 2 years ago

@lgladdy maybe it can be the case, that I have copied a block which was created in an ACF version before. Now I have created a ACF block completely new and this is not the case. The field names are there instead of the field keys in my example above. It seems it is correct in the current alpha version.

lgladdy commented 2 years ago

@CreativeDive Even if you refresh the page, does it stay as that?

ACF has always used field keys in the code editor view, once a block has been edited (or on first add). Once the page is saved, there is a server side process that converts those field keys into the field names.

CreativeDive commented 2 years ago

@lgladdy I tested again. You're right. It only happens when you create a new page with a new block. Then only the field keys are available. After saving and refreshing, the field names are set correctly again.

folbert commented 2 years ago

I am trying the developer preview and am setting both api_version and acf_block_version to 2. However, I still get a lot of extra elements in the editor. See attached screenshot of the DOM.

Screenshot 2022-05-20 at 23 22 08

The elements are not exactly the same as if i set acf_block_version to 1.

Just wondering if I am missing something or if this is the way it is supposed to be. As people before me have mentioned, this makes it a bit more difficult to use display: flex and if I set display: content to the extra elements, the blocks can not be activated for editing by clicking on them.

lgladdy commented 2 years ago

@folbert I guess that's an ACF Block inside an ACF Block? We can't control the wrappers WordPress puts on blocks itself at the moment I'm afraid.

Would it be useful if we investigating removing the acf-block-component and acf-block-preview wrappers and maybe added those classes to the main block div? (that's the one with wp-block class)

I'm not sure how viable that is, but if we're going to make breaking changes this new opt-in version is clearly the time to try it!

CreativeDive commented 2 years ago

Would it be useful if we investigating removing the acf-block-component and acf-block-preview wrappers and maybe added those classes to the main block div? (that's the one with wp-block class)

@lgladdy Wouldn't that be the complete solution to this problem? That would be extra great. The only additional wrapper would be the one for inner blocks right?

folbert commented 2 years ago

@lgladdy Thanks for your reply. Yes, it is a nested ACF Block.

And yes, fewer extra elements would make it easier to work with matching the backend and frontend. In my case, even one single div messes things up since the wrong elements becomes flex items. But I am working on moving classes around using JS in the editor so the extra divs can behave as columns. I have a block "Columns" that can have different inner blocks which all has "colum width" and "offset" settings that needs to be moved upwards in the DOM-hierarchy.

A bit more troublesome is that the "acf-inner-blocks-container"-element is also present when rendering the content in the frontend. Is there a reason for this? Removing line 560 in blocks.php takes care of the problem and I fail to see a reason for it ever being there. I guess it makes the backend match the frontend but I would rather have a "clean" frontend and then fix the backend with custom CSS and JS :)

CreativeDive commented 2 years ago

@folbert We've been trying to achieve a consistent result in the frontend and backend for months and have been in contact with the ACF developers in this regard. So far it looks good as if this will continue to work in the future. My final stand is that only the extra div for inner blocks needs to be preserved.

folbert commented 2 years ago

@CreativeDive I have read https://github.com/AdvancedCustomFields/acf/issues/465 a couple of times :)

I just very recently jumped on the Gutenberg train and have no experience at all with the core blocks. But if they also add an extra div when rendering even in the frontend, I guess it makes sense if ACF does it too (even if I still think it's a bit strange).

Maybe add a filter to let us decide if the extra element should be there or not? I guess there could be one "global" for all blocks and one for each block.