DEV Community

Cover image for WordPress Page Builder Automation: Generate Layouts via Scripts
Martijn Assie
Martijn Assie

Posted on

WordPress Page Builder Automation: Generate Layouts via Scripts

Client wants: 50 landing pages with same layout, different cities

Manual method: 50 × 15 minutes = 12.5 hours clicking in Elementor!!

My response: "Give me 45 minutes to write a script"

Result:

  • Script runs: 3 minutes
  • 50 pages created: Identical layouts, unique content
  • JSON config drives everything
  • Zero clicking!!

Here's how to automate page builder layout generation programmatically:

Why Automate Page Builder Layouts?

Manual page building SUCKS when:

  • Creating 50+ similar pages (locations, products, services)
  • Client wants consistent layouts across all pages
  • Content changes frequently but structure stays same
  • Testing A/B variations of layouts
  • Migrating layouts between sites

Automation = sanity!!

Architecture: JSON Config → Script → Page Builder

Three components:

  1. JSON configuration (layout structure + content variables)
  2. PHP script (reads JSON, generates page builder meta)
  3. WP-CLI command (creates pages programmatically)

Workflow:

cities.json → automation-script.php → wp-cli → 50 pages created
Enter fullscreen mode Exit fullscreen mode

Supported Page Builders

This technique works with:

  • Elementor (stores layouts in postmeta _elementor_data)
  • Divi (stores layouts in _et_pb_page_layout)
  • Beaver Builder (stores layouts in _fl_builder_data)
  • WPBakery (stores layouts as shortcodes in post_content)
  • Oxygen (stores layouts in postmeta ct_builder_shortcodes)

Key insight: All page builders store layouts as JSON or shortcodes in database!!

Example 1: Elementor Automation

Step 1: Export Template as JSON

Create one perfect page manually in Elementor

Export template:

Elementor → Tools → Export Template
Enter fullscreen mode Exit fullscreen mode

Saved as: template.json

Structure:

{
  "content": [
    {
      "id": "abc123",
      "elType": "section",
      "elements": [
        {
          "elType": "column",
          "elements": [
            {
              "elType": "widget",
              "widgetType": "heading",
              "settings": {
                "title": "{{CITY_NAME}} Services"
              }
            }
          ]
        }
      ]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Step 2: Create City Data JSON

File: cities.json

[
  {
    "city": "Chicago",
    "state": "IL",
    "zip": "60601",
    "phone": "(312) 555-0100"
  },
  {
    "city": "Boston",
    "state": "MA",
    "zip": "02108",
    "phone": "(617) 555-0200"
  },
  {
    "city": "Seattle",
    "state": "WA",
    "zip": "98101",
    "phone": "(206) 555-0300"
  }
]
Enter fullscreen mode Exit fullscreen mode

Step 3: PHP Automation Script

File: generate-elementor-pages.php

<?php
/**
 * Elementor Page Generator
 * Usage: php generate-elementor-pages.php
 */

// Load WordPress
require_once('/path/to/wp-load.php');

// Load data
$template = json_decode(file_get_contents('template.json'), true);
$cities = json_decode(file_get_contents('cities.json'), true);

foreach ($cities as $city) {
    // Replace placeholders in template
    $layout = replace_placeholders($template, [
        '{{CITY_NAME}}' => $city['city'],
        '{{STATE}}' => $city['state'],
        '{{ZIP}}' => $city['zip'],
        '{{PHONE}}' => $city['phone']
    ]);

    // Create page
    $page_id = wp_insert_post([
        'post_title'   => $city['city'] . ' Services',
        'post_status'  => 'publish',
        'post_type'    => 'page',
        'post_content' => '' // Elementor uses meta, not content
    ]);

    if (!is_wp_error($page_id)) {
        // Save Elementor data
        update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($layout['content'])));
        update_post_meta($page_id, '_elementor_edit_mode', 'builder');
        update_post_meta($page_id, '_elementor_template_type', 'wp-page');
        update_post_meta($page_id, '_elementor_version', '3.16.0');

        echo "✅ Created: {$city['city']} (ID: {$page_id})\n";
    }
}

function replace_placeholders($data, $replacements) {
    $json = json_encode($data);

    foreach ($replacements as $placeholder => $value) {
        $json = str_replace($placeholder, $value, $json);
    }

    return json_decode($json, true);
}

echo "\n✨ Generation complete!\n";
Enter fullscreen mode Exit fullscreen mode

Step 4: Run Script

php generate-elementor-pages.php
Enter fullscreen mode Exit fullscreen mode

Output:

✅ Created: Chicago (ID: 123)
✅ Created: Boston (ID: 124)
✅ Created: Seattle (ID: 125)

✨ Generation complete!
Enter fullscreen mode Exit fullscreen mode

3 pages created in seconds!!

Example 2: Divi Layout Automation

Divi Storage Format

Divi stores layouts as JSON in _et_pb_page_layout postmeta

Sample Divi JSON:

[
  {
    "type": "et_pb_section",
    "attrs": {
      "background_color": "#ffffff"
    },
    "content": [
      {
        "type": "et_pb_row",
        "content": [
          {
            "type": "et_pb_column",
            "content": [
              {
                "type": "et_pb_text",
                "attrs": {
                  "content": "<h1>{{CITY_NAME}} Professional Services</h1>"
                }
              }
            ]
          }
        ]
      }
    ]
  }
]
Enter fullscreen mode Exit fullscreen mode

Divi Automation Script

<?php
require_once('/path/to/wp-load.php');

$template = json_decode(file_get_contents('divi-template.json'), true);
$cities = json_decode(file_get_contents('cities.json'), true);

foreach ($cities as $city) {
    $layout = replace_placeholders($template, [
        '{{CITY_NAME}}' => $city['city'],
        '{{STATE}}' => $city['state']
    ]);

    $page_id = wp_insert_post([
        'post_title'   => $city['city'] . ' Services',
        'post_status'  => 'publish',
        'post_type'    => 'page'
    ]);

    if (!is_wp_error($page_id)) {
        // Divi-specific meta
        update_post_meta($page_id, '_et_pb_use_builder', 'on');
        update_post_meta($page_id, '_et_pb_page_layout', wp_slash(json_encode($layout)));
        update_post_meta($page_id, '_et_pb_old_content', '');

        echo "✅ Divi page: {$city['city']}\n";
    }
}
Enter fullscreen mode Exit fullscreen mode

Example 3: WP-CLI Integration

Create WP-CLI Command

File: wp-content/mu-plugins/page-generator.php

<?php
/**
 * Plugin Name: Page Generator CLI
 */

if (defined('WP_CLI') && WP_CLI) {
    WP_CLI::add_command('generate pages', 'Page_Generator_CLI');
}

class Page_Generator_CLI {

    /**
     * Generate pages from template
     * 
     * ## OPTIONS
     * 
     * --template=<file>
     * : Template JSON file
     * 
     * --data=<file>
     * : Data JSON file
     * 
     * --builder=<name>
     * : Page builder (elementor|divi|beaver)
     * 
     * ## EXAMPLES
     * 
     *     wp generate pages --template=template.json --data=cities.json --builder=elementor
     */
    public function __invoke($args, $assoc_args) {
        $template_file = $assoc_args['template'];
        $data_file = $assoc_args['data'];
        $builder = $assoc_args['builder'];

        if (!file_exists($template_file)) {
            WP_CLI::error("Template file not found: {$template_file}");
        }

        if (!file_exists($data_file)) {
            WP_CLI::error("Data file not found: {$data_file}");
        }

        $template = json_decode(file_get_contents($template_file), true);
        $data = json_decode(file_get_contents($data_file), true);

        $generated = 0;

        foreach ($data as $item) {
            $page_id = $this->create_page($template, $item, $builder);

            if ($page_id) {
                WP_CLI::success("Created page ID {$page_id}: {$item['city']}");
                $generated++;
            }
        }

        WP_CLI::success("Generated {$generated} pages!");
    }

    private function create_page($template, $data, $builder) {
        // Replace placeholders
        $layout = $this->replace_placeholders($template, $data);

        // Create page
        $page_id = wp_insert_post([
            'post_title'   => $data['city'] . ' Services',
            'post_status'  => 'publish',
            'post_type'    => 'page'
        ]);

        if (is_wp_error($page_id)) {
            return false;
        }

        // Save builder-specific meta
        switch ($builder) {
            case 'elementor':
                update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($layout)));
                update_post_meta($page_id, '_elementor_edit_mode', 'builder');
                break;

            case 'divi':
                update_post_meta($page_id, '_et_pb_use_builder', 'on');
                update_post_meta($page_id, '_et_pb_page_layout', wp_slash(json_encode($layout)));
                break;

            case 'beaver':
                update_post_meta($page_id, '_fl_builder_enabled', '1');
                update_post_meta($page_id, '_fl_builder_data', $layout);
                break;
        }

        return $page_id;
    }

    private function replace_placeholders($data, $replacements) {
        $json = json_encode($data);

        // Build replacement map
        $search = [];
        $replace = [];

        foreach ($replacements as $key => $value) {
            $search[] = '{{' . strtoupper($key) . '}}';
            $replace[] = $value;
        }

        $json = str_replace($search, $replace, $json);

        return json_decode($json, true);
    }
}
Enter fullscreen mode Exit fullscreen mode

Usage

# Generate 50 city pages
wp generate pages \
  --template=elementor-template.json \
  --data=cities.json \
  --builder=elementor

# Output:
# Success: Created page ID 123: Chicago
# Success: Created page ID 124: Boston
# Success: Created page ID 125: Seattle
# Success: Generated 50 pages!
Enter fullscreen mode Exit fullscreen mode

Advanced: REST API Integration

Create REST Endpoint

<?php
add_action('rest_api_init', function() {
    register_rest_route('page-gen/v1', '/create', [
        'methods'  => 'POST',
        'callback' => 'generate_page_via_api',
        'permission_callback' => function() {
            return current_user_can('edit_pages');
        }
    ]);
});

function generate_page_via_api($request) {
    $params = $request->get_json_params();

    $template = $params['template'];
    $data = $params['data'];
    $builder = $params['builder'];

    // Replace placeholders
    $layout = replace_placeholders($template, $data);

    // Create page
    $page_id = wp_insert_post([
        'post_title'   => $data['title'],
        'post_status'  => 'publish',
        'post_type'    => 'page'
    ]);

    // Save builder meta
    if ($builder === 'elementor') {
        update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($layout)));
        update_post_meta($page_id, '_elementor_edit_mode', 'builder');
    }

    return new WP_REST_Response([
        'success' => true,
        'page_id' => $page_id,
        'url'     => get_permalink($page_id)
    ], 201);
}
Enter fullscreen mode Exit fullscreen mode

Call API from External Script

// Node.js example
const axios = require('axios');

async function generatePages() {
    const template = require('./template.json');
    const cities = require('./cities.json');

    for (const city of cities) {
        const response = await axios.post(
            'https://yoursite.com/wp-json/page-gen/v1/create',
            {
                template: template,
                data: {
                    title: `${city.city} Services`,
                    ...city
                },
                builder: 'elementor'
            },
            {
                auth: {
                    username: 'admin',
                    password: 'application-password'
                }
            }
        );

        console.log(`✅ Created: ${response.data.url}`);
    }
}

generatePages();
Enter fullscreen mode Exit fullscreen mode

Real-World Use Case: Agency Workflow

Client: National HVAC Company

Need: Landing page for every city (300+ locations)

Layout:

  • Hero with city name
  • Service list
  • Local testimonials
  • Contact form with city phone
  • Map embed with city coordinates

Manual time: 300 × 20 minutes = 100 hours!!

Automated time:

  • Template creation: 2 hours
  • CSV data prep: 1 hour
  • Script development: 3 hours
  • Generation: 5 minutes
  • Total: 6 hours = 94 hours saved!!

Implementation

Data file: hvac-locations.csv

city,state,zip,phone,lat,lng
Chicago,IL,60601,(312) 555-0100,41.8781,-87.6298
Boston,MA,02108,(617) 555-0200,42.3601,-71.0589
Enter fullscreen mode Exit fullscreen mode

Script:

<?php
require_once('wp-load.php');

$template = json_decode(file_get_contents('hvac-template.json'), true);
$csv = array_map('str_getcsv', file('hvac-locations.csv'));
$headers = array_shift($csv);

foreach ($csv as $row) {
    $location = array_combine($headers, $row);

    $layout = replace_placeholders($template, [
        '{{CITY}}' => $location['city'],
        '{{STATE}}' => $location['state'],
        '{{PHONE}}' => $location['phone'],
        '{{LAT}}' => $location['lat'],
        '{{LNG}}' => $location['lng']
    ]);

    $page_id = wp_insert_post([
        'post_title' => "HVAC Services in {$location['city']}, {$location['state']}",
        'post_name'  => sanitize_title("hvac-{$location['city']}-{$location['state']}"),
        'post_status' => 'publish',
        'post_type' => 'page'
    ]);

    update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($layout)));
    update_post_meta($page_id, '_elementor_edit_mode', 'builder');

    // SEO meta
    update_post_meta($page_id, '_yoast_wpseo_title', 
        "HVAC Services {$location['city']}, {$location['state']} | Company Name");
    update_post_meta($page_id, '_yoast_wpseo_metadesc',
        "Professional HVAC services in {$location['city']}, {$location['state']}. Call {$location['phone']} today!");

    echo "✅ {$location['city']}, {$location['state']}\n";
}
Enter fullscreen mode Exit fullscreen mode

Result: 300 pages generated in 5 minutes!!

Handling Dynamic Content

ACF Integration

// Add ACF fields to generated page
update_field('service_area', $location['city'], $page_id);
update_field('phone_number', $location['phone'], $page_id);
update_field('map_coordinates', [
    'lat' => $location['lat'],
    'lng' => $location['lng']
], $page_id);
Enter fullscreen mode Exit fullscreen mode

Dynamic Elementor Widgets

{
  "elType": "widget",
  "widgetType": "text-editor",
  "settings": {
    "editor": "[acf field='service_area']"
  }
}
Enter fullscreen mode Exit fullscreen mode

Elementor renders ACF shortcode dynamically!!

Error Handling & Logging

<?php
class Page_Generator {
    private $log = [];

    public function generate($template, $data) {
        foreach ($data as $item) {
            try {
                $page_id = $this->create_page($template, $item);
                $this->log[] = "✅ Success: {$item['city']} (ID: {$page_id})";
            } catch (Exception $e) {
                $this->log[] = "❌ Error: {$item['city']} - {$e->getMessage()}";
            }
        }

        // Save log
        file_put_contents('generation-log.txt', implode("\n", $this->log));
    }

    private function create_page($template, $item) {
        $page_id = wp_insert_post([
            'post_title' => $item['city'] . ' Services',
            'post_status' => 'publish',
            'post_type' => 'page'
        ]);

        if (is_wp_error($page_id)) {
            throw new Exception($page_id->get_error_message());
        }

        // Validate layout before saving
        if (!$this->validate_layout($template)) {
            throw new Exception('Invalid layout structure');
        }

        $layout = $this->replace_placeholders($template, $item);
        update_post_meta($page_id, '_elementor_data', wp_slash(json_encode($layout)));

        return $page_id;
    }

    private function validate_layout($layout) {
        // Check required fields exist
        return isset($layout['content']) && is_array($layout['content']);
    }
}
Enter fullscreen mode Exit fullscreen mode

Bottom Line

Stop clicking page builders for repetitive layouts!!

Automation wins:

  • 100+ pages: Minutes not days
  • Zero human error
  • Consistent layouts guaranteed
  • Easy bulk updates (regenerate all pages)
  • Client thinks you're wizard!!

My typical workflow:

  1. Build one perfect template manually (1 hour)
  2. Export as JSON (30 seconds)
  3. Prepare data CSV/JSON (30 minutes)
  4. Write generation script (2 hours)
  5. Run script (2 minutes)

ROI: Pays for itself after 10 pages!!

For 50+ pages: Automation is NON-NEGOTIABLE!!

Page builder automation = agency superpower!! 🚀

This article contains affiliate links!

Top comments (1)

Collapse
 
martijn_assie_12a2d3b1833 profile image
Martijn Assie

Used this exact workflow last month for client with 85 location pages... saved me like 3 DAYS of clicking around in Divi!! Template took 90 min to perfect, wrote the PHP script in 2 hours, then just ran it and boom - 85 pages with unique city content, phone numbers, map embeds, everything. Client was like "how did you do this so fast" lol... JSON config is KEY - once you nail the placeholder system you can pump out pages for ANY repetitive layout. Game changer for agency work honestly...