ACF Builder (Island Pattern)
The ACF_Builder class is the core of how we define ACF fields in the Terra Framework. Instead of writing large ACF JSON exports or manually registering fields, we compose them from small, reusable “islands” — static methods that each return a single field configuration.
This pattern is inspired by the Sanity.io schema approach and is used across Flexible Content modules, Options Pages, Post Type Fields, and Custom Blocks.
Key Features
Section titled “Key Features”- Atomic fields: Each method returns one field config, ready to compose
- Composable: Combine fields with
array_merge()— no nesting complexity - Consistent defaults: Every field comes with sensible defaults you can override
- Conditional logic: Built-in
show_whenshortcut for field visibility - Deterministic keys: Field keys are generated with
md5(), not random — safe for migrations
How It Works
Section titled “How It Works”Each static method returns a single-element array. You compose them together:
<?php'fields' => array_merge( ACF_Builder::spacing(), ACF_Builder::bg_color(), ACF_Builder::title(['name' => 'heading']), ACF_Builder::wysiwyg(['name' => 'description', 'toolbar' => 'basic']), ACF_Builder::image(['name' => 'photo']), ACF_Builder::link(['name' => 'cta_button']),)Every method accepts an optional $args array to override defaults like name, label, width, etc.
Available Islands
Section titled “Available Islands”Layout Fields
Section titled “Layout Fields”These are used in almost every module to control spacing and background:
<?php// Section spacing (top/bottom padding)ACF_Builder::spacing()
// Background color selector (visual color swatches)ACF_Builder::bg_color()ACF_Builder::bg_color(['palette' => 'white-ebony'])
// Convenience: spacing + bg_color togetherACF_Builder::section_base()Text Fields
Section titled “Text Fields”<?phpACF_Builder::title() // Single-line text (name: 'title')ACF_Builder::title(['name' => 'heading', 'label' => 'Heading'])ACF_Builder::subtitle() // Single-line text (name: 'subtitle')ACF_Builder::pretitle() // Single-line text (name: 'pretitle')ACF_Builder::text() // Textarea (name: 'text')ACF_Builder::text(['name' => 'description', 'rows' => 3])ACF_Builder::wysiwyg() // Rich text editor (name: 'content')ACF_Builder::wysiwyg(['toolbar' => 'basic', 'media_upload' => 0])Media Fields
Section titled “Media Fields”<?phpACF_Builder::image() // Image upload (name: 'image')ACF_Builder::image(['name' => 'icon', 'label' => 'Icon'])ACF_Builder::file() // File upload (name: 'file')ACF_Builder::url(['name' => 'video_url']) // URL fieldInteractive Fields
Section titled “Interactive Fields”<?phpACF_Builder::link() // Link/button (name: 'button')ACF_Builder::boolean(['name' => 'show_cta']) // True/false toggleACF_Builder::select([ // Dropdown 'name' => 'layout', 'choices' => ['left' => 'Left', 'right' => 'Right'],])ACF_Builder::number(['name' => 'columns', 'min' => 1, 'max' => 6])ACF_Builder::date(['name' => 'event_date']) // Date pickerACF_Builder::taxonomy(['name' => 'topic', 'taxonomy' => 'resource-topic'])ACF_Builder::geolocation() // Google MapsComplex Fields
Section titled “Complex Fields”<?php// Repeater: list of items with sub-fieldsACF_Builder::repeater([ 'name' => 'cards', 'label' => 'Cards', 'fields' => array_merge( ACF_Builder::title(['name' => 'card_title']), ACF_Builder::text(['name' => 'card_description']), ACF_Builder::image(['name' => 'card_image']), ),])
// Relationship: select existing postsACF_Builder::relationship([ 'name' => 'related_resources', 'post_type' => ['resource'], 'max' => 3,])
// Group: groups fields visually (no repeating)ACF_Builder::group([ 'name' => 'cta_settings', 'fields' => array_merge( ACF_Builder::title(['name' => 'cta_text']), ACF_Builder::url(['name' => 'cta_url']), ),])UI Helpers
Section titled “UI Helpers”<?php// Tab separator in the adminACF_Builder::tab(['label' => 'Content'])ACF_Builder::tab(['label' => 'Settings'])
// Read-only message/note for editorsACF_Builder::note(['message' => 'Keep the title under 60 characters for SEO.'])Conditional Logic (show_when)
Section titled “Conditional Logic (show_when)”Any island accepts a show_when parameter to conditionally show/hide the field based on another field’s value:
<?phpACF_Builder::boolean(['name' => 'enable_button', 'label' => 'Show Button?']),ACF_Builder::link([ 'name' => 'button', 'show_when' => ['enable_button', '==', '1'],]),The framework automatically resolves show_when to ACF’s conditional_logic format at registration time — you never need to deal with field keys manually.
Full Module Example
Section titled “Full Module Example”Here’s how a complete flexible content module uses the ACF Builder:
<?phpreturn array( 'label' => 'Image + Text', 'fields' => array_merge( ACF_Builder::spacing(), ACF_Builder::bg_color(['palette' => 'default']), ACF_Builder::pretitle(), ACF_Builder::title(['name' => 'heading']), ACF_Builder::wysiwyg(['name' => 'content', 'toolbar' => 'basic']), ACF_Builder::image(['name' => 'side_image']), ACF_Builder::select([ 'name' => 'image_position', 'label' => 'Image Position', 'choices' => ['left' => 'Left', 'right' => 'Right'], ]), ACF_Builder::boolean(['name' => 'show_button', 'label' => 'Show Button?']), ACF_Builder::link([ 'name' => 'button', 'show_when' => ['show_button', '==', '1'], ]), ),);Overridable Parameters
Section titled “Overridable Parameters”Every island accepts these common parameters via the $args array:
| Parameter | Description |
|---|---|
name | Field name (used in get_field()) |
label | Display label in the admin |
width | Wrapper width percentage (e.g., '50' for half-width) |
show_when | Conditional visibility: ['field_name', '==', 'value'] |
required | Whether the field is required (1 or 0) |
instructions | Help text shown below the label |
wrapper | Custom wrapper attributes (class, id) |
Plus type-specific parameters like rows, toolbar, choices, min, max, return_format, etc.
Knowledge Check
Test your understanding of this section
Loading questions...