Modern Wordpress for PHP Devs using ACF 6 + block.json (Super post)
Tags: wordpress, acf, blocks
Published: 2023-07-09 21:32:37

---
title: Modern Wordpress for PHP Devs using ACF 6 + block.json (Super post)
published: true
description: Advanced Custom Fields 6 now works more seamlessly with WordPress Blocks. This is a long post explaining how to use the latest ACF 6 with the block.json format that taps into the Blocks API. 
tags: wordpress, acf, blocks
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iat96flap6v73fl5mmd4.png
# Use a ratio of 100:42 for best results.
# published_at: 2023-07-09 18:37 +0000
---

[Advanced Custom Fields(ACF)](https://www.advancedcustomfields.com/) 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](https://fullsiteediting.com/courses/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](https://www.advancedcustomfields.com/), 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2t8alyrygh2e45fcntsp.png)

*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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ldb4bgvfry5kvlz7ewrk.gif)

(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](https://github.com/RockyKev/acf-6-with-block-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](https://github.com/RockyKev/acf-6-with-block-json/archive/refs/heads/main.zip) and import it into your WordPress Themes.  

This theme uses a CDN of [tailwind css](https://tailwindcss.com/) 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](https://www.advancedcustomfields.com/resources/acf-blocks-with-block-json/) 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
```

It looks like this: 

Example: `block.json`
```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" 
    }
}
```

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');

```

Notice that it's following the Block API's recommendation. For all the attributes, visit [Metadata in block.json](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/).

In fact, you'll be using that [Metadata in block.json](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/) 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kmhvxyaya475w4kaww2i.png)

### 📝 The ACF metadata
```json
 {
  //...
 "acf": {
        "mode": "preview", // preview, edit, auto
        "renderTemplate": "template.php" 
    }
}
```

You may notice the `acf` metadata.

There's a few unique fields. [The full list](https://www.advancedcustomfields.com/resources/acf-blocks-with-block-json/#acf-configuration-key).

**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](https://github.com/RockyKev/acf-6-with-block-json) for working examples of other WP Blocks.



### 🧱 Basic: Text Field

The easiest field to work with is the Text Field. [Direct link to code](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-basic/text)

**The view:**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ojvtfhli2tufd24vpqpb.png)

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

**The code:**
```php 
<?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>
```

### 🧱 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](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-choice/button-group-with-text)


**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
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lmtu80trwfikm72vleaa.png)

**The Code**
```php 
<?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>
```

### 🧱 Content: WYSIWYG

[Direct link to code](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-content/wysiwyg)

**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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/it1i4bcm19502ft5zlv4.png)

**The code:**
```php 
<?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>

```

### 🧱 Choice: True-False

[Direct link to code](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-choice/true-false-with-text)

**The view:**
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9jk9o8l6i6bhl8ekblju.png)

**The code:**
```php 
<?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>
```

### 🧱 Relational: Link

[Direct link to code](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-relational)

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

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ultioqxn5b6bm7r70j5r.png)
**The code:**
```php 
<?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>
```

---
## 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
)
```

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

```php 
?> <div id="<?= $block['id']; ?>">
```

---
## The Supports Documentation

Your block.json may look like this:

```json
{
    "$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
        }
    }
}
```
In the `supports`, you may notice `anchor`, `align`, `color`, and `typography`. 

This is where the future of WordPress is headed. 

[Block Supports API documentation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/)

This gives us native Wordpress Block features.

### 📝 Example of Block Supports

[Direct link to code](https://github.com/RockyKev/acf-6-with-block-json/tree/main/blocks/acf-basic/text-with-support)

**The view:**

The sidebar with Color & Typography? Native Block API! 🏆
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5yrklyemg72r6ntvyr52.png)

**The code:**
```php 
<?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>
```

---
## Native Support vs ACF Versions

You might see some overlapping between native Block API supports like [Block API Color Picker for background and text](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color) and ACF Fields like [ACF Color Picker](https://www.advancedcustomfields.com/resources/color-picker/). Which one do you choose?

Honestly, hard to say. It DEPENDS.

For example:

[The Block API Color Picker](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#color) is much more 'aligned' with Modern Wordpress, versus the [ACF version](https://www.advancedcustomfields.com/resources/color-picker/).


Where the [Block API Align](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-supports/#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](https://github.com/RockyKev/acf-6-with-block-json/) 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](https://joeyfarruggio.com/wordress/register-acf-blocks/#register-block) for the inspiration for this post.