
How to Develop a Custom Gutenberg Block in WordPress (Coupon Example)
Gutenberg, the block editor introduced in WordPress 5.0, is much more than a content editor. It’s also a framework for building custom blocks that empower editors to create dynamic, reusable content without touching HTML.
In this guide, we’ll go step-by-step through building a “Coupon Claim” block, but the same process applies to any custom Gutenberg block you want to create.
Why Build a Custom Gutenberg Block?
By default, WordPress offers a set of core blocks—paragraphs, images, headings, etc. But in real projects, you often need custom components:
- Product cards
- Testimonials
- Call-to-action buttons
- Event listings
- Coupons (our example)
Custom Gutenberg blocks:
- Give non-technical editors an easy UI for custom content
- Keep design consistent across pages
- Can be static (HTML stored in post content) or dynamic (PHP rendering on the frontend)
Development Environment Setup
Before building a block, you need:
- Local WordPress installation (XAMPP, MAMP, LocalWP, or Docker)
- Node.js & npm installed
- WordPress plugin development basics
We’ll create our block as a plugin so it’s portable.
Generate the Block Plugin
WordPress provides a tool to quickly scaffold a block:
npx @wordpress/create-block coupon-claim
This command:
- Creates a plugin folder (
coupon-claim/
) - Sets up
block.json
with metadata - Adds default React code (
src/edit.js
,src/save.js
) - Configures build tools (webpack, Babel)
Understanding block.json
block.json
is the configuration file for your block.
Example:
{
"apiVersion": 2,
"name": "myplugin/coupon-claim",
"title": "Coupon Claim",
"category": "widgets",
"icon": "tickets-alt",
"description": "A block to display coupons with title, code, and a claim button.",
"attributes": {
"title": { "type": "string", "default": "" },
"code": { "type": "string", "default": "" },
"desc": { "type": "string", "default": "" },
"buttonText": { "type": "string", "default": "Claim Now" },
"buttonLink": { "type": "string", "default": "" }
},
"editorScript": "file:./build/index.js"
}
Building the Editor UI (edit.js
)
Gutenberg blocks are written in React.
We’ll use InspectorControls to add settings in the editor sidebar.
import { __ } from '@wordpress/i18n';
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
import { PanelBody, TextControl, Button } from '@wordpress/components';
export default function Edit({ attributes, setAttributes }) {
const { title, code, desc, buttonText, buttonLink } = attributes;
return (
<div {...useBlockProps({ className: 'coupon-card' })}>
<InspectorControls>
<PanelBody title={__('Coupon Settings', 'coupon-claim')}>
<TextControl
label="Coupon Title"
value={title}
onChange={(v) => setAttributes({ title: v })}
/>
<TextControl
label="Coupon Code"
value={code}
onChange={(v) => setAttributes({ code: v })}
/>
<TextControl
label="Description"
value={desc}
onChange={(v) => setAttributes({ desc: v })}
/>
<TextControl
label="Button Text"
value={buttonText}
onChange={(v) => setAttributes({ buttonText: v })}
/>
<TextControl
label="Button Link"
value={buttonLink}
onChange={(v) => setAttributes({ buttonLink: v })}
/>
</PanelBody>
</InspectorControls>
<div className="coupon-preview">
<h3>{title || 'Coupon Title'}</h3>
<p>{code ? `Coupon Code: ${code}` : 'Coupon Code: XXXX'}</p>
<small>{desc || 'Coupon description here'}</small>
<br />
<Button isPrimary>{buttonText || 'Claim Now'}</Button>
</div>
</div>
);
}
Rendering on the Frontend
You can make the block static (HTML saved in post content) or dynamic (PHP rendering).
For coupons that change over time, dynamic blocks are better.
Example render_callback
in PHP:
function myplugin_render_coupon_block( $attributes ) {
ob_start();
?>
<div class="coupon-card">
<h3><?php echo esc_html( $attributes['title'] ); ?></h3>
<p>Coupon Code: <?php echo esc_html( $attributes['code'] ); ?></p>
<small><?php echo esc_html( $attributes['desc'] ); ?></small>
<br>
<a href="<?php echo esc_url( $attributes['buttonLink'] ); ?>" class="btn">
<?php echo esc_html( $attributes['buttonText'] ); ?>
</a>
</div>
<?php
return ob_get_clean();
}
Register the block in your main plugin file:
register_block_type(
__DIR__,
[ 'render_callback' => 'myplugin_render_coupon_block' ]
);
Build & Test
Run:
npm run build
This compiles your React code from src/
into build/
, which WordPress uses.
Then:
- Activate the plugin in WordPress Admin → Plugins.
- Open the block editor.
- Search for “Coupon Claim” in the block inserter.
- Customize and insert into your post/page.
Next Steps
You can extend this coupon block by:
- Adding an expiry date with a countdown timer.
- Pulling live coupon data from WooCommerce.
- Letting editors choose colors and styles.
- Tracking coupon clicks for analytics.
In short:
Developing Gutenberg blocks follows a clear workflow:
- Scaffold the block (
npx @wordpress/create-block
). - Configure
block.json
. - Build the editor UI in React.
- Render content (static or dynamic).
- Compile and test.
Once you understand this pattern, you can build any type of custom content block for WordPress.
Comments are closed.