Skip to content
Development
Command

/wp-block

Scaffold a custom WordPress block (block.json, edit.js, save.js or render.php, styles) ready to register inside a block theme.

From plugin
wp-block-theme-converter
4511 skills1 agent11 commands1 hook
Install
> /plugin marketplace add siddik-web/wp-block-theme-converter
> /plugin install wp-block-theme-converter@siddik-web

How it fires

How this command gets triggered: by you, by Claude, or both.

  • Fires itselfClaude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/wp-block

Context preview

What this command does when you run it.

Scaffold a custom WordPress block (block.json, edit.js, save.js or render.php, styles) ready to register inside a block theme.

Command definition

wp-block.md
description: Scaffold a custom WordPress block (block.json, edit.js, save.js or render.php, styles) ready to register inside a block theme.

/wp-block

**Purpose:** Scaffold a custom WordPress block — `block.json`, `edit.js`, `save.js` or `render.php`, `style.css`, and `editor.css` — ready to register inside a block theme.

When to Use

Use this command when no core block (or combination of core blocks in a pattern) satisfies the requirement. Ask before scaffolding a custom block:

> "This interaction/layout could also be achieved with a `core/group` + Interactivity API pattern. Do you want a custom block, or would a block pattern be simpler?"

Only proceed with a custom block if the user confirms or the use case clearly requires it (e.g., server-side dynamic rendering with custom REST data, deeply custom editor UI, registering a new block type for a plugin).

Workflow

Step 1: Gather Block Requirements

Ask (or infer from context):

| Question | Default if silent | |----------|-------------------| | Block name (human-readable) | Required — always ask | | Block slug (`namespace/block-name`) | Derive from theme slug + block name | | Block category | `theme` | | Block type: **static** (save.js renders HTML) or **dynamic** (render.php renders HTML server-side) | Ask — explain the tradeoff below | | Attributes needed | Infer from description | | Supports needed (innerBlocks, align, color, typography, spacing) | Minimal — only what's asked | | Icon | `block-default` (dashicons slug) | | Keywords | 3 inferred from block name |

**Static vs Dynamic — explain the tradeoff:**

| | Static Block | Dynamic Block | |--|-------------|---------------| | Output stored in | Post content (HTML) | Database (attributes only) | | Re-renders when | Post saved | Every page load | | Best for | Design components (hero, card, CTA) | Data-driven content (recent posts, live inventory) | | `save.js` | Required | Must return `null` | | `render.php` | Not used | Required |

Step 2: Plan the Block Structure

State the file list before generating:

BLOCK PLAN: {{namespace}}/{{block-name}}
Type: Static | Dynamic
Files to generate:
  blocks/{{block-name}}/block.json
  blocks/{{block-name}}/edit.js
  blocks/{{block-name}}/save.js          (static only)
  blocks/{{block-name}}/render.php       (dynamic only)
  blocks/{{block-name}}/style.css
  blocks/{{block-name}}/editor.css
  inc/block-registration.php             (only if not already present)
Attributes: [list]
Supports: [list]

Step 3: Generate block.json

> For the complete `block.json` schema — all properties, every attribute type, deprecated API versions — see [`references/custom-blocks.md`](../references/custom-blocks.md).

{
    "$schema": "https://schemas.wp.org/trunk/block.json",
    "apiVersion": 3,
    "name": "{{namespace}}/{{block-name}}",
    "version": "1.0.0",
    "title": "{{Block Name}}",
    "category": "{{category}}",
    "icon": "{{icon}}",
    "description": "{{One-line description}}",
    "keywords": ["{{keyword1}}", "{{keyword2}}", "{{keyword3}}"],
    "textdomain": "{{text-domain}}",
    "attributes": {
        {{attributes}}
    },
    "supports": {
        {{supports}}
    },
    "style": "file:./style.css",
    "editorStyle": "file:./editor.css",
    "editorScript": "file:./edit.js",
    "viewScript": "file:./view.js"
}

**Attribute type reference:**

| Data | `type` | `default` example | |------|--------|-------------------| | Short text | `"string"` | `""` | | Long/rich text | `"string"` + `"source": "html"` | `""` | | True/false toggle | `"boolean"` | `false` | | Number | `"number"` | `0` | | URL | `"string"` | `""` | | Image (media picker) | `"object"` with `id`, `url`, `alt` sub-attrs | see below | | Array of items | `"array"` | `[]` | | Color (free) | `"string"` | `""` |

Image attribute pattern:

"image": {
    "type": "object",
    "default": { "id": 0, "url": "", "alt": "" }
}

**Supports reference (only include what's needed):**

"supports": {
    "html": false,
    "align": ["wide", "full"],
    "color": { "background": true, "text": true, "gradients": true },
    "typography": { "fontSize": true, "lineHeight": true },
    "spacing": { "margin": true, "padding": true, "blockGap": true },
    "dimensions": { "minHeight": true },
    "position": { "sticky": false }
}

Step 4: Generate edit.js

import { __ } from '@wordpress/i18n';
import { useBlockProps{{, InnerBlocks, RichText, MediaUpload, InspectorControls}} } from '@wordpress/block-editor';
import { PanelBody, TextControl, ToggleControl } from '@wordpress/components';

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

    return (
        <>
            {/* Inspector sidebar controls */}
            <InspectorControls>
                <PanelBody title={ __( '{{Block Name}} Settings', '{{text-domain}}' ) }>
                    {/* Controls mapped to attributes */}
                </PanelBody>
            </InspectorControls>

            {/* Block canvas */}
            <div { ...blockProps }>
                {/* Editable block content */}
            </div>
        </>
    );
}

**Common edit.js patterns — include only what's needed:**

| Need | Import + JSX | |------|-------------| | Editable heading | `RichText` with `tagName`, `value`, `onChange` | | Editable paragraph | `RichText` with `tagName="p"` | | Media picker (image) | `MediaUpload` + `MediaUploadCheck` | | Nested blocks | `InnerBlocks` with optional `allowedBlocks`, `template` | | Sidebar text field | `TextControl` inside `InspectorControls > PanelBody` | | Sidebar toggle | `ToggleControl` inside `InspectorControls > PanelBody` | | Color picker | `PanelColorSettings` or `useSettings` from `@wordpress/block-editor` |

Step 5: Generate save.js (Static blocks only)

import { useBlockProps{{, RichText, InnerBlocks}} } from '@wor
Read more
Ships withwp-block-theme-converter

A Claude Code plugin (and standalone skill) for converting any HTML/CSS/JavaScript project into a production-ready WordPress Block Theme (Full Site Editing). Author: Md Siddiqur Rahman License: MIT

Get the whole plugin
Stats
45
Stars
14
Forks
Maintained
Maintenance
Go Template
Language
MIT
License
3mo ago
Last commit
5mo ago
Created

Repo: siddik-web/wp-block-theme-converter

Other commands on wp-block-theme-converter.