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.
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!
(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
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"
}
}
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.
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.
๐ The ACF metadata
{
//...
"acf": {
"mode": "preview", // preview, edit, auto
"renderTemplate": "template.php"
}
}
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
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>
๐งฑ 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
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 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>
๐งฑ 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.)
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>
๐งฑ Choice: True-False
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>
๐งฑ Relational: Link
The view:
What I like about this ACF field is that it still uses native WordPress features.
<?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:
?> <div id="<?= $block['id']; ?>">
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
}
}
}
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
The view:
The sidebar with Color & Typography? Native Block API! ๐
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>
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)
This is really, really great. Thanks for the write up and especially the repo!