ACF Blocks is a lightweight library that provides a clean, object-oriented API to create and render ACF field groups.
Your WordPress code base doesn't have to be a mess.
This library is in beta. Use at your own risk. Contributions are welcome.
ACF Blocks introduces the concept of blocks, which are essentially Controllers (or actually ViewModels) for field groups and flexible layouts. Fields are created using the excellent ACF Builder library.
The three main benefits of using ACF blocks are:
- Speed up development of simple sites,
- Provide a super simple, but clean architecture for developing more complex sites,
- Allow re-using blocks between projects.
composer require codelight/acf-blocks dev-master
If you're still not using Composer in 2018, then do yourself a huge favor and get started now. [todo: article]
As an example, let's go through creating and rendering a simple field group.
<?php
// blocks.php
use Codelight\ACFBlocks\Blocks;
use Codelight\ACFBlocks\BlockType;
add_action('init', function() {
// Create a new block
$imageBlock = new BlockType('example_image');
/**
* Define ACF fields - see https://github.com/StoutLogic/acf-builder
* Add an image field and a wysiwyg field.
* Also add the field group to template-image.php page template
*/
$imageBlock->getFieldsBuilder()
->addImage('awesome_image', ['return_format' => 'id'])
->addWysiwyg('boring_text')
->setLocation('page_template', '==', 'template-image.php');
/**
* Add a function for processing raw ACF data before it's sent to the template.
* This allows you to do additional processing depending on the data and keep your templates clean.
*/
$imageBlock->addCallback(function($data) {
// Return the full image html with srcset attribute generated by wordpress
$data['image'] = wp_get_attachment_image($data['awesome_image'], 'large');
// Split the wysiwyg contents into an excerpt and the full text
$data['excerpt'] = wp_trim_words($data['boring_text'], 25);
$data['text'] = $data['boring_text'];
return $data;
});
// Set the template for this block
$imageBlock->setTemplate('templates/blocks/image.php');
// Register the block with the main block manager class
$blocks = Blocks::getInstance();
$blocks->registerBlock($imageBlock);
}
<?php
// template-image.php
/**
* Template name: Image
*
* This is the page template where we will be rendering our block.
* Calling `blocks()->get()` inside the Loop will return all pre-rendered blocks
* assigned to that specific page or post.
*/
?>
<?php while (have_posts()) : the_post(); ?>
<?php foreach (blocks()->get() as $block): ?>
<?= $block; ?>
<?php endforeach; ?>
<?php endwhile; ?>
<?php
// templates/blocks/image.php
/**
* This is the template of the single block.
* Data is injected automatically.
*/
?>
<section class="section-image">
<?= $image; ?>
<div class="description">
<div class="description-excerpt">
<?= $excerpt; ?>
</div>
<div class="description-full">
<?= $text; ?>
</div>
</div>
</section>
Let's create the same block in a much cleaner way - as a class. This class should be in a separate file called ImageBlock.php. You'll probably want to keep it in a separate folder, which you might want to call 'blocks'.
<?php
use Codelight\ACFBlocks\BlockType;
class ImageBlock extends BlockType {
protected $config = [
// The machine-readable name of the block
'name' => 'example_image';
// The location of the template
'template' => 'templates/blocks/image.php',
];
// This function is called when the block type is initialized for the first time.
// You'll use it mostly to register the fields
public function init()
{
$this->getFieldsBuilder()
->addImage('awesome_image', ['return_format' => 'id'])
->addWysiwyg('boring_text')
->setLocation('page_template', '==', 'template-image.php');
}
// This function works in a similar way to addCallback() - it allows you to
// modify the data that's passed into the template
public function filterData($data)
{
// Return the full image html with srcset attribute generated by wordpress
$data['image'] = wp_get_attachment_image($data['awesome_image'], 'large');
// Split the wysiwyg contents into an excerpt and the full text
$data['excerpt'] = wp_trim_words($data['boring_text'], 25);
$data['text'] = $data['boring_text'];
return $data;
}
}
We'll also need to register the block we just created. This goes into your functions.php (or equivalent):
<?php
require_once('blocks/ImageBlock.php');
add_action('init', function() {
$blocks = Blocks::getInstance();
$blocks->init([
'blocktypes' => [
// array of block class names as strings
'ImageBlock',
]
]);
});
And that's it. You'll also need to add the templates as in the previous example.
Let's continue the previous example, but register the ImageBlock as a Flexible Content layout.
First, we'll need to create the Flexible Content block which will contain our ImageBlock.
<?php
use Codelight\ACFBlocks\FlexibleContentBlockType;
class FlexibleBlock extends FlexibleContentBlockType
{
protected $config = [
// The machine-readable name of the block
'name' => 'flexible_block',
// The location of the template
'template' => 'blocks.content-builder',
];
public function init()
{
$this->getFieldsBuilder()
->setGroupConfig('title', 'Content Blocks')
->setLocation('post_type', '==', 'page');
// This registers our ImageBlock as a child block of this flexible content layout
$this->registerBlockType('ImageBlock');
}
}
This flexible content block works exactly as any other block. To register it, modify the code you previously added to your functions.php (or equivalent) as follows:
<?php
require_once('blocks/ImageBlock.php');
require_once('blocks/FlexibleBlock.php');
add_action('init', function() {
$blocks = Blocks::getInstance();
$blocks->init([
'blocktypes' => [
// array of block class names as strings
'ImageBlock',
'FlexibleBlock',
]
]);
});
Now, you will have a flexible content area on every Page where you can add the ImageBlock. Note that the ImageBlock will still be added to template-image.php as a regular (non-flexible-layout) block as well. The ImageBlock will use the same template in both cases. This provides an easy way to re-use blocks between templates, flexible content areas and even projects. It's also possible to use a different template in different situations (e.g. flexible layout vs regular page context), whilst keeping the backend code of the block the same.
One obvious answer is that once you get the general idea, it's about 10x faster compared to writing all the annoying template code by hand. However, the actual main advantage of using ACF Blocks is that it makes you architect things in one specific, clean, flexible and modular way. You now have a really good way to separate your templates and functionality. You can re-use and extend ACF field groups and blocks. You always know where to find your code. This approach speeds up the development of smaller projects but it really shines in the context of massive sites where you have lots of different fields and field groups.
todo: add more complex examples.
Will using this library have an impact on performance?
No, it's just a really thin layer of abstraction. It doesn't do much, it just allows you to write better code.
I'm using soberwp/controller which already provides me with a Controller. Why should I use this library?
The concept behind soberwp/controller is great, but it doesn't have much use in the context of flexible layouts.