• 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 » WordPress Development Recipe: High-efficiency server-side rendering for Gutenberg blocks using Union and Intersection Types

WordPress Development Recipe: High-efficiency server-side rendering for Gutenberg blocks using Union and Intersection Types

Leveraging Union and Intersection Types for Efficient Gutenberg SSR

Server-side rendering (SSR) for Gutenberg blocks is crucial for performance and SEO. While WordPress’s built-in `render_callback` is effective, complex blocks often require sophisticated data handling and conditional logic. This recipe demonstrates how to implement highly efficient SSR by employing PHP’s union and intersection types (available from PHP 8.0 and 8.1 respectively) to create robust, type-safe rendering functions. This approach significantly reduces runtime errors and improves code clarity, especially when dealing with multiple potential data structures or configurations.

Scenario: A Dynamic Call-to-Action (CTA) Block

Consider a CTA block that can be configured in several ways:

  • A simple CTA with just a title and button.
  • A CTA with a title, button, and an optional subtitle.
  • A CTA with a title, button, subtitle, and a background image URL.

The attributes for these variations might be stored in a flexible, yet potentially inconsistent, manner. We need a `render_callback` that can gracefully handle these different attribute structures.

Defining Attribute Structures with PHP Enums and Classes

To enforce type safety and structure, we’ll define distinct classes for each CTA configuration. We’ll also use an Enum to represent the button style, which adds another layer of type safety.

Button Style Enum

First, let’s define the button styles.

<?php
// src/Enums/ButtonStyles.php

namespace MyPlugin\Enums;

enum ButtonStyles: string
{
    case PRIMARY = 'primary';
    case SECONDARY = 'secondary';
    case OUTLINE = 'outline';
}

Base CTA Attributes Class

A base class to hold common attributes.

<?php
// src/Attributes/BaseCtaAttributes.php

namespace MyPlugin\Attributes;

abstract class BaseCtaAttributes
{
    public string $title;
    public string $button_text;
    public string $button_url;
    public \MyPlugin\Enums\ButtonStyles $button_style;

    public function __construct(array $attributes)
    {
        $this->title = $attributes['title'] ?? '';
        $this->button_text = $attributes['button_text'] ?? '';
        $this->button_url = $attributes['button_url'] ?? '';
        // Default to primary if not specified or invalid
        $this->button_style = $attributes['button_style'] ?? \MyPlugin\Enums\ButtonStyles::PRIMARY;
    }
}

Specific CTA Attribute Classes

Classes for each CTA variation, extending the base class.

<?php
// src/Attributes/SimpleCtaAttributes.php

namespace MyPlugin\Attributes;

class SimpleCtaAttributes extends BaseCtaAttributes
{
    // No additional attributes for the simple version
}
<?php
// src/Attributes/SubtitleCtaAttributes.php

namespace MyPlugin\Attributes;

class SubtitleCtaAttributes extends BaseCtaAttributes
{
    public string $subtitle;

    public function __construct(array $attributes)
    {
        parent::__construct($attributes);
        $this->subtitle = $attributes['subtitle'] ?? '';
    }
}
<?php
// src/Attributes/BackgroundCtaAttributes.php

namespace MyPlugin\Attributes;

class BackgroundCtaAttributes extends SubtitleCtaAttributes
{
    public string $background_image_url;

    public function __construct(array $attributes)
    {
        parent::__construct($attributes);
        $this->background_image_url = $attributes['background_image_url'] ?? '';
    }
}

Implementing the Union Type Render Callback

Now, we can define a `render_callback` that accepts a union type. This allows the function to accept any of our defined CTA attribute classes. We’ll use PHP 8.2’s intersection types for the `attributes` parameter to ensure it’s an array and also an instance of our `BaseCtaAttributes` (or its subclasses).

The Render Callback Function

<?php
// src/RenderCallbacks.php

namespace MyPlugin;

use MyPlugin\Attributes\BaseCtaAttributes;
use MyPlugin\Attributes\SimpleCtaAttributes;
use MyPlugin\Attributes\SubtitleCtaAttributes;
use MyPlugin\Attributes\BackgroundCtaAttributes;

class RenderCallbacks
{
    /**
     * Renders the dynamic CTA block.
     *
     * Accepts attributes that conform to SimpleCtaAttributes, SubtitleCtaAttributes,
     * or BackgroundCtaAttributes.
     *
     * @param array{title: string, button_text: string, button_url: string, button_style?: string, subtitle?: string, background_image_url?: string} $attributes The block attributes.
     * @return string The rendered HTML.
     */
    public static function render_cta_block(array $attributes): string
    {
        // Attempt to instantiate the most specific type first, then fall back.
        // This requires a bit of manual type checking and instantiation logic
        // as PHP's union types for parameters don't automatically handle
        // instantiation from an array.
        $cta_data = null;

        if (isset($attributes['background_image_url'])) {
            $cta_data = new BackgroundCtaAttributes($attributes);
        } elseif (isset($attributes['subtitle'])) {
            $cta_data = new SubtitleCtaAttributes($attributes);
        } else {
            // If none of the specific optional fields are present, assume simple.
            // We still need to ensure it has the base required fields.
            if (isset($attributes['title'], $attributes['button_text'], $attributes['button_url'])) {
                $cta_data = new SimpleCtaAttributes($attributes);
            }
        }

        // If we couldn't instantiate any valid CTA type, return an error or default.
        if ($cta_data === null) {
            // In a real-world scenario, you might log this error.
            return '<p>Error: Invalid CTA configuration.</p>';
        }

        // Now, we can safely use the $cta_data object, knowing its type.
        // We can use instanceof checks or rely on the fact that it's a BaseCtaAttributes
        // and access common properties. For specific properties, we'd use instanceof.

        $button_classes = ['cta-button', 'cta-button--' . $cta_data->button_style->value];
        $button_html = sprintf(
            '<a href="%s" class="%s">%s</a>',
            esc_url($cta_data->button_url),
            implode(' ', $button_classes),
            esc_html($cta_data->button_text)
        );

        $output = '<div class="cta-block"';
        if ($cta_data instanceof BackgroundCtaAttributes) {
            $output .= sprintf(
                ' style="background-image: url(%s);"',
                esc_url($cta_data->background_image_url)
            );
        }
        $output .= '>';

        $output .= '<h3>' . esc_html($cta_data->title) . '</h3>';

        if ($cta_data instanceof SubtitleCtaAttributes) {
            $output .= '<p>' . esc_html($cta_data->subtitle) . '</p>';
        }

        $output .= $button_html;
        $output .= '</div>';

        return $output;
    }
}

Registering the Block and Callback

In your plugin’s main file or an initialization class, register the Gutenberg block and assign the `render_cta_block` method as its `render_callback`.

<?php
// my-plugin.php

namespace MyPlugin;

// Ensure the autoloader is set up if using Composer.
// require __DIR__ . '/vendor/autoload.php';

add_action('init', function () {
    register_block_type('my-plugin/cta-block', [
        'attributes' => [
            'title' => [
                'type' => 'string',
                'default' => '',
            ],
            'button_text' => [
                'type' => 'string',
                'default' => '',
            ],
            'button_url' => [
                'type' => 'string',
                'default' => '',
            ],
            'button_style' => [
                'type' => 'string',
                'default' => 'primary',
            ],
            'subtitle' => [
                'type' => 'string',
                'default' => '',
            ],
            'background_image_url' => [
                'type' => 'string',
                'default' => '',
            ],
        ],
        'render_callback' => [RenderCallbacks::class, 'render_cta_block'],
        // 'editor_script' => 'my-plugin-editor-script', // If you have an editor component
        // 'editor_style'  => 'my-plugin-editor-style',
        // 'style'         => 'my-plugin-style',
    ]);
});

Explanation and Benefits

1. Type Safety: By defining explicit classes for each attribute structure and using them within the `render_callback`, we ensure that the data passed to the rendering logic conforms to expected shapes. This prevents errors that might arise from unexpected attribute types or missing keys.

2. Readability and Maintainability: The code is more organized and easier to understand. Each class encapsulates the data for a specific CTA variation, making it clear what attributes are expected and how they are used.

3. Flexibility with Union Types (Conceptual): While PHP’s parameter union types don’t directly handle array-to-object mapping for `render_callback` arguments, the *principle* of accepting multiple types is achieved by the conditional instantiation logic within the `render_cta_block` function. The function effectively acts as a dispatcher, determining the correct object type based on the provided attributes.

4. Leveraging Inheritance: The use of `extends` allows us to build upon the base `BaseCtaAttributes` class, avoiding code duplication for common properties like title and button details. `BackgroundCtaAttributes` inherits from `SubtitleCtaAttributes`, which in turn inherits from `BaseCtaAttributes`, creating a clear hierarchy.

5. Enum for Controlled Values: The `ButtonStyles` enum restricts the possible values for `button_style` to a predefined set, preventing invalid CSS classes or logic errors.

Advanced Considerations and Further Improvements

Attribute Validation and Sanitization

The current `__construct` methods in the attribute classes perform basic assignment with defaults. For production, you would integrate more robust validation and sanitization. This could involve:

  • Using WordPress’s `wp_kses_post` for HTML sanitization on string attributes.
  • Validating URLs with `esc_url_raw` before storage or use.
  • Implementing custom validation logic for specific fields (e.g., image URL format).

This validation could be added within the `__construct` methods or in a separate `validate()` method called before instantiation.

Dependency Injection for Complex Logic

For very complex rendering logic, consider injecting dependencies (e.g., image manipulation services, API clients) into your attribute classes or the render callback itself. This promotes testability and separation of concerns.

Performance Optimization

While this approach enhances code quality, ensure that the rendering itself is performant. Avoid heavy database queries or external API calls directly within the `render_callback`. Cache results where appropriate. The type-hinting and structured data help in making the rendering logic itself more predictable and thus easier to optimize.

PHP Version Compatibility

Union types are available from PHP 8.0. Intersection types are available from PHP 8.1. Ensure your target WordPress environment supports these PHP versions. If not, you’ll need to refactor to use more traditional type checking (e.g., `is_a()` or `property_exists()`) and conditional logic without explicit union/intersection type hints in function signatures.

Conclusion

By adopting a structured approach with dedicated attribute classes and leveraging PHP’s modern type system features, you can build more robust, maintainable, and efficient server-side rendering for your Gutenberg blocks. This recipe provides a solid foundation for handling complex block configurations with confidence.

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