Structuring multi-block WordPress plugins that scale

I had a client recently, a real go-getter, who needed a pile of custom blocks for a new content strategy: dynamic sliders, interactive toggles, that sort of thing. We started with a straightforward multi-block plugin setup, the kind you see in a lot of WordPress developer examples. It was quick, it worked, and everyone was happy, for about two months. Then the block count grew and the whole thing started feeling clunky. Builds got slow, dependencies piled up, and adding a new block felt like untangling a ball of yarn after the cat had gotten to it. Total mess.

My first thought was, “Maybe we just need more aggressive caching or a stronger CDN setup for those bundled assets.” That would have hidden some of the performance issues, but it wouldn’t have touched the actual development mess. We were still fighting the build, and the registration logic got harder to maintain with every block we added. The fix had to happen at the architectural level. It needed a real refactor.

Refactoring for scalable WordPress blocks

The core problem was that the “simple” foundation, fine for getting off the ground, didn’t account for real growth. Bundling everything into one file was fine for CDN delivery, but it worked against the way WordPress prefers to load individual blocks. We needed a setup that recognized the different block types (static, dynamic, and interactive) and handled their assets accordingly.

It wasn’t magic, just structure and automation. We started by moving every block into a top-level src/blocks directory, which alone made things cleaner. No more hunting for where a block’s files lived. The bigger change was the registration function. Instead of registering each block by hand, we automated it: drop a new block into src/blocks, run the build, and it registers itself.

<?php
function register_blocks() {
  $build_dir = __DIR__ . '/build/blocks';
  $manifest  = __DIR__ . '/build/blocks-manifest.php';

  // WP 6.8+: one-call convenience.
  if ( function_exists( 'wp_register_block_types_from_metadata_collection' ) ) {
      wp_register_block_types_from_metadata_collection( $build_dir, $manifest );
      return;
  }

  // WP 6.7: index the collection, then loop and register each block from metadata.
  if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
      wp_register_block_metadata_collection( $build_dir, $manifest );
      $manifest_data = require $manifest;
      foreach ( array_keys( $manifest_data ) as $block_type ) {
          register_block_type_from_metadata( $build_dir . '/' . $block_type );
      }
      return;
  }

  // WP 5.5-6.6: no collection APIs; just loop the manifest directly.
  if ( function_exists( 'register_block_type_from_metadata' ) ) {
      $manifest_data = require $manifest;
      foreach ( array_keys( $manifest_data ) as $block_type ) {
          register_block_type_from_metadata( $build_dir . '/' . $block_type );
      }
      return;
  }
}
add_action( 'init', 'register_blocks' );
?>

That snippet is the part that does the heavy lifting. It registers blocks from their block.json metadata regardless of the WordPress version, which keeps the plugin lean. The WordPress Developer Resources guide walks through the same approach in more detail.

Beyond the blocks themselves, we split the global editor and frontend scripts into their own standalone assets. That let us load shared code only where it was actually needed, so the overall payload dropped. Interactive blocks need a little extra handling in the build, so we updated package.json to pass the --experimental-modules flag to wp-scripts, which lets everything compile without conflicts.

Why the structure matters

The takeaway: don’t let a “simple” solution turn into a pile of technical debt. When you’re building multi-block plugins for WordPress, plan for growth. A modular layout, automated registration, and sensible asset handling are what keep the plugin maintainable as it gets bigger. Putting the work in up front means fewer headaches down the line and a plugin that grows with the project.

This stuff gets complicated fast. If you’re tired of debugging someone else’s mess and just want the site to work, drop my team a line. We’ve probably seen it before.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.