Enter
  • Resources
  • PHP
  • How to Transform Custom WordPress Blocks to Core Blocks with WP All Import and parse_blocks()

PHP / 8 min read

How to Transform Custom WordPress Blocks to Core Blocks with WP All Import and parse_blocks()

close up of a colorful PHP code over a dark screen

Migrating WordPress content can be daunting, especially when dealing with a mix of custom blocks and third-party plugins. However, using WP All Import and WordPress’s parse_blocks() function, it’s possible to efficiently transform custom blocks into core blocks, creating a more streamlined and manageable content experience.

If not properly imported, these blocks can disrupt a theme’s style, leading to inconsistent aesthetics and a messy content structure. As a result, it’s very important to get the import right.

Let’s explore how to do it.

The Challenge of Custom Blocks

One of the main reasons to transform custom blocks to core blocks is the challenge they present for long-term maintainability. Additionally, custom blocks introduced by third-party plugins often break the site’s style and aesthetic consistency.

In a recent project, the client had several custom blocks that didn’t align with the templates and patterns we created (WordPress FSE). Our templates provided a structured, cohesive look for the site, but the custom blocks weren’t compatible with it.

Keeping these third-party blocks would have undermined our effort to achieve a well-organized and visually consistent web design.

By converting these blocks to core blocks, we gained better control over the appearance and functionality of the content. This ensured it adhered to the style guide and improved overall site consistency.

Why WP All Import?

We’ve used WP All Import to great success in multiple projects now.

Its robust features and ability to handle complex imports have made it our first option when importing large volumes of content. One of its key strengths is its flexibility, allowing us to write custom scripts to manipulate data during the import process.

This customization comes in handy when transforming custom blocks into core blocks. For this particular migration, WP All Import’s script capabilities allowed us to fine-tune how each block was handled during the import.

Leveraging parse_blocks() for Block Transformation

Initially, the strategy for identifying and replacing blocks relied on regular expressions (regex).

This approach worked for simpler blocks, like converting a Genesis spacer block into a core WordPress spacer block.

However, as the blocks became more complex, regex became insufficient. When faced with more robust blocks, I began looking for alternatives and came across the parse_blocks() function in the WordPress documentation.

parse_blocks() parses post content into an array of block objects, providing access to crucial information such as block names, attributes, inner HTML, and nested blocks (innerBlocks).

This allowed me to develop conditions and logic based on the block structure, making it much easier to transform complex custom blocks into core blocks.

Converting Genesis Blocks to Core Blocks Using PHP: 2 Examples

Example #1: The Final Result

The transformation process, while effective, has been time-consuming due to the unique structure of each block.

No pair of custom blocks are exactly alike, meaning each one requires thorough debugging to understand its structure and determine how best to replace it. The process of figuring all this out took more than 16 hours of work.

Here’s an example of how blocks look after being transformed from Genesis to core blocks.

Before (Custom Block)

<!-- wp:columns {"columns":2} -->
<div class="wp-block-genesis-blocks-gb-columns gb-layout-columns-2 gb-2-col-equal alignwide"><div class="gb-layout-column-wrap gb-block-layout-column-gap-2 gb-is-responsive-column"><!-- wp:column -->
  <div class="wp-block-genesis-blocks-gb-column gb-block-layout-column"><div class="gb-block-layout-column-inner"><!-- wp:heading {"level":5} -->
  <h5>Lorem Ipsum</h5>
  <!-- /wp:heading -->
  <!-- /wp:genesis-blocks/gb-column -->

  <!-- wp:column -->
  <div class="wp-block-genesis-blocks-gb-column gb-block-layout-column"><div class="gb-block-layout-column-inner"><!-- wp:heading {"level":5} -->
  <h5>Lorem Ipsum</h5>
  <!-- /wp:heading -->
  <!-- /wp:genesis-blocks/gb-column --></div></div>
<!-- /wp:columns -->

After (Core Block)

<!-- wp:columns -->
  <div class="wp-block-columns"><!-- wp:column -->
  <div class="wp-block-column"><!-- wp:heading {"level":5} -->
  <h5 class="wp-block-heading">Lorem Ipsum</h5></div>
  <!-- /wp:heading -->

  <!-- wp:column -->
  <div class="wp-block-column"><!-- wp:heading {"level":5} -->
    <h5 class="wp-block-heading">Lorem Ipsum</h5>
    <!-- /wp:heading --></div>
  <!-- /wp:column --></div>
<!-- /wp:columns -->

This example shows the final result of transforming a Genesis column block layout into a native WordPress columns block, ensuring that all HTML, attributes, and inner blocks are preserved and migrated correctly.

Example #2: The Step-by-Step Process

Let’s explore a second, more detailed example, showing the step-by-step process of how to achieve this transformation using WP All Import and parse_blocks(). Here’s the code for converting Genesis Columns to Core Columns:

/**
 * Convert Genesis blocks to WordPress core blocks.
 *
 * This function parses the content, identifies Genesis blocks (Columns and Column)
 * and converts them into core WordPress blocks.
 *
 * @param string $content The original content containing Genesis blocks.
 * @return string The content with Genesis blocks converted to core blocks.
 */
function convert_genesis_blocks_to_core( $content ) {
    // Parse the content into blocks
    $blocks = parse_blocks( $content );

    // Recursively convert the blocks
    $converted_blocks = convert_blocks_recursively( $blocks );

    // Serialize the blocks back into content and return
    return serialize_blocks( $converted_blocks );
}

/**
 * Recursively convert custom blocks into core blocks.
 *
 * This function loops through parsed blocks and applies transformations to Genesis blocks.
 *
 * @param array $blocks An array of parsed block objects.
 * @return array The transformed array of block objects.
 */
function convert_blocks_recursively( $blocks ) {
    $converted_blocks = array();

    foreach ( $blocks as $block ) {
        // Convert Genesis column blocks to core columns
        if ( 'genesis-blocks/gb-columns' === $block['blockName'] ) {
            $converted_blocks[] = convert_genesis_columns_block( $block );
        } elseif ( 'genesis-blocks/gb-column' === $block['blockName'] ) {
            $converted_blocks[] = convert_genesis_column_block( $block );
        } else {
            // Recursively convert inner blocks
            if ( ! empty( $block['innerBlocks'] ) ) {
                $block['innerBlocks'] = convert_blocks_recursively( $block['innerBlocks'] );
            }
            $converted_blocks[] = $block;
        }
    }

    return $converted_blocks;
}

/**
 * Convert Genesis Columns block to a core Columns block.
 *
 * This function maps Genesis Columns block attributes and structure to core Columns attributes.
 *
 * @param array $block The Genesis Columns block data.
 * @return array The transformed core Columns block.
 */
function convert_genesis_columns_block( $block ) {
    $attrs = array( 'columns' => $block['attrs']['columns'] ?? 2 );

    // Recursively convert inner blocks (Genesis Columns)
    $inner_blocks = convert_blocks_recursively( $block['innerBlocks'] );

    return array(
        'blockName'    => 'core/columns',
        'attrs'        => $attrs,
        'innerBlocks'  => $inner_blocks,
        'innerHTML'    => '',  // Will be regenerated automatically
        'innerContent' => array(),
    );
}

/**
 * Convert Genesis Column block to a core Column block.
 *
 * This function converts individual Genesis Columns into WordPress core Columns.
 *
 * @param array $block The Genesis Column block data.
 * @return array The transformed core Column block.
 */
function convert_genesis_column_block( $block ) {
    // Recursively convert inner blocks inside the Column
    $inner_blocks = convert_blocks_recursively( $block['innerBlocks'] );

    return array(
        'blockName'    => 'core/column',
        'attrs'        => array(),  // No special attributes for core Column block
        'innerBlocks'  => $inner_blocks,
        'innerHTML'    => '',  // Will be regenerated automatically
        'innerContent' => array(),
    );
}

This example shows how to transform a Genesis column block layout into a native WordPress columns block, ensuring that all HTML, attributes, and inner blocks are preserved and migrated correctly.

Integrating the Code with WP All Import

Once you’ve crafted your block transformation code, it’s time to put it to work within WP All Import. The process is simple and can be done during the import configuration.

In the third step of creating a new import (the “Drag & Drop” interface), you would typically map your content fields. Instead of using the standard {content[1]} field for your post content, you can call the custom function directly to handle the block transformation.

For example, use:

[convert_genesis_blocks_to_core({content[1]})]

This will apply your transformation logic to the content before it’s imported, ensuring your custom blocks are converted to core blocks during the import process.

The WP All Import interface during the Drag & Drop step

Where to Define the Function for Converting Custom Blocks to Core Blocks?

WP All Import allows you to define custom functions right within the interface.

Scroll down in the same “Drag & Drop” step until you find the “Function Editor” section. Here, you can paste the PHP code for the convert_genesis_blocks_to_core() function. Once added, WP All Import will recognize it and apply it to the content as configured.

Wp All Import's function editor feature. The function depicted converts custom blocks to core WordPress blocks

For more detailed guidance, you can check out WP All Import’s official documentation on using inline PHP.

Benefits of Using Core Blocks

The benefits of this transformation go beyond looks.

By using WordPress core blocks alongside our custom blocks, we’ve minimized our reliance on third-party plugins. This improves performance since fewer external scripts are loaded on the front end and also gives us complete control over the styling and behavior of the blocks.

Customizing a core block is far easier than working around someone else’s custom block.

Additionally, the client’s experience remains seamless, as core blocks are intuitive and well-known within the WordPress ecosystem.

Testing and Ensuring Data Integrity

As with any large migration, ensuring the integrity of the content is important. We conducted multiple local migrations, processing over 1,700 posts in total. To ensure accuracy, we reviewed approximately one post out of every thirty, manually checking that the data and formatting were preserved correctly after the transformation.

This testing helped us maintain confidence that no content was lost or damaged during the process.

Transforming Custom Blocks Into Core Blocks Streamlines Content Management

By transforming custom blocks into core blocks, we’ve made the client’s site more efficient, consistent, and easier to maintain.

WP All Import and parse_blocks() proved invaluable tools in this process, allowing for a flexible, scalable solution to handle complex content migrations.

For developers facing similar challenges, this method not only future-proofs content but also significantly reduces the overhead of managing third-party plugins.

If you found this post useful, read our blog and developer resources for more insights and guides!