• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » How to build custom ACF Pro dynamic fields extensions utilizing modern Block Patterns API schemas

How to build custom ACF Pro dynamic fields extensions utilizing modern Block Patterns API schemas

Leveraging ACF Pro’s Dynamic Field Capabilities with Block Patterns

Advanced Custom Fields (ACF) Pro offers a powerful mechanism for creating dynamic fields, allowing field values to be populated programmatically rather than through manual input. This is particularly useful when integrating with external data sources or generating complex, context-aware options. When combined with WordPress’s modern Block Editor and its Block Patterns API, these dynamic fields can unlock sophisticated content creation workflows. This guide details how to build custom ACF Pro dynamic field extensions, specifically focusing on how to leverage the Block Patterns API schema for dynamic field population.

Understanding ACF Pro Dynamic Fields

ACF Pro’s dynamic fields are configured within the ACF Field Group editor. Instead of selecting a static value, you choose “Dynamic” and then specify a “Source” and “Value Format”. The “Source” determines where the data comes from (e.g., a post object, a taxonomy term, a user, or a custom PHP function). The “Value Format” dictates how the retrieved data is presented as the field’s value.

The most flexible “Source” option is “PHP Function”. This allows you to write custom PHP code that returns an array of key-value pairs, where the keys are the actual values to be stored and the values are the human-readable labels displayed in the ACF field dropdown or radio button list. This is the foundation upon which we’ll build our Block Patterns integration.

The Block Patterns API Schema

WordPress 5.5 introduced the Block Patterns API, a structured way to register and manage reusable content blocks. Patterns are essentially pre-defined layouts and content structures that users can insert into their posts or pages. The API allows for programmatic registration of patterns, including their categories, title, description, and most importantly, their content (HTML markup).

The key to our integration lies in the ability to programmatically access registered block patterns. While there isn’t a direct, built-in ACF “Source” for Block Patterns, we can achieve this by writing a custom PHP function that queries the registered patterns and formats them into the key-value array ACF expects.

Developing the Custom PHP Function for Dynamic Fields

We’ll create a PHP function that retrieves all registered block patterns and formats them into an array suitable for ACF Pro’s dynamic fields. This function will be hooked into WordPress’s initialization process to ensure patterns are available.

Registering the Dynamic Field Function

First, let’s define the PHP function. This function will iterate through all registered block patterns and create an associative array where the pattern’s slug (or a unique identifier) is the key, and its title is the value. We’ll also add a prefix to the key to avoid potential naming conflicts.

Example PHP Function

/**
 * Retrieves registered block patterns and formats them for ACF dynamic fields.
 *
 * @return array An associative array of block pattern slugs and titles.
 */
function my_acf_get_block_patterns_for_acf() {
    $patterns = WP_Block_Pattern_Registry::get_instance()->get_all_registered();
    $options  = array();
    $prefix   = 'my_pattern_'; // Prefix to avoid conflicts

    if ( ! empty( $patterns ) ) {
        foreach ( $patterns as $slug => $pattern_data ) {
            // Ensure we have a valid pattern object and it's not a category
            if ( is_array( $pattern_data ) && isset( $pattern_data['title'] ) ) {
                $options[$prefix . $slug] = sanitize_text_field( $pattern_data['title'] );
            }
        }
    }

    // Optionally, add a default or placeholder option
    if ( empty( $options ) ) {
        $options[''] = __( 'No block patterns found', 'your-text-domain' );
    }

    return $options;
}

Now, we need to make this function available to ACF Pro. We do this by adding it to the `acf/init` action hook. This ensures that ACF is initialized and ready to process dynamic field sources.

/**
 * Register the custom function as an ACF dynamic field source.
 */
function my_acf_register_dynamic_pattern_field_source() {
    // This function name must match the 'Source' selected in ACF Field Group settings.
    // ACF Pro will automatically look for functions named like 'acf_get_dynamic_field_source_{your_function_name}'.
    // However, for custom PHP functions, we simply reference the function name directly.
    // The key here is that ACF Pro's 'PHP Function' source expects a function that returns an array.
    // We will reference 'my_acf_get_block_patterns_for_acf' directly in the ACF Field Group settings.
}
// No explicit hook needed here for ACF's 'PHP Function' source.
// The function 'my_acf_get_block_patterns_for_acf' will be directly referenced in the ACF Field Group UI.

Place this PHP code in your theme’s `functions.php` file or, preferably, within a custom plugin. Ensure your plugin or theme is active.

Configuring the ACF Pro Field Group

With the PHP function ready, we can now configure an ACF Pro field group to use it. Navigate to your WordPress admin dashboard, go to “Custom Fields” -> “Field Groups”, and create a new field group or edit an existing one.

Adding the Dynamic Field

1. Click “Add Field”.

2. Set the “Field Label” (e.g., “Select Block Pattern”).

3. Set the “Field Name” (e.g., `selected_block_pattern`).

4. Choose “Select” or “Radio Button” as the “Field Type”.

5. Under the “Settings” tab for the field, locate the “Data Source” section.

6. Select “Dynamic” for the “Data Source”.

7. In the “Source” dropdown, select “PHP Function”.

8. In the “PHP Function” text input field, enter the exact name of your custom function: my_acf_get_block_patterns_for_acf.

9. For “Value Format”, you can typically leave this as “Key => Value” if your function returns an associative array as expected. If you needed to format it differently (e.g., just the value), you could use `{{value}}` or `{{key}}` placeholders, but for this scenario, the default is appropriate.

10. Configure other field settings (Instructions, Required, etc.) as needed.

11. Save your Field Group.

Retrieving and Using the Selected Pattern

When a user selects a block pattern from this dynamic field and saves the post, the selected pattern’s slug (prefixed with `my_pattern_`) will be stored as the field’s value. You can then retrieve this value using standard ACF functions like get_field().

Example: Displaying the Selected Pattern’s Content

Let’s say you have a custom post type or a specific page template where you want to display the content of the selected block pattern. You would retrieve the pattern slug and then use WordPress functions to get the pattern’s actual content.

<?php
// Assuming you are within the WordPress loop or have a post ID.
$post_id = get_the_ID();
$selected_pattern_slug_prefixed = get_field( 'selected_block_pattern', $post_id ); // e.g., 'my_pattern_my-hero-section'

if ( $selected_pattern_slug_prefixed ) {
    // Remove the prefix to get the original slug
    $prefix = 'my_pattern_';
    if ( strpos( $selected_pattern_slug_prefixed, $prefix ) === 0 ) {
        $original_pattern_slug = substr( $selected_pattern_slug_prefixed, strlen( $prefix ) );

        // Get the pattern object
        $pattern_object = WP_Block_Pattern_Registry::get_instance()->get_pattern_data( $original_pattern_slug );

        if ( $pattern_object && isset( $pattern_object['content'] ) ) {
            // Render the pattern's content.
            // Note: This directly renders the block markup. For more complex scenarios,
            // you might want to parse and render blocks individually using render_block().
            echo '<div class="selected-block-pattern-wrapper">';
            echo do_blocks( $pattern_object['content'] ); // Use do_blocks to render block markup
            echo '</div>';
        } else {
            echo '<p>' . esc_html__( 'Block pattern content not found.', 'your-text-domain' ) . '</p>';
        }
    } else {
        // Handle cases where the slug might not have the expected prefix (e.g., if manually entered or from a different source)
        echo '<p>' . esc_html__( 'Invalid block pattern selected.', 'your-text-domain' ) . '</p>';
    }
} else {
    echo '<p>' . esc_html__( 'No block pattern selected.', 'your-text-domain' ) . '</p>';
}
?>

The do_blocks() function is crucial here. It takes a string of block markup and renders it, respecting any inner blocks, attributes, and dynamic rendering logic within those blocks.

Advanced Considerations and Customizations

Filtering Block Patterns

Your `my_acf_get_block_patterns_for_acf` function can be extended to filter which patterns are available. For instance, you might only want to show patterns from a specific category, or patterns that have been programmatically registered with a certain flag.

/**
 * Retrieves filtered block patterns for ACF dynamic fields.
 *
 * @return array An associative array of block pattern slugs and titles.
 */
function my_acf_get_FILTERED_block_patterns_for_acf() {
    $patterns = WP_Block_Pattern_Registry::get_instance()->get_all_registered();
    $options  = array();
    $prefix   = 'my_pattern_';
    $allowed_categories = array( 'my-custom-category', 'featured' ); // Example categories to include

    if ( ! empty( $patterns ) ) {
        foreach ( $patterns as $slug => $pattern_data ) {
            if ( is_array( $pattern_data ) && isset( $pattern_data['title'] ) ) {
                // Check if the pattern belongs to an allowed category
                $pattern_categories = isset( $pattern_data['categories'] ) && is_array( $pattern_data['categories'] )
                                    ? $pattern_data['categories']
                                    : array();

                $is_allowed = false;
                foreach ( $allowed_categories as $allowed_cat ) {
                    if ( in_array( $allowed_cat, $pattern_categories, true ) ) {
                        $is_allowed = true;
                        break;
                    }
                }

                if ( $is_allowed ) {
                    $options[$prefix . $slug] = sanitize_text_field( $pattern_data['title'] );
                }
            }
        }
    }

    if ( empty( $options ) ) {
        $options[''] = __( 'No matching block patterns found', 'your-text-domain' );
    }

    return $options;
}

Remember to update the “PHP Function” field in your ACF Field Group to point to this new function (e.g., my_acf_get_FILTERED_block_patterns_for_acf).

Customizing the Stored Value

Currently, the function stores the pattern slug. You might want to store something else, like the pattern’s title, or a combination. The “Value Format” option in ACF Pro can help, but for more complex transformations, you’d modify the PHP function’s return array.

/**
 * Retrieves block patterns and formats them for ACF dynamic fields, storing title as value.
 *
 * @return array An associative array of block pattern slugs and titles.
 */
function my_acf_get_block_patterns_storing_title_for_acf() {
    $patterns = WP_Block_Pattern_Registry::get_instance()->get_all_registered();
    $options  = array();
    $prefix   = 'my_pattern_';

    if ( ! empty( $patterns ) ) {
        foreach ( $patterns as $slug => $pattern_data ) {
            if ( is_array( $pattern_data ) && isset( $pattern_data['title'] ) ) {
                // Store the slug as the key, and the title as the value.
                // This is the standard format ACF expects.
                $options[$prefix . $slug] = sanitize_text_field( $pattern_data['title'] );
            }
        }
    }

    // If you wanted to store the TITLE as the VALUE in the database,
    // and the SLUG as the KEY, you would do this:
    // $options[ $slug ] = $pattern_data['title']; // This is what we are doing.

    // If you wanted to store the SLUG as the VALUE and TITLE as KEY:
    // $options[ sanitize_text_field( $pattern_data['title'] ) ] = $prefix . $slug;
    // But this is less common for select/radio fields where you want to display labels.

    if ( empty( $options ) ) {
        $options[''] = __( 'No block patterns found', 'your-text-domain' );
    }

    return $options;
}

In this specific example, the function already returns an array where the key is the pattern slug (prefixed) and the value is the pattern title. This is the ideal format for ACF’s select or radio button fields, as it displays the human-readable title to the user while storing the programmatic identifier (the slug).

Conclusion

By combining ACF Pro’s dynamic field capabilities with a custom PHP function that queries the Block Patterns API, you can create powerful and flexible content management solutions. This approach allows content creators to easily select and insert pre-designed block layouts directly from the WordPress editor, driven by your site’s specific pattern library. This integration streamlines workflows, ensures consistency, and leverages the full potential of the modern WordPress Block Editor.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins
  • How to implement native Redis caching layers for high-volume custom taxonomy queries in Carbon Fields custom wrappers
  • Building secure B2B pricing grids with custom REST API Controllers endpoints and role overrides

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (48)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (182)
  • WordPress Plugin Development (197)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Reducing database query bloat in Sage Roots modern environments layouts using custom lazy loaders
  • Performance Optimization: Tuning PHP-FPM and opcache pools for high-concurrency Firebase Realtime DB handlers
  • Reducing Largest Contentful Paint (LCP) by optimizing custom script enqueuing structures in legacy plugins

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala