ACF { Advanced Concepts Archives https://www.advancedcustomfields.com/resource-category/advanced-concepts/ Wed, 31 Jan 2024 19:13:39 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.2 Using Context With ACF Blocks https://www.advancedcustomfields.com/resources/using-context-with-acf-blocks/ Wed, 24 Jan 2024 20:20:31 +0000 https://www.advancedcustomfields.com/?post_type=resource&p=465089 ACF Blocks opens the door to more creative building possibilities. One example we previously explored was using InnerBlocks and parent/child relationships, where we nested ACF Blocks inside of each other. Nesting your ACF Blocks organizes your block structure and codebase while allowing for a refined editorial experience. Ready to dive into the code? You can […]

The post Using Context With ACF Blocks appeared first on ACF.

]]>
ACF Blocks opens the door to more creative building possibilities. One example we previously explored was using InnerBlocks and parent/child relationships, where we nested ACF Blocks inside of each other. Nesting your ACF Blocks organizes your block structure and codebase while allowing for a refined editorial experience.

Ready to dive into the code?
You can dive right in by downloading the tt4child.zip! Be sure to have the TwentyTwentyFour theme installed as well as ACF PRO.

ACF 6.0 introduced support for WordPress’s block context. Block context enables higher-level blocks, such as parent blocks, to supply values that descendant blocks within the same structure can utilize. This functionality permits direct child blocks and blocks further down the hierarchy to receive values from a parent block. This process occurs without the necessity for embedding these values directly into the code or establishing a direct link between the parent and descendant blocks.

It is critical to note that block context only flows downward from parent blocks, and it’s not possible to share data upward from child blocks to their parent.

Creating Block Context

Block context is defined in the block’s block.json, just like other block properties and attributes. The relationship of block context relies on there being a block that is the provider and a block that is the consumer of the providing block’s context.

The provider block defines providesContext in its block.json:

Example block that provides context

{
    ...rest of block.json

    "providesContext": {
        "acf/fields": "data"
    },

    ...rest of block.json
}

And the consumer block defines the usesContext in its block.json:

Example block that consumes context

{
    ...rest of block.json

    "usesContext": ["acf/fields"],

    ...rest of block.json
}

Displaying Context Values in ACF Blocks

Once you have established a binding context relationship between your ACF Blocks, you can reference values from the parent block in any nested block by checking and outputting the value in the child block’s template.

<?php echo $context['acf/fields']['an_example_field']; ?>

One thing to note: ACF Blocks use field keys in the block editor, and block data is only hydrated to field names upon saving. Because of this, you should use $context['acf/fields']['field_key'] to get access to the data inside your template if it exists, before defaulting back to $context['acf/fields']['field_name'] if it doesn’t. This supports both backend and frontend output of context data.

Also, whenever the providing parent block’s field value is updated in the editor, the child block that consumes the parent’s context will be automatically re-rendered.

You should also be aware that sharing ACF data with your child blocks will result in sending the complete ACF field data back to the server for rendering previews. This may have performance implications for your blocks in the editor.

Also, ACF automatically passes the postId and postType down through block context by default, which expedites nesting your ACF Block in the Query Loop block.

Conclusion

In summary, ACF Blocks introduces a versatile and powerful way to extend the functionality of the WordPress editor, offering a rich set of features that enhance both the developer and editor experiences. By leveraging InnerBlocks and parent/child relationships, you can structure your content with greater flexibility and precision. The introduction of block context in ACF 6.0 further amplifies this by allowing data to flow seamlessly between blocks, removing the need for direct code embeddings or explicit relationships.

This advancement simplifies the development process and opens up a myriad of creative possibilities for content management and presentation. Whether you are building complex layouts, crafting unique editorial experiences, or providing dynamic content relationships, ACF Blocks equipped with block context capabilities are an invaluable tool in your WordPress development arsenal.

Remember, while the power of ACF Blocks and block context brings great flexibility, it’s important to consider performance implications and the best practices for data management to ensure your site remains fast and responsive. With the right approach, ACF Blocks can transform the way you think about and build with WordPress.

Download the tt4child.zip and dive into the code to see firsthand how ACF Blocks can revolutionize your WordPress projects. Happy coding!

The post Using Context With ACF Blocks appeared first on ACF.

]]>
Extending ACF Blocks With Block Supports https://www.advancedcustomfields.com/resources/extending-acf-blocks-with-block-supports/ Wed, 24 Jan 2024 19:47:24 +0000 https://www.advancedcustomfields.com/?post_type=resource&p=446919 Overview The WordPress Block Supports API offers plenty of features to extend your ACF Blocks. Additional attributes are passed to your block when you opt in to these features. Often, these features enable different parts of the block editor’s user interface and allow your clients to customize corresponding properties like spacing, alignment, or color. This […]

The post Extending ACF Blocks With Block Supports appeared first on ACF.

]]>
Overview

The WordPress Block Supports API offers plenty of features to extend your ACF Blocks. Additional attributes are passed to your block when you opt in to these features. Often, these features enable different parts of the block editor’s user interface and allow your clients to customize corresponding properties like spacing, alignment, or color.

This tutorial shows you how to utilize Block Supports with ACF Blocks to give your clients a consistent and easy-to-use experience for managing block settings and styles. We’ll explore how to add Block Support properties, and then show how to ensure your block’s assigned properties are properly output in the final markup.

This tutorial will modify the custom Author Info block used in previous tutorials. However, you should be able to add the code to any ACF Block and obtain similar results. You can download the current version of the Author Info block here: author-info-block-v2.zip

Be sure to check out the previous tutorials:

  1. Using InnerBlocks and Parent/Child Relationships With ACF Blocks

  2. Locking Down Your ACF Blocks With Block Locking

Declaring Block Supports in ACF Blocks

The entry point for declaring your Block Supports is your ACF Blocks block.json. Let’s look at a simple ACF Block example:

{
    "name": "acf/author-info",
    "title": "Author Info",
    "description": "Display an author's info and picture.",
    "icon": "id",
    "acf": {
        "mode": "preview",
        "renderTemplate": "template.php"
    },
    "supports": {
        "align": true,
        "html": false,
        "jsx": true,
        "mode": true
    }
}

Most of the block.json example above should already look familiar. The "supports" key is where we want to focus. Here, we’re declaring our support for certain features. Two features are unique to ACF Blocks and not part of WordPress: jsx and mode.

  • jsx: JSX refers to how ACF renders your block. This property is true by default in ACF Blocks v2, and is required to use features like <InnerBlocks /> and will be required for upcoming features. When enabled, ACF processes your rendered PHP template in JavaScript first, allowing the use of React implemented features.

  • mode: Adding support for mode allows users to toggle between edit and preview modes via a button. This property defaults to true.

By declaring "align": true, we’re enabling our clients to set this block’s alignment to center, left, right, full, or wide.

The Block Editor in WordPress, showing alignment options for a block.

We can limit the options for alignment by passing in specific attributes.

...
"supports": {
    // Declare support for specific alignment options.
    "align": ["left", "right", "full" ]
}

A block in the WordPress block editor, with limited options for alignment.

You can go even further, using the attributes key to pass a default value for many Block Supports.

...
"supports": {
    // Enable all alignment options.
    "align": true
},
"attributes": {
    "align": {
        "type": "string",
        "default": "right"
    }
}

Whenever a client adds this block to the editor, it will automatically be aligned right.

A block in the block editor, with supports set so it automatically aligns to the right.

Alternatively, you can disable the alignment controls and still force a non-default alignment attribute. Set "align": false, and then pass in an attribute with a new default alignment:

...
"supports": {
    // Disable alignment controls.
    "align": false
},
"attributes": {
    "align": {
        "type": "string",
        "default": "wide"
    }
}

Spacing is another Block Support attribute that we can explore as an example. Spacing can include margin, padding, and blockGap, and each exists as sub-properties of spacing.

...
"supports": {
    "spacing": {
        "margin": true, // Enable margin UI control.
        "padding": true, // Enable padding UI control.
        "blockGap": true // Enables block spacing UI control for blocks that use layout.
    }
}

The example above enables all three spacing properties. Of course, we can be more specific on what we want to allow.

...
"supports": {
    "spacing": {
        "margin": ["bottom", "top"], // Enable margin for arbitrary sides.
        "padding": true, // Enable padding for all sides.
        "blockGap": ["horizontal", "vertical"] // Enables axial (column/row) block spacing controls.
    }
}

Again, we can also provide default values for specific properties that we support with the attributes definition. When we opt into specific spacing properties, the definition of the attributes includes the style attribute.

...
"supports": {
    "spacing": {
        "margin": ["bottom", "top"], // Enable margin for arbitrary sides.
        "padding": true, // Enable padding for all sides.
        "blockGap": ["horizontal", "vertical"] // Enables axial (column/row) block spacing controls.
    }
},
"attributes": {
    "style": {
        "type": "object",
        "default": {
            "spacing": {
                "margin": {
                   "bottom": "2rem",
                    "top": "2rem"
                },
                "padding": "2rem" // Assign default value for all sides
            }
        }
    }
}

Above, we’re opting into specific spacing properties in our "supports" definition. In our "attributes" definition, we’re passing default values to each of our properties. There are a lot of Block Support properties, and we encourage you to experiment with them to turn key features of your ACF Blocks on or off. If you use ACF Blocks v2 and define your blocks with block.json, any new supports added by WordPress in future versions are likely to work without any other changes.

Also, remember that declaring support in your block.json will not automatically apply the final properties to your final saved block markup. Once your blocks have attributes assigned, you will want to apply them programmatically to your blocks. We’ll cover how to do this next.

Applying Block Supports to ACF Blocks

Defining Block Support in your ACF Block’s block.json file was the first step. Next, we need to ensure all of the properties our block supports can be output in the final block markup.

This is where the convenience of ACF PRO’s "renderTemplate" definition comes in handy. In your block.json, you can pass the PHP file you want to call for your block’s template:

"acf": {
    "renderTemplate": "template.php"
}

Once we step into our template.php, we’re passed in several helpful parameters to utilize:

  • $attributes – (array) The block’s attributes.
  • $content – (string) The block’s content as a parse string.
  • $is_preview – (boolean) Check whether or not the block is currently in the editing view.
  • $post_id – (int) The current post being edited or viewed.
  • $wp_block – (WP_Block) The block instance.
  • $context – (array) Any block context information.

WordPress provides us with the handy get_block_wrapper_attributes() function, which we can use to assign our attributes. However, we must be mindful to not try and use this function when ACF Blocks are in preview in the editor, as your blocks will automatically get a wrapper provided by the block editor which could duplicate your attributes. We can use $is_preview to check when we’re in preview mode and avoid confusion.

Let’s look at a specific example. Here is our ACF Block’s block.json definition:

{
    "name": "acf/author-info",
    "title": "Author Info",
    "description": "Display an author's info and picture.",
    "icon": "id",
    "acf": {
        "mode": "preview",
        "renderTemplate": "template.php"
    },
    "attributes": {
        "style": {
            "type": "object",
            "default": {
                "spacing": {
                    "margin": {
                        "bottom": "2rem",
                        "top": "2rem"
                    },
                    "padding": "1rem"
                }
            }
        }
    },
    "supports": {
        "color": true,
        "multiple": false,
        "spacing": {
            "margin": ["bottom", "top"],
            "padding": true
        }
    }
}

Enabling "color": true automatically opts us into some of color’s sub-properties, like "background" and "text". These will allow editors to choose a background color and text color.

We’re passing in a new definition for "multiple": false, which makes sure that this block can only be inserted once in the editor. If an editor tried to insert another copy of our block in the same post, then they would see a grayed-out version of the block in the inserter.

The block editor in WordPress, with the "Author Info" ACF Block greyed out to indicate it is already in the content and cannot be inserted again.

Finally, we’re passing in some "spacing" definitions and setting default values for the desired margin and padding in our "attributes".

When we want to output all this for the final markup and leverage the convenience of get_block_wrapper_attributes() in our "renderTemplate": "template.php" file, we would put:

<?php if ( ! $is_preview ) { ?>
    <div <?php echo wp_kses_data( get_block_wrapper_attributes() ); ?>>
<?php } ?>

    // Block content goes here.

<?php if ( ! $is_preview ) { ?>
    </div>
<?php } ?>

When our editors leverage any of the customization options, they’ll be output in the final markup. It may be a class or style that is output, depending on which features we allow.

The output of an ACF Block, with a devtools panel showing the class and style being output in the block.

Tips for Block Supports and ACF Blocks

There are some special tips to keep in mind when working with Block Supports and ACF Blocks.

Adding, modifying, or removing an attribute from an existing block’s block.json definition will not update the blocks that have already been inserted in your content. It will only impact future versions of the block, including if a user modifies an existing block entry. This is a limitation of how blocks work in WordPress.

ACF Blocks automatically passes a few default Block Supports behind the scenes:

array (
    'align' => true, // Enables alignment
    'html'  => false, // Disables individual block editing in HTML view
    'mode'  => true,
    'jsx'   => true, // Allows ACF to parse JSX to HTML for InnerBlocks
)

This is really just the beginning of what you can do with Block Supports. Some more helpful Block Supports that we want to point out:

By default, all blocks will appear in the inserter, block transforms menu, Style Book, etc. To hide a block from all parts of the user interface so that it can only be inserted programmatically, set inserter to false.

{
…
    "supports": {
        // Hides this block from the inserter.
        "inserter": false
    }
}

By default, all blocks can be converted to reusable blocks, but you may want to disable this ability for certain blocks. If "supports": reusable is set to false, the option to convert the block into a reusable block will not appear.

{
…
    "supports": {
        // Do not allow the block to be converted into a reusable block.
        "reusable": false
    }
}

We’re still just scratching the surface, and WordPress offers a great deal of flexibility for styling and controlling your ACF Blocks with Block Supports. Be sure to check out the full list of Block Supports for more features you can add to your ACF Blocks.

The post Extending ACF Blocks With Block Supports appeared first on ACF.

]]>
ACF Blocks: How to Use Block Locking https://www.advancedcustomfields.com/resources/acf-blocks-how-to-use-block-locking/ Mon, 04 Dec 2023 18:59:13 +0000 https://www.advancedcustomfields.com/?post_type=resource&p=434572 Locking down your ACF Blocks with block locking ensures those blocks can’t be removed or modified in unauthorized ways. You can think of block locking as a safety mechanism, whether you’re using it on a client’s WordPress site or one of your own. In this tutorial, we’ll show you how to use locking to restrict […]

The post ACF Blocks: How to Use Block Locking appeared first on ACF.

]]>
Locking down your ACF Blocks with block locking ensures those blocks can’t be removed or modified in unauthorized ways. You can think of block locking as a safety mechanism, whether you’re using it on a client’s WordPress site or one of your own. In this tutorial, we’ll show you how to use locking to restrict the movement and removal of individual blocks, and even patterns and templates.

In our previous tutorial on using ACF Blocks with InnerBlocks and parent/child relationships, we built a custom Author Info block (parent). This custom ACF Block used InnerBlocks to pass a series of nested blocks, which included another custom Author Twitter block (child).

The Author Twitter block was only available as a nested block within its parent Author Info block context. We used "parent": [ "acf/author-info" ] in the Author Twitter’s block.json file to establish this relationship and nested discoverability.

Now, we want to extend this Author Info block to refine the editorial experience for our editors. We want to make sure that they can get right to editing, and not accidentally remove or move a block and mess up the overall layout. This is where block locking is useful.

If you want to follow the steps in this tutorial exactly and already have some experience with ACF Blocks, you can download the plugin created in our last tutorial and add to it as we go.


New to ACF Blocks? Start with our tutorial on creating your first ACF Block!


What is Block Locking?

WordPress provides two types of block locking: template locking and individual block locking. You can utilize either of these, or combine them for sophisticated restrictions on your blocks.

Some other considerations when using block locking in WordPress:

  • Developers can use templateLock in their nested blocks.
  • Developers can lock entire templates with template_lock, even when registering custom post types.
  • Individual blocks can be assigned lock parameters in block markup. Assigned lock parameters can be used on the individual blocks passed into a template. The individual block’s lock overrides the template locking, unless the template locking value is contentOnly.

We highly recommend reviewing this helpful video on The Key to Locking Blocks from Wes Theron of the Make WordPress Training Team, along with the WordPress documentation.

Using InnerBlock Template Locking

Template locking can be accomplished by passing templateLock to the InnerBlocks component. Like this:

<?php
<InnerBlocks templateLock="all" />

Template locking options include the following:

  • contentOnly — Prevents all operations. Additionally, the block types that don’t have content are hidden from the list view and can’t gain focus within the block list. Unlike the other lock types, children can’t override this.
  • all — Prevents all operations. It is not possible to insert new blocks, move existing blocks, or delete blocks.
  • insert — Prevents inserting or removing blocks, but allows moving blocks.

Below are screenshots of what each of these would look like when applied to our Author Info block.

Editor with list view sidebar expanded and showing only nested content blocks with a lock icon. The result of having InnerBlock templateLock=contentOnly.

Author Info block with templateLock="contentOnly" set on InnerBlocks.
All nested blocks that do not contain content are hidden from the list view. Only content is editable.

Editor with list view sidebar expanded and showing all nested blocks with a lock icon. The result of having InnerBlock templateLock=all.

Author Info block with templateLock="all" set on InnerBlocks.
All nested blocks are locked to prevent moving, deleting, or inserting new blocks.

Editor with list view sidebar expanded and showing all nested blocks with a lock icon. Also, edit navigation expanded for nested paragraph block with option to 'Move to' highlighted. The result of having InnerBlock templateLock=insert.

Author Info block with templateLock="insert" set on InnerBlocks.
All nested blocks are locked from being removed or having new blocks inserted. Existing blocks can be moved.

Unlocking One Nested Block

For our Author Info block, we want to offer editors the option to remove the author’s biography paragraph, but everything else should remain locked from being removed. We’ll start by locking all the blocks down with templateLock="all" attribute on our InnerBlocks component, and then we’ll use individual locking properties to unlock the one nested block we want to allow them to remove. We’ll make all of our changes to the Author’s Info template.php file, in the author-info directory of the custom plugin we created in our tutorial on InnerBlocks.

For now, we’ll update our InnerBlocks code as follows:

<?php
<InnerBlocks templateLock="all" />

Next, we’ll have to update our individual nested block to allow removal. So, if editors choose to remove the author’s biography paragraph then they have the ability.

How to Use Individual Block Locking

Individual block locking takes priority and overrides template locking, unless templateLock="contentOnly" is used. This hides all blocks that do not have content from the list view, and allows editors to update only the nested content block.

However, we previously decided to apply templateLock="all". To update the individual Paragraph block nested within our passed template, we just need to target it with an additional lock parameter. Here is our abbreviated nested code before applying the parameter:

array(
    'core/paragraph',
    array(
        'style'    => array(...),
        'fontSize' => 'small',
        'content'  => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.',
    ),
    array(),
),

And here it is after, with our lock applied:

array(
    'core/paragraph',
    array(
        'style'    => array(...),
        'fontSize' => 'small',
        'content'  => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.',
        'lock'     => array(
            'remove' => false,
        ),
    ),
    array(),
),

With the 'remove' => false above, we’re stating that the nested Paragraph block should be allowed to be removed. Yes, the false is confusing, but this is how ya do it! 😉

Now we have our desired control of the block, with both template locking and individual block locking in place.

Author Info block example with lines pointing to differentiated blocks.

Author Info block example with lines pointing to differentiated blocks.

Next Steps and Considerations

This tutorial shows how you can use block and template locking to set editorial conditions and prevent unauthorized removal or modification of your ACF Blocks, but there is a lot of room left to explore.

There is another element to curating your editorial experience, which can be utilized when placing your blocks within patterns. If you plan to leverage your ACF Blocks in the context of patterns, then you’ll want to check out content-only block locking.

You could also extend your block content control strategy by preventing certain roles or users from locking and unlocking blocks. Be sure to check out how to restrict locking and unlocking for roles, specific users, or even post types.

If you’ve been following along, your final, full plugin code should match our version: author-info-block-v2.zip

In the next tutorial, we’ll show you how to use WordPress global styles and block styles with your ACF Blocks, providing a consistent and easy to use experience when managing settings and styles.

The post ACF Blocks: How to Use Block Locking appeared first on ACF.

]]>
ACF Blocks: Using InnerBlocks and Parent/Child Relationships https://www.advancedcustomfields.com/resources/acf-blocks-using-innerblocks-and-parent-child-relationships/ Wed, 11 Oct 2023 15:13:31 +0000 https://www.advancedcustomfields.com/?post_type=resource&p=408935 In this tutorial, we’ll show you how to utilize the InnerBlocks component within an ACF Block. We’ll also demonstrate how you can leverage relationships to nest blocks while limiting their discoverability. By the end of the tutorial, you’ll know how to create an “Author Info” block that mixes ACF Blocks with WordPress core blocks, allowing […]

The post ACF Blocks: Using InnerBlocks and Parent/Child Relationships appeared first on ACF.

]]>
In this tutorial, we’ll show you how to utilize the InnerBlocks component within an ACF Block. We’ll also demonstrate how you can leverage relationships to nest blocks while limiting their discoverability.

By the end of the tutorial, you’ll know how to create an “Author Info” block that mixes ACF Blocks with WordPress core blocks, allowing editors to assign an author image, name, bio, and a social link.

In future tutorials, we’ll demonstrate how to use the Block Locking API (introduced in WordPress 5.9) to lock certain blocks from being modified or moved, and show how to extend your ACF Blocks with alternative Block Styles.


New to ACF Blocks? Start with our tutorial on creating your first ACF Block!


The video below provides a walkthrough of the Author Info block we’re going to create.

Author Info block example with lines pointing to differentiated blocks.

Author Info block example with lines pointing to differentiated blocks.

Steps to complete

  1. Create a WordPress plugin to organize our custom code
  2. Register parent and child ACF Blocks with block.json
  3. Register ACF field for the author’s Twitter
  4. Create display logic with InnerBlocks and block template

Requirements

ACF Blocks is a premium feature found only in ACF PRO. You will also need a WordPress site where you have access to the wp-content directory. We highly recommend using Local or another WordPress development environment to create a sandbox site so you can experiment in complete safety.

Nesting Blocks With InnerBlocks

The InnerBlocks WordPress component is handy for creating a custom block that passes a series of curated nested blocks. There are a few things about how InnerBlocks works that we should cover before we get too deep into the tutorial.

Some native WordPress blocks already utilize InnerBlocks as part of their functionality, including the Columns and Social Icons blocks.

It is important to note that a block can only contain a single InnerBlocks component. This is due to the way the contents of InnerBlocks is stored on the block.

Using nested templates in InnerBlocks

Passing a template of blocks into the InnerBlocks component can pre-populate nested blocks and placeholder attributes, expediting the editorial experience.

Admittedly, the process to create your nested block template can be a bit clumsy, especially if you’re using several blocks and nesting is a few levels deep. Typically, we recommend something like the following process:

  1. Create your nested block layout in the block editor, assigning all desired styles and attributes.
  2. Select the parent block in the editor and choose Copy.
  3. Visit the WPHTML Converter and paste your block markup from the editor. Click Convert to PHP, and copy the converted markup.
  4. Paste the converted markup into your block’s template.php and assign it to a variable so you can use it later on. Be sure to nest it within an array(). We’ll cover this in our last step in this tutorial.

Here is a simple example of what this might look like:

Example of passing a template to InnerBlocks

<?php
    $my_block_template = array(
        array(
            'core/group',
            array(
                'layout' => array(
                    'type' => 'constrained',
                ),
            ),
            array(
                array(
                    'core/paragraph',
                    array(
                        'align'   => 'center',
                        'content' => 'I'm a paragraph.',
                    ),
                    array(),
                ),
                array(
                    'core/separator',
                    array(),
                    array(),
                ),
            ),
        ),
    );

    //...

    <InnerBlocks template="<?php echo esc_attr( wp_json_encode( $my_block_template ) ); ?>" />

Using parent and ancestor relationships in blocks

A common pattern for using InnerBlocks is to create a custom block that’s only available if its parent block is inserted. This allows builders to establish a relationship between blocks, while also limiting a nested block’s discoverability. Currently, there are two relationships builders can use: parent and ancestor. The differences are:

  • If you assign a parent, then you’re stating that the nested block can only be used and inserted as a direct descendant of the parent.
  • If you assign an ancestor, then you’re stating that the nested block can be used and inserted as any descendant of the parent.

The key difference between parent and ancestor is that parent has finer specificity, while an ancestor has greater flexibility in its nested hierarchy.

In our Author Info block, we want the Author Twitter block to be nested inside as a direct descendant. Author Info is defined as the parent in the Author Twitter’s block.json file:

Example block.json with parent key


{ ... "parent": [ "acf/author-info" ] }

Alright, let’s start building our custom plugin and blocks!

1. Create a WordPress plugin to organize our custom code

For our example, we’ll create a custom WordPress plugin to organize our code, although you can create the blocks directly in your theme if you wish. Create a new author-info-block folder in your WordPress site’s wp-content/plugins folder. Then add an author-info-block.php file in the folder. It’s within this file that we’ll define our new WordPress plugin with the following code:

wp-content/plugins/author-info-block/author-info-block.php

<?php
/**
 * Plugin Name: Author Info Block for ACF PRO
 * Description: An example ACF PRO Block to display Author Info.
 * Text Domain: demo-author-block-acf
 */

2. Register parent and child ACF Blocks with block.json

We need to register two ACF Blocks:

  1. Author Info (parent)
  2. Author Twitter (child)

If you’ve followed our Create Your First ACF Block tutorial, then this should be pretty familiar. However, we’re doing things a bit differently, because we’re organizing our blocks in a custom WordPress plugin for this tutorial instead of a child theme.

To register our blocks, we’ll continue editing author-info-blocks.php, and add the following code right after the header:

wp-content/plugins/author-info-block/author-info-block.php

<?php
/**
 * Register our blocks.
 *
 * @link https://www.advancedcustomfields.com/resources/whats-new-with-acf-blocks-in-acf-6/
 *
 * @return void
 */
function demo_author_block_acf_blocks_register() {
    /**
     * We register our blocks with WordPress's handy
     * register_block_type();
     *
     * @link https://developer.wordpress.org/reference/functions/register_block_type/
     */
    // Author Info (parent) block.
    register_block_type( __DIR__ . '/blocks/author-info' );
    // Author Twitter (child) block.
    register_block_type( __DIR__ . '/blocks/author-twitter' );
}
add_action( 'init', 'demo_author_block_acf_blocks_register', 5 );

The code snippet above is registering two blocks with register_block_type(). See the WordPress docs for more information on the args you can pass with this function.

All WordPress blocks, including ACF Blocks, require a block.json file to register their properties. Each block must have its own block.json file.

First, create a blocks directory in your plugin, and then two more directories nested within it: author-info and author-twitter.

Each of these blocks needs the required block.json file. We’ll also create an empty template.php in each directory, which is where our display logic will go (we’ll get to this later). When you’re done, you should have the following within your plugin’s blocks directory:

  • author-info-block/blocks/author-info/block.json
  • author-info-block/blocks/author-info/template.php
  • author-info-block/blocks/author-twitter/block.json
  • author-info-block/blocks/author-twitter/template.php

Let’s start by populating our Author Info block’s block.json metadata.

blocks/author-info/block.json

{
    "name": "acf/author-info",
    "title": "Author Info (ACF Block)",
    "description": "Display an author's info and picture.",
    "icon": "id",
    "keywords": ["author", "writer"],
    "acf": {
        "mode": "preview",
        "renderTemplate": "template.php"
    },
    "supports": {
        "align": false,
        "anchor": true,
        "mode": false
    }
}

And here is the block.json code for the Author Twitter block.

blocks/author-twitter/block.json

{
    "name": "acf/author-twitter",
    "title": "Author Twitter (ACF Block)",
    "description": "Display an author's Twitter link.",
    "icon": "twitter",
    "keywords": ["author", "twitter"],
    "acf": {
        "renderTemplate": "template.php"
    },
    "supports": {
        "anchor": false,
        "align": false
    },
    "parent": [ "acf/author-info" ]
}

The configuration keys used in ACF Blocks are generally the same as those used in WordPress core blocks, but with the addition of the acf configuration key.

If you’re new to registering WordPress block types with block.json metadata, then be sure to dig in to WordPress Block Editor Handbook’s reference: Metadata in block.json.

Some things of note in the block.json files:

  • "renderTemplate": "template.php": Found in both files, this is where our template logic will exist for each block. You are free to change the names of your template files as long as that change is reflected in your JSON file as well. We’ll add the code to these template files in a later step.
  • "parent": [ "acf/author-info" ]: This is found only in the Author Twitter block, making it available only within the Author Info block. The parent configuration key automatically designates the block as only available when used as a child block of the named parent.

Be sure to save your progress, and then go ahead and activate your custom plugin. Because we’ve already defined our ACF Blocks with block.json in the plugin, activating it will automatically make those blocks available. However, the Author Twitter block will only be available in the block inserter if its parent, the Author Info block, exists. Also, since our template.php files are empty, you’ll see nothing in the block editor. Let’s keep going and fix that.

3. Register ACF field for the author’s Twitter

We want to allow editors to be able to add a custom Twitter username, which will in turn create a link for the author’s Twitter profile. So, we need to register a custom field for this and assign it to our Author Twitter block. There are two ways to go about this. One way is to register everything through ACF’s UI, use “Generate PHP” in the ACF’s Tools menu, and then drop the generated code into your plugin’s author-info-block.php file. Alternatively, you can register the fields via PHP in author-info-block.php.

If you’re using ACF’s UI, go ahead and create a new field group for Author Twitter and add a single Text field for Twitter. Be sure to assign it to the Author Twitter block under the “Location Rules” settings.

ACF new field group screen with Twitter field added.

ACF new field group screen with the Presentation tab activated.

Changing settings on the Twitter field’s Presentation tab can provide an easier editorial experience:

  • Presentation > Instructions: https://twitter.com/[username]
  • Presentation > Prepend: https://twitter.com/

We could stop here, because technically our field group is registered and assigned to the block. However, we want to keep our entire custom block plugin portable and distributable between projects. So, we’ll want to co-locate the registration of our newly created Author Twitter field group to reside within our custom plugin. Lucky for us ACF makes this easy too!

Click on Tools in the ACF menu, then select your Author Twitter field group and click Generate PHP. This will give you the code to drop right into your plugin.

Exporting the PHP for a field group using ACF's built-in tools.

Once you’ve added the generated code to your plugin’s author-info-block.php, you can go ahead and delete the field group that you created in ACF’s UI, because it is now registered with code.

wp-content/plugins/author-info-block/author-info-block.php

<?php
/**
 * Register our Author Twitter field group
 * directly in our PHP for portability.
 *
 * @link https://www.advancedcustomfields.com/resources/register-fields-via-php/
 */
add_action(
    'acf/include_fields',
    function() {
        if ( ! function_exists( 'acf_add_local_field_group' ) ) {
            return;
        }

        acf_add_local_field_group(
            array(
                'key'      => 'group_64e3e09959e8f',
                'title'    => 'Author Twitter',
                'fields'   => array(
                    array(
                        'key'          => 'field_64e3e09a7a544',
                        'label'        => 'Twitter',
                        'name'         => 'twitter',
                        'type'         => 'text',
                        'instructions' => 'https://twitter.com/[username]',
                        'prepend'      => 'https://twitter.com/',
                    ),
                ),
                'location' => array(
                    array(
                        array(
                            'param'    => 'block',
                            'operator' => '==',
                            'value'    => 'acf/author-twitter',
                        ),
                    ),
                ),
            )
        );
    }
);

We’ve gone ahead and streamlined the output above, because not all options are totally necessary. ACF will use defaults for the omitted options. As mentioned previously, it’s entirely possible to skip registering the fields in the UI, and just write the PHP code needed. The Author Info block is controlled by the PHP in author-info-block.php, not the selections made in the admin UI.

4. Create display logic with InnerBlocks and block template

At this point, you have two blocks registered, but there is no display logic for either of them. This is where we utilize InnerBlocks and pass down a block template string to assign and automatically populate the Author Info block upon creation.

First, we’ll set up our display logic for our Author Twitter block, which is outputting the Author Twitter field group we created in the last step.

Open the Author Twitter block’s author-info-block/blocks/author-twitter/template.php and insert the following code.

blocks/author-twitter/template.php

<?php
/**
 * Author Twitter (child) block.
 * This block is only available as a child
 * block within the parent Author Info block.
 */

// Grab our ACF field.
$twitter_handle = get_field( 'twitter' );
?>

<?php if ( empty( $twitter_handle ) ) : ?>
    <p>Please enter a Twitter handle.</p>
<?php else : ?>
    <p>
        <svg height="0.95rem" width="0.95rem" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="icon icon-twitter" viewBox="0 0 24 24"><path d="M22 4s-.7 2.1-2 3.4c1.6 10-9.4 17.3-18 11.6 2.2.1 4.4-.6 6-2C3 15.5.5 9.6 3 5c2.2 2.6 5.6 4.1 9 4-.9-4.2 4-6.6 7-3.8 1.1 0 3-1.2 3-1.2z"/></svg>
        <a href="https://twitter.com/<?php echo esc_html( $twitter_handle ); ?>">
            @<?php echo esc_html( $twitter_handle ); ?>
        </a>
    </p>
<?php endif; ?>

This will check for our Twitter field value and display it if there is one available.

Next, we’ll add the Author Info block’s display logic in the corresponding demo-acf-plugin/blocks/author-info/template.php file.

blocks/author-info/template.php

<?php
/**
 * Author Info block (parent).
 *
 * @param array  $block The block settings and attributes.
 * @param string $content The block inner HTML (empty).
 * @param bool   $is_preview True during backend preview render.
 * @param int    $post_id The post ID the block is rendering content against.
 *                     This is either the post ID currently being displayed inside a query loop,
 *                     or the post ID of the post hosting this block.
 * @param array $context The context provided to the block by the post or its parent block.
 */

// Support custom id values.
$block_id = '';
if ( ! empty( $block['anchor'] ) ) {
    $block_id = esc_attr( $block['anchor'] );
}

// Create class attribute allowing for custom "className".
$class_name = 'demo-author-block-acf';
if ( ! empty( $block['className'] ) ) {
    $class_name .= ' ' . $block['className'];
}

/**
 * A template string of blocks.
 * Need help converting block HTML markup to an array?
 * 👉 https://happyprime.github.io/wphtml-converter/
 *
 * @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-templates/
 */
$inner_blocks_template = array(
    array(
        'core/columns',
        array(
            'verticalAlignment' => 'center',
            'style'             => array(
                'spacing' => array(
                    'padding' => array(
                        'top'    => 'var:preset|spacing|30',
                        'right'  => 'var:preset|spacing|30',
                        'bottom' => 'var:preset|spacing|30',
                        'left'   => 'var:preset|spacing|30',
                    ),
                ),
            ),
        ),
        array(
            array(
                'core/column',
                array(
                    'verticalAlignment' => 'center',
                    'width'             => '120px',
                ),
                array(
                    array(
                        'core/image',
                        array(
                            'align'           => 'center',
                            'sizeSlug'        => 'thumbnail',
                            'linkDestination' => 'none',
                            'className'       => 'is-style-rounded',
                            'url'             => 'https://i.pravatar.cc/120',
                        ),
                        array(),
                    ),
                ),
            ),
            array(
                'core/column',
                array(
                    'verticalAlignment' => 'center',
                    'width'             => '',
                ),
                array(
                    array(
                        'core/paragraph',
                        array(
                            'fontSize' => 'large',
                            'content'  => 'Taylor Swift',
                        ),
                        array(),
                    ),
                    array(
                        'core/paragraph',
                        array(
                            'style'    => array(
                                'spacing' => array(
                                    'margin' => array(
                                        'bottom' => '0',
                                        'top'    => '0',
                                    ),
                                ),
                            ),
                            'fontSize' => 'small',
                            'content'  => 'Ea qui voluptate irure nulla aliquip nulla anim laborum exercitation eu incididunt.',
                        ),
                        array(),
                    ),
                    array(
                        'acf/author-twitter-v1',
                        array(
                            'name' => 'acf/author-twitter-v1',
                            'data' => array(
                                'twitter' => 'wp_acf',
                            ),
                            'mode' => 'auto',
                        ),
                        array(),
                    ),
                ),
            ),
        ),
    ),
);

?>

<?php if ( ! $is_preview ) { ?>
    <div
        <?php
        echo wp_kses_data(
            get_block_wrapper_attributes(
                array(
                    'id'    => $block_id,
                    'class' => esc_attr( $class_name ),
                )
            )
        );
        ?>
    >
<?php } ?>

    <InnerBlocks
        class="demo-author-block-acf__innerblocks"
        template="<?php echo esc_attr( wp_json_encode( $inner_blocks_template ) ); ?>"
    />

<?php if ( ! $is_preview ) { ?>
    </div>
<?php } ?>

There is a lot going on in the code snippet above. Let’s break it down. The biggest piece of this snippet is the $inner_blocks_template (near the top), a variable we assign to our template property within <InnerBlocks> (near the bottom). The $inner_blocks_template variable consists of an array of blocks and their attributes, with further nested blocks within those. Near the bottom of the long nested array you’ll see that we’re passing our custom acf/author-twitter block with a default twitter field value of wp_acf. This will help pre-populate the field when the Author Info block is added in a new post.

The nesting and proper syntax to get these complex template strings correct can be pretty hard to figure out. The array that defines the $inner_blocks_template has over 30 more arrays nested within it. The first array is core/columns, a WordPress core block that allows us to display multiple columns that each contain blocks. Diving a little deeper into the core/columns array, we see it’s a further array containing style values:

$inner_blocks_template = array(
    array(
        'core/columns',
        array(
            'verticalAlignment' => 'center',
            'style'             => array(
                'spacing' => array(
                    'padding' => array(
                        'top'    => 'var:preset|spacing|30',
                        'right'  => 'var:preset|spacing|30',
                        'bottom' => 'var:preset|spacing|30',
                        'left'   => 'var:preset|spacing|30',
                    ),
                ),
            ),
        ),

This nesting quickly becomes complex, even for relatively simple uses of InnerBlocks. The easiest way to create an array like this is to create the layout and design within the block editor, and then switch to “List View” and click the three dots to the right of your block. Click Copy block to copy the WordPress block HTML to your clipboard. Finally, paste it into a tool like WPHTML Converter to convert the markup into the proper array format.

Below is a video demonstrating the conversion process.

If you’ve been following along, your final, full plugin code should match our version: author-info-block-v1.zip

Wrapping Up

This tutorial illustrates how to create an Author Info block and integrate InnerBlocks with ACF Blocks to create nested blocks with parent/child relationships. However, there is still much more to explore.

In the next tutorial, we’ll show you how to use block and template locking to lock down key blocks in your markup and set editorial conditions. This helps ensure your editors only edit what they need to, setting them up for the best editorial experience.

The post ACF Blocks: Using InnerBlocks and Parent/Child Relationships appeared first on ACF.

]]>
Block API v2 https://www.advancedcustomfields.com/resources/block-api-v2/ Thu, 17 Feb 2022 17:37:54 +0000 https://www.advancedcustomfields.com/resources/block-api-v2/ Introduction Since WordPress 5.6, the block editor has a new version of the Block API. The ACF 5.10 release introduced support for the Block API v2. This is only available when ACF is installed on sites using WordPress 5.6 and above. Changes The block wrapper element for ACF Blocks with Block API v2 support now […]

The post Block API v2 appeared first on ACF.

]]>
Introduction

Since WordPress 5.6, the block editor has a new version of the Block API. The ACF 5.10 release introduced support for the Block API v2. This is only available when ACF is installed on sites using WordPress 5.6 and above.

Changes

The block wrapper element for ACF Blocks with Block API v2 support now have a predefined class of wp-block-{name}, where name is generated from the name of the block. This is in line with the changes to how the block editor defines the default wrapper element.

<div id="testimonial-block_6126540e5e5e2" class="testimonial wp-block-acf-testimonial">

Block Filters

In ACF 5.10 we moved to support version 2 of the WordPress Blocks API. The goal was to support more advanced functionality such as the ability to use the Block Editor’s extraProps filter. Unfortunately, our implementation of this triggered re-rendering of ACF blocks anytime a property changed, which caused issues with other block editor features such as block styles and the built-in spacing/padding support.

ACF 5.11 removed support of the extraProps functionality to prevent these re-renders which will improve performance and solve issues with block styles. We want ACF blocks to function as closely as possible to core or custom-built WordPress blocks. Therefore, we’re working on re-introducing support for this in an upcoming release.

The post Block API v2 appeared first on ACF.

]]>