DEV Community

Cover image for Modern Wordpress for PHP Devs using ACF 6 + block.json (Super post)
Rocky Kev
Rocky Kev

Posted on

Modern Wordpress for PHP Devs using ACF 6 + block.json (Super post)

Advanced Custom Fields(ACF) is a WordPress developer's dream. ACF allows developers to add extra content fields to the WordPress Editor.

With ACF 6, ACF Blocks are now registered using the register_block_type(), which loads a block.json file and allows a PHP developer to tap into the Block API for more flexibility.


Background

Before this change, a developer would need to utilize React to build WP Blocks. [For those curious, here's WordPress's Introduction to Block Development with React].(https://learn.wordpress.org/course/introduction-to-block-development-build-your-first-custom-block/)

The alternative was making Blocks with pure HTML (Check out Carolina Nymark's free course on Full site editing for theme developers) or utilize workarounds.

Much of the WordPress ecosystem is PHP Developers. Making WP Blocks with PHP - you had to rely on Advance Custom Fields, you were not able to tap into the Block API, and you missed out on future development that the WordPress team are pushing forward.

Making WP Blocks with PHP + ACF sort of looked like a halfway point between a relic of the past and the latest Modern WordPress.

The Old way

For those unfamiliar, it looks like cramming the WordPress Classic Editor into the Modern Editor.๐Ÿคข๐Ÿคข๐Ÿคข

With ACF 6, there's now more synergy between WP Blocks made natively with React, and the PHP alternative!

Modern Wordpress

(Notice the Editor rendering the changes on the fly? That's now possible thanks to ACF 6!)


Example Repository

In this repo: Advanced Custom Fields 6 + Blocks.json, I made a extremely bare-bones Wordpress theme that uses ALL ACF Fields into individual blocks. You can download the theme as a zip file and import it into your WordPress Themes.

This theme uses a CDN of tailwind css ONLY for ease of use. Tailwind is 100% optional. If you plan to fork this theme, set up tailwind properly.


Block.json

To tap into that synergy with ACF 6, register your blocks with a block.json file.

The block.json is a metadata file to help WordPress identify WHAT the block looks like.

.
โ””โ”€โ”€ the-theme-name
    โ”œโ”€โ”€ blocks
    โ”‚   โ”œโ”€โ”€ text-block
    โ”‚   โ”‚   โ”œโ”€โ”€ template.php
    โ”‚   โ”‚   โ””โ”€โ”€ block.json <--- here
    โ”‚   โ”œโ”€โ”€ different-block
    โ”‚   โ”‚   โ”œโ”€โ”€ template.php
    โ”‚   โ”‚   โ”œโ”€โ”€ block.json <--- here
    โ”‚   โ”‚   โ””โ”€โ”€ style.css
    โ”‚   โ””โ”€โ”€ another-block
    โ”‚       โ”œโ”€โ”€ template.php
    โ”‚       โ”œโ”€โ”€ block.json <--- here
    โ”‚       โ”œโ”€โ”€ style.css
    โ”‚       โ””โ”€โ”€ script.js
    โ”œโ”€โ”€ function.php  
    โ””โ”€โ”€ style.css
Enter fullscreen mode Exit fullscreen mode

It looks like this:

Example: block.json

{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "acf-block-json/text",
    "title": "ACF Block Json Basic: Text",
    "category": "acf-block-json",
    "icon": "welcome-write-blog",
    "version": "1.0.0",
    "acf": {
        "mode": "preview",
        "renderTemplate": "template.php" 
    }
}
Enter fullscreen mode Exit fullscreen mode

Then in your theme, you'll load it with:

    register_block_type(get_template_directory() . '/blocks/text-block/block.json');

    register_block_type(get_template_directory() . '/blocks/different-block/block.json');

    register_block_type(get_template_directory() . '/blocks/another-block/block.json');

Enter fullscreen mode Exit fullscreen mode

Notice that it's following the Block API's recommendation. For all the attributes, visit Metadata in block.json.

In fact, you'll be using that Metadata in block.json like a bible after we're done. :-)

PROTIP: A quick way to verify if your block was properly registered is to check the ACF menu for it.

Quick Check

๐Ÿ“ The ACF metadata

 {
  //...
 "acf": {
        "mode": "preview", // preview, edit, auto
        "renderTemplate": "template.php" 
    }
}
Enter fullscreen mode Exit fullscreen mode

You may notice the acf metadata.

There's a few unique fields. The full list.

Mode is the display.

  • Preview mode - The ACF field lives on the sidebar. This is the method I will use in this article.
  • Auto mode - preview is shown but when you click on the block, it goes into "edit" mode.
  • Edit mode - The ACF Fields exist inside the block. This is similar to how Classic WordPress looks like. (And while it has it's use-cases, it's quite... ugly.)

renderTemplate is the frontend view.
It points to a php file with your business logic and markup.

There's a few other fields, but they're optional and out of the scope of this article.


WP Block Examples with ACF 6

I'll cover some of the more popular WP Blocks.

You can review the repo for working examples of other WP Blocks.

๐Ÿงฑ Basic: Text Field

The easiest field to work with is the Text Field. Direct link to code

The view:
Image description

What ever you put in on the sidebar will automatically render to the markup.

The code:

<?php 

// Text Field
// https://www.advancedcustomfields.com/resources/text/

$text = esc_html(get_field('text'));

$additionalClasses = !empty($block['className']) ? $block['className'] : 'no-classes-added';
?>

<div class="outline outline-4 outline-blue-500 py-4 my-4 <?= $additionalClasses; ?>">
    <h1 class="text-4xl underline pb-4">ACF-basic/Text</h1>
    <p>Text: <?= $text; ?></p>
</div>
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฑ Choice: Button Group

Choice features in ACF all work similar to each other. I picked the more complex field group to highlight how to use it show content, as well as a conditional. Direct link to code

In the Edit Field Group:

field label: Button Group
field name: button_group
choices:
๐Ÿ‡ : ๐Ÿ‡ Grapes
๐Ÿˆ : ๐Ÿˆ Melon
๐Ÿ‰ : ๐Ÿ‰ Watermelon
๐ŸŠ : ๐ŸŠ Tangerine
๐Ÿ‹ : ๐Ÿ‹ Lemon
๐ŸŒ : ๐ŸŒ Banana
๐Ÿ : ๐Ÿ Pineapple
๐Ÿฅญ : ๐Ÿฅญ Mango
๐ŸŽ : ๐ŸŽ Red Apple
๐Ÿ : ๐Ÿ Green Apple
Enter fullscreen mode Exit fullscreen mode

I also created a text field with a conditional to ONLY SHOW if the choice has apple inside the name. (Pineapple, Red Apple, and Green Apple)

The View
Image description

The Code

<?php

// Button Group Field
// https://www.advancedcustomfields.com/resources/button-group/

$buttonGroupData = get_field('button_group');
$buttonValue = $buttonGroupData['value'];
$buttonLabel = $buttonGroupData['label'];

$showAppleText = false;
$addMoreToApples = '';

if (str_contains($buttonLabel, 'Apple')) {
    $showAppleText = true;
    $addMoreToApples = esc_html(get_field('add_more_to_apples'));
}

$additionalClasses = !empty($block['className']) ? $block['className'] : 'no-classes-added';
?>

<div class="outline outline-4 outline-purple-500 py-4 my-4 <?= $additionalClasses; ?>">
    <h1 class="text-4xl underline pb-4">ACF-Choice/Button Group With Text</h1>
    <p>The button selected was: <?= $buttonValue; ?></p>
    <p>If there's more content, it'll show up below:</p>
    <hr />
    <?php if ($showAppleText): ?>
        <p> <?= $addMoreToApples; ?></p>
    <?php endif; ?>
    <hr />
</div>
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฑ Content: WYSIWYG

Direct link to code

The view:
This is one of those moments where rendering the WYSIWYG ACF field into the sidebar is a awful UI experience.

Click on the Pencil Icon and switch it to EDIT mode. (You can also modify the block.json to default it to edit mode.)

Image description

The code:

<?php 
// WYSIYWG Field
// https://www.advancedcustomfields.com/resources/wysiwyg-editor/

$wysiwyg = get_field('wysiwyg');

$additionalClasses = !empty($block['className']) ? $block['className'] : 'no-classes-added';
?>

<div class="outline outline-4 outline-blue-500 py-4 my-4 <?= $additionalClasses; ?>">
<h1 class="text-4xl underline pb-4">ACF-content/WYSIWYG</h1>
    <?= $wysiwyg; ?>
</div>

Enter fullscreen mode Exit fullscreen mode

๐Ÿงฑ Choice: True-False

Direct link to code

The view:
Image description

The code:

<?php 

// True False Field
// https://www.advancedcustomfields.com/resources/true-false/

$boolean = get_field('true-false');

$booleanAsString = $boolean ? 'true' : 'false';
$content = $boolean ? get_field('text') : 'No content. Content set to false';

$additionalClasses = !empty($block['className']) ? $block['className'] : 'no-classes-added';
?>

<div class="outline outline-4 outline-purple-500 py-4 my-4 <?= $additionalClasses; ?>">
    <h1 class="text-4xl underline pb-4">ACF-Choice/True False With Text</h1>
    <p>Test boolean: <?= $booleanAsString; ?></p>
    <p><?= $content; ?></p>
</div>
Enter fullscreen mode Exit fullscreen mode

๐Ÿงฑ Relational: Link

Direct link to code

The view:
What I like about this ACF field is that it still uses native WordPress features.

Image description
The code:

<?php 

// Link Field
// https://www.advancedcustomfields.com/resources/link/

$link = get_field('link');
$fullLink = '';

if ( $link ) {
    $link_url = $link['url'];
    $link_title = $link['title'];
    $link_target = $link['target'] ? $link['target'] : '_self';

    $fullLink = "<a href='$link_url' target='$link_target'>$link_title</a>";
}

$additionalClasses = !empty($block['className']) ? $block['className'] : 'no-classes-added';
?>

<div class="outline outline-4 outline-orange-500 py-4 my-4 <?= $additionalClasses; ?>">
    <h1 class="text-4xl underline pb-4">ACF-relational/Link</h1>
    <p>Test Link: <?= $fullLink; ?></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Hidden Attributes

Tucked away inside all WP Blocks is a $block.

All data within the Editor screen can be accessible from this $block array.

It looks like this:

Array
(
    [render_template] => template.php
    // ... 
    [supports] => Array
        (
            [align] => 1
            [html] => 
            [mode] => 1
            [jsx] => 1
            [anchor] => 1
            [ariaLabel] => 1
            [color] => Array
                (
                    [background] => 1
                    [gradients] => 1
                    [link] => 1
                    [text] => 1
                )

            [position] => Array
                (
                    [sticky] => 1
                )

            [spacing] => Array
                (
                    [margin] => 1
                    [padding] => 1
                    [blockGap] => 1
                )

            [typography] => Array
                (
                    [fontSize] => 1
                    [lineHeight] => 1
                )

        )
    [acf_block_version] => 2
    [api_version] => 3
    [title] => ACF Block Json Basic: Text with Block Supports
    [category] => acf-block-json
    [icon] => welcome-write-blog
    [mode] => preview
    [name] => acf-block-json/text-with-block-supports
    [data] => Array
        (
            [text] => Test Block.
            [_text] => field_64a8ebaf28669
        )
    [align] => 
    [backgroundColor] => vivid-red
    [textColor] => luminous-vivid-amber
    [fontSize] => x-large
    [id] => block_6be9f1b1aa3b7a2d677a19b71715d58c
)
Enter fullscreen mode Exit fullscreen mode

For example, if you wanted to add anchor IDs to your element, you can do:

?> <div id="<?= $block['id']; ?>">
Enter fullscreen mode Exit fullscreen mode

The Supports Documentation

Your block.json may look like this:

{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "acf-block-json/text-with-block-supports",
    "title": "ACF Block Json Basic: Text with Block Supports",
    "category": "acf-block-json",
    "icon": "welcome-write-blog",
    "version": "1.0.0",
    "acf": {
        "mode": "preview",
        "renderTemplate": "template.php"
    },
    "supports": {
        "anchor": true,
        "align": true,
        "color": {
            "background": true,
            "text": true
        }, 
        "typography": {
            "fontSize": true
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In the supports, you may notice anchor, align, color, and typography.

This is where the future of WordPress is headed.

Block Supports API documentation

This gives us native Wordpress Block features.

๐Ÿ“ Example of Block Supports

Direct link to code

The view:

The sidebar with Color & Typography? Native Block API! ๐Ÿ†
Image description

The code:

<?php

$text = esc_html(get_field('text'));

// SUPPORT OPTIONS
// == Anchor (anchor: true) ==
//  This gives you a anchor ID. <a id="anchor-id" href="https://example.com">Link</a>
$anchorID = $block['anchor'] ?: $block['id'];

// == Align (align: true) ==
//  This determines alignment. 
//  NOTE: On the WP Editor, it's a bit buggy. 
$alignSupport = "text-align: " . $block['align'] . ";" ?: '';

// == Color [background, text] == 
//  Two types of values. Named values vs custom values.
//  Named values have a class: <div class="has-vivid-green-cyan-background-color"></div>
//  Custom values are style injected: <div style="background-color:#ffffff;"></div>
$backgroundColorNamed = ($block['backgroundColor']) ? "has-" . $block['backgroundColor'] . "-background-color" : '';
$backgroundColorCustom = ($block['style']['color']['background']) ? "background-color:" . $block['style']['color']['background'] . ";": '';

$textColorNamed = ($block['textColor']) ? "has-" . $block['textColor'] . "-color" : '';
$textColorCustom = ($block['style']['color']['text']) ? "color:" . $block['style']['color']['text'] . ";": '';

// == Typography == 
//  Two types of values. Named values vs custom values.
//  Named values have a class: <div class="has-x-large-font-size"></div>
//  Custom values are style injected: <div style="font-size: 1.9em;"></div>

$fontSizeNamed = ($block['fontSize']) ? "has-" . $block['fontSize'] . "-font-size" : '';
$fontSizeCustom = ($block['style']['typography']['fontSize']) ? "font-size:" . $block['style']['typography']['fontSize'] . ";": '';

// == AdditionalClasses (true) == 
// Default is true. This allows you to add classes from the editor side
$additionalClasses .= !empty($block['className']) ? $block['className'] : ' no-classes-added';

// FRONTEND
$additionalStyles .= "$backgroundColorCustom $textColorCustom $fontSizeCustom $alignSupport ";
$additionalClasses .= "$backgroundColorNamed $textColorNamed $fontSizeNamed ";
$addAnchorID = "id=$anchorID";
?>

<div <?= $addAnchorID;?> class="outline outline-4 outline-blue-500 py-4 my-4 <?= $additionalClasses; ?>" style="<?= $additionalStyles; ?>">
    <h1 class="text-4xl underline pb-4">ACF-basic/Text</h1>
    <p>Text: <?= $text; ?></p>
</div>
Enter fullscreen mode Exit fullscreen mode

Native Support vs ACF Versions

You might see some overlapping between native Block API supports like Block API Color Picker for background and text and ACF Fields like ACF Color Picker. Which one do you choose?

Honestly, hard to say. It DEPENDS.

For example:

The Block API Color Picker is much more 'aligned' with Modern Wordpress, versus the ACF version.

Where the Block API Align doesn't seem to work very well with ACF Blocks, and I rather recreate a radio field that does it better.

If possible, I'd personally choose native Block API support as much as I can.


Finally

This was a long post. It's the result of my weekend of experimenting and building WP blocks with ACF 6. Use the Advanced Custom Fields 6 + Blocks.json repo for more code examples.

Huge shoutout to Advanced Custom Fields team for their hard work in getting ACF and the Block API working nicely together. As well as the WordPress team in really improving the Editor experience.

Also a huge shoutout to Register ACF Blocks - joeyfarruggio.com for the inspiration for this post.

Top comments (1)

Collapse
 
wordpressure profile image
TricaExMachina

This is really, really great. Thanks for the write up and especially the repo!