Creating Blocks
Deodar supports two types of blocks: ACF provider blocks and Core provider blocks. This guide will show you how to create both types and understand when to use each approach. To modify core or other provider blocks check out Working with Non ACF Blocks
Block Types Overview
ACF Provider Blocks
- Use Case: Blocks that require custom fields and complex data
- Features: ACF Pro integration, custom field management, advanced data handling
- Location:
blocks/acf/directory - Files:
block.json,{block-name}.php,block.scss,block.js(optional)
ACF Provider Blocks
Creating an ACF Block
Method 1: Using the CLI Tool (Recommended)
# Navigate to your project directory
cd your-project
# Create a new block
deodar new hero-section
# Follow the interactive prompts:
# - Block name: hero-section
# - Display title: Hero Section
# - Category: design
# - Include JavaScript: yes
Method 2: Manual Creation
-
Create Block Directory
blocks/acf/hero-section/ -
Create block.json
{
"name": "your-project/hero-section",
"title": "Hero Section",
"description": "A hero section block with custom fields",
"style": ["file:./build/hero-section.css"],
"category": "design",
"icon": "admin-comments",
"keywords": ["hero", "banner", "header"],
"acf": {
"mode": "preview",
"renderTemplate": "hero-section.php"
},
"supports": {
"anchor": true
}
} -
Create hero-section.php
<?php
$title = get_field('title') ?: 'Default Title';
$subtitle = get_field('subtitle') ?: 'Default Subtitle';
$background_image = get_field('background_image');
$button_text = get_field('button_text') ?: 'Learn More';
$button_url = get_field('button_url') ?: '#';
?>
<section class="hero-section" <?php if ($background_image): ?>style="background-image: url('<?php echo $background_image['url']; ?>')"<?php endif; ?>>
<div class="hero-section__content">
<h1 class="hero-section__title"><?php echo esc_html($title); ?></h1>
<p class="hero-section__subtitle"><?php echo esc_html($subtitle); ?></p>
<a href="<?php echo esc_url($button_url); ?>" class="hero-section__button">
<?php echo esc_html($button_text); ?>
</a>
</div>
</section> -
Create block.scss
.hero-section {
position: relative;
min-height: 500px;
display: flex;
align-items: center;
justify-content: center;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
&__content {
text-align: center;
color: white;
max-width: 800px;
padding: 2rem;
}
&__title {
font-size: 3rem;
margin-bottom: 1rem;
font-weight: 700;
}
&__subtitle {
font-size: 1.25rem;
margin-bottom: 2rem;
opacity: 0.9;
}
&__button {
display: inline-block;
padding: 1rem 2rem;
background-color: #007cba;
color: white;
text-decoration: none;
border-radius: 4px;
font-weight: 600;
transition: background-color 0.3s ease;
&:hover {
background-color: #005a87;
}
}
} -
Create block.js (Optional)
// Hero section JavaScript functionality
document.addEventListener('DOMContentLoaded', function() {
const heroSections = document.querySelectorAll('.hero-section');
heroSections.forEach(section => {
// Add any JavaScript functionality here
console.log('Hero section loaded:', section);
});
});
ACF Field Group Configuration
Create an ACF field group for your block:
- In WordPress Admin: Go to Custom Fields > Field Groups
- Create New Field Group: Name it "Hero Section"
- Add Fields:
- Title (Text)
- Subtitle (Textarea)
- Background Image (Image)
- Button Text (Text)
- Button URL (URL)
- Set Location Rules: Block is equal to Hero Section
- Save and Publish
ACF Block Structure
blocks/acf/hero-section/
├── block.json # Block configuration
├── hero-section.php # PHP template (matches folder basename)
├── block.scss # Stylesheet
├── block.js # JavaScript (optional)
├── hero-section.field-group.json # ACF field group (auto-generated)
└── build/ # Compiled assets (auto-generated)
├── hero-section.build.css
├── hero-section.build.css.map # Development file
├── hero-section.build.js
└── hero-section.build.js.map # Development file
Block Configuration Options
block.json Configuration
| Option | Type | Description |
|---|---|---|
name | string | Block namespace/name (e.g., "your-project/hero-section") |
title | string | Human-readable block title |
description | string | Block description |
category | string | Block category (text, media, design, widgets, theme, custom) |
icon | string | Block icon (Dashicon name) |
keywords | array | Search keywords for the block |
style | array | Stylesheet files |
script | array | JavaScript files |
supports | object | Block supports (anchor, align, etc.) |
acf | object | ACF-specific configuration |
Block Categories
- text: Text-based blocks
- media: Media and image blocks
- design: Layout and design blocks
- widgets: Widget-like blocks
- theme: Theme-specific blocks
- custom: Custom category (specify name)
Block Supports
{
"supports": {
"anchor": true,
"align": ["wide", "full"],
"className": true,
"customClassName": true,
"html": false
}
}
Build Process
Using the CLI Tool
# Development build
deodar development
# Production build
deodar production
# Watch mode for development
deodar watch
Manual Build Process
- SCSS Compilation: SCSS files are compiled to CSS
- JavaScript Bundling: JS files are bundled and minified
- Source Maps: Generated for development debugging
- File Generation: Build files are created in
build/directories
Best Practices
Block Development
- Naming Conventions: Use kebab-case for block names
- File Organization: Keep related files together
- Security: Always escape output in PHP templates
- Performance: Optimize images and assets
- Accessibility: Follow WCAG guidelines
ACF Field Management
- Field Naming: Use descriptive field names
- Field Groups: Organize fields logically
- Validation: Add field validation rules
- Conditional Logic: Use conditional field display
- Default Values: Provide sensible defaults
Styling Guidelines
- CSS Classes: Use BEM methodology
- Responsive Design: Mobile-first approach
- Performance: Minimize CSS specificity
- Consistency: Follow design system patterns
- Browser Support: Test across browsers
Examples
Complete ACF Block Example
// blocks/acf/testimonial/testimonial.php
<?php
$quote = get_field('quote') ?: 'Default testimonial quote';
$author = get_field('author') ?: 'Default Author';
$company = get_field('company') ?: 'Default Company';
$avatar = get_field('avatar');
?>
<div class="testimonial-block">
<blockquote class="testimonial-block__quote">
"<?php echo esc_html($quote); ?>"
</blockquote>
<div class="testimonial-block__author">
<?php if ($avatar): ?>
<img src="<?php echo esc_url($avatar['url']); ?>" alt="<?php echo esc_attr($author); ?>" class="testimonial-block__avatar">
<?php endif; ?>
<div class="testimonial-block__info">
<cite class="testimonial-block__name"><?php echo esc_html($author); ?></cite>
<span class="testimonial-block__company"><?php echo esc_html($company); ?></span>
</div>
</div>
</div>
Troubleshooting
Common Issues
Block Not Appearing
- Check block.json syntax
- Verify file paths
- Ensure ACF Pro is active
- Check WordPress block editor
Styles Not Loading
- Verify SCSS compilation
- Check build process
- Ensure proper file paths
- Check browser console
Fields Not Saving
- Verify ACF field group configuration
- Check location rules
- Ensure proper field names
- Test in different contexts
Next Steps
Now that you can create blocks:
- Working with Non ACF Blocks
- Learn about Post Types
- Explore Taxonomies
- Learn about Production Builds
- Master the CLI Tool
Ready to create amazing blocks? Start with the CLI tool and build something incredible!