October 14, 2026 5 min read WordPress

Building Custom Gutenberg Blocks using React, Block JSON, and Server-Side Rendering

Introduction to Modern WordPress Block Engineering

The WordPress Gutenberg block editor has revolutionized content publishing, moving away from rigid meta boxes and clunky shortcodes toward an intuitive, component-driven editing experience. For enterprise clients and high-traffic publishers, relying on bloated third-party page builders often compromises site performance. At Tech Aditya, we build lightning-fast, tailored web architectures that leverage native WordPress APIs.

In this deep-dive technical guide, we will walk through the exact workflow required to build a production-grade, custom Gutenberg block from scratch. We will combine modern React hooks, standardized block.json metadata configuration, and Server-Side Rendering (SSR) via PHP.

Setting Up the Development Environment and Directory Structure

A clean architecture begins with proper organization. Modern block development relies on Node.js, `@wordpress/scripts` (which abstracts Webpack and Babel configurations), and a local WordPress development environment.

Navigate to your active theme or custom plugin directory (typically wp-content/plugins/) and scaffold the block structure:

Snippet
mkdir -p tech-aditya-blocks/src/dynamic-card
cd tech-aditya-blocks
npm init -y
npm install @wordpress/scripts --save-dev

Update your package.json file to include the standard build and start scripts provided by the WordPress ecosystem:

Snippet
{
  "name": "tech-aditya-blocks",
  "version": "1.0.0",
  "description": "Custom Gutenberg blocks engineered by Tech Aditya",
  "scripts": {
    "build": "wp-scripts build",
    "start": "wp-scripts start"
  },
  "devDependencies": {
    "@wordpress/scripts": "^30.0.0"
  }
}

Configuring Metadata with block.json

The block.json file is the single source of truth for your block's metadata. Placing this file inside your block directory allows WordPress to auto-register both client-side assets and server-side rendering callbacks seamlessly.

Create a file named block.json inside src/dynamic-card/:

Snippet
{
  "$schema": "https://schemas.wp.org/trunk/block.json",
  "apiVersion": 3,
  "name": "tech-aditya/dynamic-card",
  "title": "Tech Aditya Dynamic Card",
  "category": "widgets",
  "icon": "laptop",
  "description": "A high-performance server-side rendered dynamic card block.",
  "supports": {
    "html": false,
    "align": ["wide", "full"]
  },
  "attributes": {
    "cardTitle": {
      "type": "string",
      "default": "Engineering Excellence"
    },
    "displayBadge": {
      "type": "boolean",
      "default": true
    }
  },
  "textdomain": "tech-aditya",
  "editorScript": "file:./index.js",
  "style": "file:./style-index.css",
  "render": "file:./render.php"
}

Architecting the React Editor Component (edit.js)

The editor component determines how the block renders inside the Gutenberg canvas. We use React alongside WordPress components like InspectorControls and TextControl to manage attributes reactively.

Create src/dynamic-card/edit.js:

Snippet
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, ToggleControl } from '@wordpress/components';
import './editor.scss';

export default function Edit({ attributes, setAttributes }) {
    const { cardTitle, displayBadge } = attributes;
    const blockProps = useBlockProps();

    return (
        

{cardTitle}

{displayBadge && Active}

{__('Preview mode: Server-side rendering output will display on the frontend.', 'tech-aditya')}

); }

Registering the Block and Writing the SSR PHP Callback

With our React components compiled, we register the block on the server using register_block_type_from_metadata(). Because we declared "render": "file:./render.php" in our block.json, WordPress automatically handles Server-Side Rendering.

Create the main plugin entry file tech-aditya-blocks.php:

Snippet
<?php
/**
 * Plugin Name: Tech Aditya Custom Blocks
 * Description: Custom Gutenberg blocks with block.json and SSR.
 * Version: 1.0.0
 * Author: Tech Aditya
 * Author URI: https://www.techaditya.com
 * Text Domain: tech-aditya
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

function tech_aditya_register_blocks() {
    register_block_type_from_metadata( __DIR__ . '/build/dynamic-card' );
}
add_action( 'init', 'tech_aditya_register_blocks' );

Now, create the corresponding server-side render file src/dynamic-card/render.php:

Snippet
<?php
/**
 * Server-side rendering template for tech-aditya/dynamic-card
 */

$card_title   = isset( $attributes['cardTitle'] ) ? esc_html( $attributes['cardTitle'] ) : '';
$display_badge = isset( $attributes['displayBadge'] ) ? (bool) $attributes['displayBadge'] : false;

$wrapper_attributes = get_block_wrapper_attributes( array( 'class' => 'tech-aditya-ssr-card' ) );
?>

<div <?php echo $wrapper_attributes; ?>>
    <div class="card-content-wrapper">
        <header class="card-header">
            <h2><?php echo $card_title; ?></h2>
            <?php if ( $display_badge ) : ?>
                <span class="tech-badge"><?php esc_html_e( 'Verified', 'tech-aditya' ); ?></span>
            <?php endif; ?>
        </header>
        <div class="card-body">
            <p><?php esc_html_e( 'This content is dynamically rendered via PHP and optimized for performance.', 'tech-aditya' ); ?></p>
        </div>
    </div>
</div>

Comparative Performance: Client-Side vs Server-Side Blocks

Choosing the right rendering strategy impacts both administrative usability and frontend speed. Examine the architectural trade-offs below:

Metric / Feature Client-Side (save.js) Server-Side Rendering (SSR)
Database Updates Static HTML saved directly to post_content. Attributes saved; markup generated dynamically on request.
Frontend Performance Instant DOM painting with zero PHP overhead. Requires PHP execution; mitigated easily with object caching.
Content Refactoring Requires database migration script if markup changes. Instant global updates by modifying render.php.
Best Use Case Static layouts, text boxes, buttons, banners. Dynamic queries, real-time feeds, secure user data.

Pro-Tip from Tech Aditya: When utilizing Server-Side Rendering for high-traffic enterprise portals, always implement transient caching or object caching (Redis/Memcached) inside your render.php logic to avoid redundant database queries on every page view.

Compiling and Building for Production

Once your editor script, block metadata, and PHP render files are in place, compile your assets using the WordPress build script:

Snippet
npm run build

This command compiles your ESNext and JSX code from src/ into optimized production assets inside the build/ directory, ready for deployment. For scalable enterprise solutions, explore our Full-Stack Web Development services.

Conclusion

Building custom Gutenberg blocks using React, block.json, and Server-Side Rendering grants developers absolute control over the WordPress editorial experience without sacrificing site speed. By keeping your codebase modular and leveraging native WordPress APIs, you ensure long-term maintainability and superior performance. If you need bespoke WordPress engineering or optimization, contact Tech Aditya today to discuss your project.

Frequently Asked Questions

Quick, authoritative answers to common questions on this topic

Q1 Why should I use block.json instead of registering custom blocks via PHP?
Using block.json is the modern standard recommended by WordPress. It improves performance by enabling asset loading only when the block is present on the page, optimizes translations, and standardizes block metadata registration across both PHP and JavaScript environments.
Q2 When should I use Server-Side Rendering (SSR) for a Gutenberg block?
SSR is ideal when your block displays dynamic data from the database, relies on frequent updates from external APIs, or needs to render complex backend logic where JavaScript client-side rendering would introduce security risks or heavy frontend overhead.
Q3 How do I pass attributes from the React edit component to the PHP render callback?
Attributes defined in your block.json are automatically saved to the block's comment delimiter in the post content. When rendering via PHP, these attributes are passed directly as an associative array into your designated render callback function.
Q4 Can I optimize custom Gutenberg blocks for Core Web Vitals?
Yes. By leveraging block.json for lazy asset registration, utilizing Server-Side Rendering for lightweight HTML output, and minimizing heavy third-party React dependencies, you can maintain pristine Core Web Vitals scores.
Aditya Kumar

Aditya Kumar

Full-Stack Engineer

Chat on WhatsApp