Skip to content

Custom Block Transformers

WP Block to HTML provides a flexible API for creating custom block transformers to handle special cases or extend support for custom blocks.

Introduction to Block Transformers

Block transformers are functions that convert WordPress block data into HTML. The library includes default transformers for all WordPress core blocks, but you can create custom transformers for:

  1. Custom Blocks: Handle blocks from plugins or custom WordPress implementations
  2. Special Styling: Apply custom styling or structure to specific blocks
  3. Extended Functionality: Add additional features like analytics tracking or special attributes

Creating a Custom Block Transformer

The createBlockHandler function makes it easy to create custom block transformers:

javascript
import { createBlockHandler, convertBlocks } from 'wp-block-to-html';

const customParagraphHandler = createBlockHandler('core/paragraph', {
  transform(block, options) {
    const { attrs = {}, innerContent = [] } = block;
    const { align = '', fontSize = '', dropCap = false } = attrs;
    
    // Extract text content from the paragraph
    const content = innerContent[0].replace(/<\/?p[^>]*>/g, '');
    
    // Apply custom styling based on attributes
    let className = '';
    if (align) {
      className += options.cssFramework === 'tailwind' 
        ? `text-${align} ` 
        : `has-text-align-${align} `;
    }
    
    if (fontSize) {
      className += options.cssFramework === 'tailwind'
        ? `text-${fontSize} `
        : `has-${fontSize}-font-size `;
    }
    
    if (dropCap) {
      className += options.cssFramework === 'tailwind'
        ? 'first-letter:text-5xl first-letter:font-bold first-letter:float-left first-letter:mr-2 '
        : 'has-drop-cap ';
    }
    
    return `<p class="${className.trim()}">${content}</p>`;
  }
});

// Use the custom transformer
const html = convertBlocks(blockData, {
  blockTransformers: {
    'core/paragraph': customParagraphHandler
  }
});

Block Transformer Interface

A block transformer must implement the transform method:

typescript
interface BlockTransformer {
  transform(block: WordPressBlock, options: ConversionOptions): string;
}
  • block: The WordPress block object to transform
  • options: The configuration options for the conversion
  • Returns: HTML string representing the transformed block

Overriding Default Transformers

You can override the default transformers for core blocks by providing your own in the blockTransformers option:

javascript
import { convertBlocks } from 'wp-block-to-html';

const html = convertBlocks(blockData, {
  blockTransformers: {
    'core/heading': {
      transform(block, options) {
        const { attrs = {} } = block;
        const { level = 2, content = '', align = '' } = attrs;
        
        // Custom implementation for headings
        return `<h${level} class="custom-heading ${align ? `align-${align}` : ''}">${content}</h${level}>`;
      }
    }
  }
});

Handling Custom WordPress Blocks

For blocks from plugins or custom implementations:

javascript
import { createBlockHandler, convertBlocks } from 'wp-block-to-html';

// Handler for a custom testimonial block
const testimonialBlockHandler = createBlockHandler('acme/testimonial', {
  transform(block, options) {
    const { attrs = {}, innerBlocks = [] } = block;
    const { author = '', role = '', rating = 5 } = attrs;
    
    // Process the content from inner blocks
    let testimonialContent = '';
    if (innerBlocks.length > 0) {
      testimonialContent = innerBlocks.map(innerBlock => 
        convertBlocks(innerBlock, options)
      ).join('');
    }
    
    // Generate stars for rating
    const stars = '★'.repeat(rating) + '☆'.repeat(5 - rating);
    
    // Return custom HTML structure
    return `
      <div class="testimonial">
        <div class="testimonial-content">${testimonialContent}</div>
        <div class="testimonial-meta">
          <div class="testimonial-author">${author}</div>
          <div class="testimonial-role">${role}</div>
          <div class="testimonial-rating">${stars}</div>
        </div>
      </div>
    `;
  }
});

// Use the custom block handler
const html = convertBlocks(blockData, {
  blockTransformers: {
    'acme/testimonial': testimonialBlockHandler
  }
});

Accessing CSS Framework Options

Block transformers have access to the current CSS framework and custom class mappings:

javascript
createBlockHandler('core/button', {
  transform(block, options) {
    const { attrs = {}, innerContent = [] } = block;
    const { url = '#', text = '', style = {} } = attrs;
    
    // Get appropriate button classes based on CSS framework
    let className = '';
    
    if (options.cssFramework === 'tailwind') {
      className = 'px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600';
    } else if (options.cssFramework === 'bootstrap') {
      className = 'btn btn-primary';
    } else {
      className = 'wp-block-button__link';
    }
    
    // Apply custom style
    const styleAttr = style.color 
      ? `style="background-color:${style.color.background};color:${style.color.text}"` 
      : '';
    
    return `<a href="${url}" class="${className}" ${styleAttr}>${text}</a>`;
  }
});

Common Use Cases

Adding Data Attributes

javascript
createBlockHandler('core/image', {
  transform(block, options) {
    const { attrs = {} } = block;
    const { url, alt = '', id, width, height } = attrs;
    
    // Add data attributes for lazy loading, lightbox, etc.
    return `
      <img 
        src="${url}" 
        alt="${alt}" 
        width="${width}" 
        height="${height}"
        data-id="${id}"
        data-lightbox="gallery"
        data-caption="${alt}"
      />
    `;
  }
});

Adding Analytics Tracking

javascript
createBlockHandler('core/button', {
  transform(block, options) {
    const { attrs = {} } = block;
    const { url = '#', text = '' } = attrs;
    
    // Add analytics tracking attributes
    return `
      <a 
        href="${url}" 
        class="button" 
        data-tracking="true"
        data-event-category="Button"
        data-event-action="Click"
        data-event-label="${text}"
      >
        ${text}
      </a>
    `;
  }
});

Supporting Third-Party Blocks

javascript
// Support for a WooCommerce product block
createBlockHandler('woocommerce/product', {
  transform(block, options) {
    const { attrs = {} } = block;
    const { id, showPrice = true, showTitle = true, showImage = true } = attrs;
    
    // In a real implementation, you might fetch product data
    // or use data already available in the block
    
    return `
      <div class="product" data-product-id="${id}">
        ${showImage ? '<div class="product-image"><!-- Image HTML --></div>' : ''}
        ${showTitle ? '<h3 class="product-title">Product Title</h3>' : ''}
        ${showPrice ? '<div class="product-price">$99.99</div>' : ''}
        <button class="add-to-cart">Add to Cart</button>
      </div>
    `;
  }
});

Best Practices

When creating custom block transformers:

  1. Respect Content Handling Mode: Check options.contentHandling to decide how to process content
  2. Framework Compatibility: Adapt your output based on options.cssFramework
  3. Handle Nested Blocks: Use convertBlocks recursively for inner blocks
  4. Sanitize Content: Ensure your output HTML is properly sanitized
  5. Preserve Accessibility: Maintain important accessibility attributes
  6. Consider SSR: If using server-side rendering, maintain compatibility with optimizations

Released under the MIT License.