WP Manifestindependent plugin directory
manifest / editor / broke-blocks

Broke Blocks

A designless polymorphic block that can be any HTML element.

by Broke · github.com/danielrsnell/broke-blocks

4stars
1forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/danielrsnell/broke-blocks/archive/refs/heads/main.zip

Readme

Broke Blocks

A designless polymorphic WordPress Gutenberg block that can transform into any HTML element with full attribute control. Build anything from simple paragraphs to complex dynamic templates using a single, flexible block.

Features

Core Capabilities

  • 🎯 Polymorphic HTML Elements: Transform into any HTML tag (div, section, article, img, a, h1-h6, etc.)
  • 🎨 Designless Architecture: Zero injected styles - your theme controls the appearance
  • ⚙️ Full Attribute Control: Set any HTML attributes (id, class, style, data-, aria-, href, src, etc.)
  • 🔄 Bidirectional Parsing: Convert HTML ↔ Blocks with 100% structural consistency
  • 🌲 Timber/Twig Integration: Dynamic content with loop, if, and set tags
  • 🎭 Custom Web Components: Support for custom elements with hyphens
  • 📦 No Wrapper Elements: Direct HTML output, no WordPress wrapper divs

Advanced Features

  • Plain Classes Manager: Tokenized UI for easy CSS class management with Tailwind support
  • Image Settings Panel: Visual media library picker with metadata
  • Link Settings Panel: Post/page picker or external URL with target and ARIA controls
  • Preview Context System: Test Timber/Twig templates with real post/WooCommerce data
  • Dynamic Tag Settings: Context-aware inputs for loop, if, and set tags
  • HTML Import/Export: Paste HTML to create blocks, export blocks to HTML
  • Automatic Block IDs: Unique identifiers for targeting and debugging

Installation

Quick Start

  1. Clone or download this repository into wp-content/plugins/
  2. Install dependencies and build:
    cd universal-block
    npm install
    npm run build
  3. Activate Broke Blocks in WordPress Admin → Plugins

Requirements

  • WordPress 6.0+
  • PHP 7.4+
  • Node.js 18+ (for development)
  • Timber 2+ (for dynamic features - installed via Composer)

Development

# Install dependencies
npm install

# Development mode (watch with hot reload)
npm run start
# or
npm run dev

# Production build
npm run build

# Linting
npm run lint:js         # Lint JavaScript files
npm run lint:css        # Lint CSS files

# Formatting
npm run format:js       # Format JavaScript with Prettier

# Testing
npm run test            # Run unit tests

Usage

Basic Usage

  1. Insert Block: Add "Element" block in the editor
  2. Choose Tag: Select from common tags (div, section, article, etc.) or enter custom tag
  3. Set Content Type:
    • Blocks: Container with nested blocks (InnerBlocks)
    • Text: Rich text content (RichText)
    • HTML: Raw HTML via Ace Editor with Emmet support
    • Empty: Self-closing/void elements (img, hr, br)
  4. Add Classes: Use the Plain Classes Manager for easy class management
  5. Configure Attributes: Set id, data-, aria-, or any HTML attribute

Content Types Explained

Blocks (Container)

Use for layout elements that contain other blocks:

<div class="container mx-auto">
  <!-- Other blocks nested here -->
</div>

Text

Use for inline text elements:

<h1>Welcome to My Site</h1>
<p>This is a paragraph of text.</p>

HTML

Use for complex markup, SVGs, or custom code:

<svg viewBox="0 0 100 100">
  <circle cx="50" cy="50" r="40" />
</svg>

Empty

Use for self-closing elements:

<img src="image.jpg" alt="Description" />
<hr />

Dynamic Content with Timber

Use Twig control attributes for dynamic templating:

Set Variables

<div setVariable="featured_image" setExpression="post.thumbnail.src"></div>

Conditional Rendering

<div conditionalExpression="user.ID > 0">
  <p>Welcome back, {{ user.display_name }}!</p>
</div>

Loops

<div loopSource="posts" loopVariable="item">
  <h2>{{ item.title }}</h2>
  <p>{{ item.excerpt }}</p>
</div>

Learn more:

Image Management

When tag is <img>, the Image Settings Panel appears:

  • Visual media library picker
  • Automatic alt text, width, and height
  • Preview with replace/remove options

Link Management

When tag is <a>, the Link Settings Panel appears:

  • Internal Links: Select from posts/pages by post type
  • External Links: Manual URL entry
  • Target Control: Open in new tab with automatic rel="noopener noreferrer"
  • ARIA Labels: Accessibility improvements

HTML ↔ Block Conversion

HTML to Blocks (Import)

  1. Click Import HTML button in sidebar
  2. Paste or write HTML in Ace Editor
  3. Click Import - HTML is parsed into nested blocks

Blocks to HTML (Export)

  1. Select a block with nested content
  2. Click To HTML button
  3. Block tree converts to clean HTML string

Both conversions preserve:

  • Exact DOM structure
  • All attributes (including custom data- and aria-)
  • Twig control attributes (loopSource, conditionalExpression, setVariable, etc.)

Learn more: docs/lib-parsers.md

Dynamic Preview System

Test Timber/Twig templates with live data in the editor:

  1. Click the Database icon in block toolbar to toggle dynamic preview
  2. Preview uses window.universal.preview context with current page data
  3. Renders with real Timber context (post, user, custom fields, WooCommerce)
  4. Phase 1: UI toggle implemented (full preview functionality coming soon)

Learn more: docs/dynamic-preview.md

Architecture

Tag-Based System

Blocks are defined by:

  • Tag Name: HTML element (p, div, h1, img, loop, if, set)
  • Content Type: How content is handled (text, blocks, html, empty)
  • Category: Logical grouping (common, layout, text, media, dynamic, custom)

Configuration: src/config/tags/

Dual Rendering

Editor (React):

  • Main component: src/components/Edit.js
  • Tag selection toolbar
  • Plain Classes Manager (always visible)
  • Context-aware settings panels
  • Dynamic preview mode

Frontend (PHP):

Key Components

UI Components:

Utilities:

PHP Backend:

File Structure

universal-block/
├── src/                              # React source files
│   ├── components/                   # UI components
│   │   ├── Edit.js                  # Main editor component
│   │   ├── TagControls.js           # Tag selection UI
│   │   ├── ClassesPanel.js          # CSS class management
│   │   ├── AttributesPanel.js       # Attributes editor
│   │   ├── TwigControlsPanel.js     # Twig configuration
│   │   └── AceEditor.js             # HTML editor
│   ├── config/tags/                  # Tag configuration
│   │   ├── index.js                 # Tag definitions
│   │   └── categories.js            # Category groupings
│   ├── utils/                        # Utility functions
│   │   ├── htmlToBlocks.js          # HTML parser integration
│   │   └── blocksToHtml.js          # HTML serializer integration
│   └── index.js                      # Main entry point
├── includes/                         # PHP backend
│   ├── blocks/                       # Block rendering
│   │   ├── render-element.php       # Server-side render
│   │   └── class-block-processor.php # Block tree processing
│   ├── parser/                       # Twig attribute parser
│   │   └── class-dynamic-tag-parser.php
│   ├── twig/                         # Twig utilities
│   │   └── class-twig-helpers.php   # Helper functions
│   ├── editor/                       # Editor customizations
│   │   └── class-editor-tweaks.php  # Editor enhancements
│   └── admin/                        # Admin functionality
├── assets/                           # Static assets
│   ├── global/                       # Third-party libraries
│   │   ├── ace/                     # Ace Editor
│   │   ├── emmet/                   # Emmet abbreviations
│   │   └── beautify/                # HTML beautifier
│   └── react-components/             # Standalone React apps
│       └── editor-tweaks/           # Enhanced sidebar UI
│           ├── HtmlEditorPopup.js   # HTML editor modal
│           └── AceEditor.js         # Ace wrapper component
├── lib/                              # Standalone libraries
│   ├── html2blocks.js               # HTML to blocks parser
│   └── blocks2html.js               # Blocks to HTML serializer
├── package/                          # CLI tool for pattern generation
│   ├── src/                         # Parser implementations
│   │   ├── htmlToBlocks.js          # Node.js HTML parser
│   │   ├── blocksToHtml.js          # Node.js serializer
│   │   └── htmlToPattern.js         # Pattern file generator
│   ├── bin/cli.js                   # CLI entry point
│   ├── CONVERT.md                   # Conversion guide
│   └── CHANGELOG.md                 # Version history
├── docs/                             # Documentation
│   ├── lib-parsers.md               # Parser documentation
│   ├── writing-dynamic-html.md      # Dynamic content guide
│   └── dynamic-preview.md           # Preview system docs
├── _legacy/                          # Legacy code (archived)
├── build/                            # Build output (generated)
├── universal-block.php               # Main plugin file
├── block.json                        # Block metadata
├── package.json                      # Node.js dependencies
├── CLAUDE.md                         # AI development guide
└── README.md                         # This file

Documentation

Core Concepts

  • CLAUDE.md - Complete development guide and architecture overview
  • block.json - Block registration and metadata

Parsers & CLI

Dynamic Features

CLI Tool

Convert HTML files to WordPress PHP patterns:

# Install CLI globally
cd package
npm install
npm link

# Convert single file
universal-block convert hero.html --namespace=mytheme

# Convert directory
universal-block convert ./patterns -o ./theme/patterns --namespace=mytheme --category="featured"

# With full metadata
universal-block convert page.html \
  --namespace=mytheme \
  --category="pages,layouts" \
  --description="Custom page layout"

Learn more: package/CONVERT.md

Timber Context & Twig Helpers

Available Context Variables

  • post - Current post object with meta, thumbnail, etc.
  • user - Current user with ID, display_name, etc.
  • page_data - Custom page data via filters
  • fun - Call any PHP function (e.g., fun.get_bloginfo('name'))
  • timber - Access Timber methods (e.g., timber.get_posts())
  • Test variables for preview mode

Basic Usage

<div loopSource="posts" loopVariable="post">
  <h2>{{ post.title }}</h2>
  <img src="{{ post.thumbnail.src }}" alt="{{ post.thumbnail.alt }}" />
  <p>By {{ post.author.display_name }}</p>
</div>

Twig Helper Objects

Call WordPress functions and Timber methods directly in templates:

{# WordPress functions via fun object #}
<title>{{ fun.get_bloginfo('name') }}</title>
<span>${{ fun.number_format(product.price, 2) }}</span>

{# Timber methods via timber object #}
{% set related = timber.get_posts('category=' ~ post.category.slug) %}

See docs/twig-helpers.md for complete guide.

Attribute Storage

  • globalAttrs: All HTML attributes EXCEPT class (id, style, data-, aria-, href, src, etc.)
  • className: WordPress-managed classes (CSS class string)
  • content: Text/HTML content (not used for blocks contentType)
  • tagName: Current HTML element
  • contentType: Content handling mode (blocks, text, html, empty)
  • loopSource: Twig loop expression (e.g., "posts", "items")
  • loopVariable: Loop item variable name (default: "item")
  • conditionalExpression: Twig conditional (e.g., "user.ID > 0")
  • setVariable: Variable name for set tags
  • setExpression: Variable value expression
  • dynamicPreview: Flag for dynamic preview mode (Phase 1)

Read the full README on GitHub →