Blog/WordPress ACF Block Migration
WordPressPerformanceDevelopment10 min read

Modernizing Legacy WordPress: Converting Heavy Page Builders into Custom ACF Gutenberg Blocks

If you manage client WordPress sites built between 2015 and 2022, legacy page builders like Elementor, Divi, and WPBakery drag down performance and Core Web Vitals. Here is the engineering roadmap to migrate them into lean, native ACF Gutenberg blocks.
WordPress Gutenberg block editor with custom ACF blocks

If you manage or maintain client WordPress sites built between 2015 and 2022, you know the pain of heavy legacy page builders like Elementor, Divi, or WPBakery. While these visual builders made page layout accessible years ago, they now drag down modern site performance, inflate page sizes with nested <div> wrappers, and slow down editing workflows.

With Google's strict Core Web Vitals enforcement, legacy page builder bloat is no longer just a developer annoyance—it directly degrades organic search rankings and conversion rates.

Converting a bloated legacy page builder site into native Custom Advanced Custom Fields (ACF) Gutenberg Blocks restores lightning-fast performance, cleans up the codebase, and provides a streamlined editing experience for content teams.

Here is the step-by-step engineering roadmap to execute this migration cleanly.

The Legacy Page Builder Problem

Legacy visual builders rely on shortcodes or deep JSON arrays stored in wp_posts.post_content. To render a basic two-column section, these engines inject dozens of DOM nodes, external CSS stylesheets, and heavy JavaScript frameworks.

Legacy Builder: [section][row][column][wrapper][text] Content [/text][/wrapper][/column][/row][/section]
Native Gutenberg: <!-- wp:acf/custom-card {...} --> <div class="card">Content</div> <!-- /wp:acf/custom-card -->

The Architectural Upgrade Comparison

Metric / AspectLegacy Builder (Elementor/Divi)Custom ACF Blocks
DOM Depth10–20 nested wrapper divs per sectionClean, semantic HTML (3–5 divs)
CSS/JS FootprintLoads global builder CSS/JS on every pageEnqueues asset files only when the block is rendered
Editing ExperienceSlow preview canvas, fragile drag-and-dropStructured, locked-down form fields in native WordPress editor
Page Speed ImpactHeavy DOM size, poor LCP / CLS scoresMinimal DOM size, high Core Web Vitals scores

1. Audit and Map Legacy Design Components

Before touching any code, inventory the site's existing design patterns. Pages built with drag-and-drop builders often look inconsistent because editors tweaked margins and fonts on individual pages over time.

  1. Identify Repeating UI Patterns: Group page layouts into 6 to 12 core reusable component types (e.g., Hero Header, Feature Grid, Testimonial Slider, Call to Action Banner, Pricing Table).
  2. Define Field Schemas: For each block component, list the required content fields:
    • Hero Block: Title (Text), Subtitle (Textarea), Primary CTA (Link Picker), Background Image (Image Upload).
    • Feature Grid Block: Section Header (Text), Features (Repeater: Icon, Title, Description).
  3. Establish Design Tokens: Standardize spacing, typography classes, and color palettes in your primary stylesheet so individual blocks don't require inline styling.

2. Register Custom ACF Blocks Native to Gutenberg

ACF Pro allows developers to register custom Gutenberg blocks directly through PHP using acf_register_block_type() or the modern block.json standard—without needing complex React compilation setups.

Step A: Register the Block (block.json)

Create a dedicated folder for your block inside your theme: /blocks/hero-banner/block.json.

{
  "name": "acf/hero-banner",
  "title": "Hero Banner",
  "description": "Custom high-performance hero section.",
  "category": "formatting",
  "icon": "superhero",
  "keywords": ["hero", "banner", "header"],
  "acf": {
    "mode": "preview",
    "renderTemplate": "template.php"
  },
  "supports": {
    "anchor": true,
    "align": false
  }
}

Step B: Register the Block in PHP

In your theme's functions.php, register the block folder:

add_action('init', 'register_custom_acf_blocks');
function register_custom_acf_blocks() {
    register_block_type( __DIR__ . '/blocks/hero-banner' );
}

3. Build Clean Render Templates & Modular Assets

Create the corresponding template.php file inside /blocks/hero-banner/. This file retrieves field data using standard ACF functions (get_field()) and outputs clean HTML.

<?php
/**
 * Block Name: Hero Banner
 */

$title       = get_field('hero_title');
$subtitle    = get_field('hero_subtitle');
$cta_link    = get_field('hero_cta');
$bg_image_id = get_field('hero_bg_image');

// Render semantic, unbloated HTML
?>
<section class="c-hero-banner">
    <div class="o-container">
        <?php if ($title): ?>
            <h1 class="c-hero-banner__title"><?php echo esc_html($title); ?></h1>
        <?php endif; ?>

        <?php if ($subtitle): ?>
            <p class="c-hero-banner__subtitle"><?php echo esc_html($subtitle); ?></p>
        <?php endif; ?>

        <?php if ($cta_link): ?>
            <a href="<?php echo esc_url($cta_link['url']); ?>" class="c-btn c-btn--primary">
                <?php echo esc_html($cta_link['title']); ?>
            </a>
        <?php endif; ?>
    </div>
</section>

Asset Conditional Loading

Unlike page builders that load mega-stylesheets on every page, enqueue block-specific CSS only when the block appears on the page:

wp_enqueue_script(
    'hero-banner-js',
    get_template_directory_uri() . '/blocks/hero-banner/script.js',
    array(),
    '1.0.0',
    true
);

4. Migrate Content and Clean the Database

Once your custom blocks are built, convert old page content to the new block format.

  • Option A: Manual Migration (Best for High-Value Pages): For core pages (Homepage, Services, Pricing), rebuild the page using the newly created ACF blocks. Copy content out of the old builder fields into the structured ACF fields. This guarantees perfect formatting and removes legacy CSS classes.
  • Option B: Programmatic Parsing (Best for Large Sites / Blogs): For sites with hundreds of pages built in WPBakery or Divi, write a WP-CLI script or PHP migration tool to regex-match legacy shortcodes and map their content into native block markup before saving back to post_content.
  • Database Cleanup: Once content is migrated, deactivate and remove the legacy page builder plugin. Run database optimization tools or SQL queries to delete legacy shortcodes, orphan post meta, and transient options left behind by the builder.

Migration Checklist

  1. Audit component patterns: Group legacy designs into 6 to 12 core reusable block specs.
  2. Configure field groups: Build structured ACF field groups mapped to each component.
  3. Register native blocks: Use block.json and PHP templates for clean HTML rendering.
  4. Enqueue assets modularly: Load CSS and JS conditionally based on active blocks on the page.
  5. Migrate content & strip builder: Swap legacy shortcodes for ACF blocks, then deactivate the page builder plugin.

If you have a complex enterprise WordPress site plagued by page-builder bloat, low Core Web Vitals scores, or slow editor workflows, visit austin-web-services.com to review our custom theme engineering and block migration services.

Frequently Asked Questions

Is it worth migrating from Elementor to Gutenberg blocks for a small site?
Yes, even for small sites the performance gains are measurable. A typical Elementor page loads 200–400 KB of builder CSS and JavaScript on every page, even pages that use almost no builder features. Removing that overhead with native blocks improves LCP scores by 20–40% in most cases. For small sites with fewer than 20 pages, manual migration is usually the fastest approach.
Do I need ACF Pro to build custom Gutenberg blocks?
Yes, the ACF block registration feature requires ACF Pro. The free version of ACF does not support the acf_register_block_type() or block.json workflow. If you are already running ACF Pro on the client site, there is no additional licensing cost.
Can I mix legacy page builder content with new ACF blocks during migration?
Yes. Gutenberg and legacy shortcodes coexist in post_content. You can migrate page by page, keeping old builder content on low-traffic pages while rebuilding high-value pages with ACF blocks. Once all pages are converted, deactivate the legacy builder plugin and run database cleanup.
Will the block.json approach work with any WordPress theme?
block.json-based custom blocks work with any theme that calls the_content() or the Block Editor. However, your blocks will inherit theme styling. For best results, pair custom blocks with a custom or child theme where you control the full stylesheet. Blocks built with block.json are also compatible with FSE (Full Site Editing) themes.
What about dynamic blocks that need JavaScript on the front end?
ACF blocks support both static (PHP-rendered) and dynamic (JavaScript-enhanced) templates. For things like sliders, accordions, or interactive maps, enqueue a lightweight JavaScript file only when that specific block is present on the page. This is far more efficient than page builders that load their entire JS framework globally.

Ready to Break Free From Page Builder Bloat?

Our Austin team specializes in migrating legacy WordPress sites to custom ACF Gutenberg blocks. We handle the audit, block development, content migration, and database cleanup so your site loads fast and ranks higher.