How to Create a Custom WordPress Block from Scratch
Creating custom WordPress blocks allows you to extend the Gutenberg editor with your own unique content elements. This guide will walk you through the entire process of developing a custom block from scratch using modern WordPress development practices.
Prerequisites
Before we begin, ensure you have:
- WordPress 5.8+ (with Gutenberg enabled)
- Node.js (v14+) and npm installed
- A local development environment (Local by Flywheel, XAMPP, etc.)
- Basic knowledge of JavaScript (ES6+) and React
1. Setting Up the Development Environment
Install the Required Tools
First, install the official WordPress block development toolchain:
npm install -g @wordpress/create-block
Create a New Block Plugin
Run the following command to scaffold a new block:
npx @wordpress/create-block custom-block
cd custom-blockThis creates a new plugin with:
- A ready-to-use block structure
- Webpack configuration
- Modern JavaScript/React setup. Our YouTube channel; https://www.youtube.com/@easythemestore
2. Understanding the Block Structure
The generated plugin contains these key files:
custom-block/ ├── build/ # Compiled assets ├── src/ # Source files │ ├── block.json # Block metadata │ ├── edit.js # Editor component │ ├── index.js # Main block file │ └── save.js # Frontend render ├── package.json # NPM dependencies └── plugin.php # Main plugin file
3. Customizing Your Block
Let’s modify the default block to create a “Call to Action” block.
Update block.json
Modify the metadata in src/block.json:
{ "apiVersion": 2, "name": "custom-block/cta", "title": "Call to Action", "category": "design", "icon": "megaphone", "description": "A customizable call-to-action block", "attributes": { "heading": { "type": "string", "source": "html", "selector": "h2" }, "content": { "type": "string", "source": "html", "selector": "p" } } }
Edit the Block Component (edit.js)
Update src/edit.js to include editable fields:
import { useBlockProps, RichText } from '@wordpress/block-editor'; export default function Edit({ attributes, setAttributes }) { return ( <div {...useBlockProps()}> <RichText tagName="h2" value={attributes.heading} onChange={(heading) => setAttributes({ heading })} placeholder="Enter heading..." /> <RichText tagName="p" value={attributes.content} onChange={(content) => setAttributes({ content })} placeholder="Enter content..." /> </div> ); }
Define Frontend Output (save.js)
Update src/save.js to render the block:
import { useBlockProps, RichText } from '@wordpress/block-editor'; export default function save({ attributes }) { return ( <div {...useBlockProps.save()}> <RichText.Content tagName="h2" value={attributes.heading} /> <RichText.Content tagName="p" value={attributes.content} /> </div> ); }
4. Adding Block Styles
Add custom CSS for your block:
Editor Styles
Create src/editor.scss:
.wp-block-custom-block-cta { background: #f0f0f0; padding: 20px; border-radius: 5px; h2 { color: #2271b1; } }
Frontend Styles
Create src/style.scss:
.wp-block-custom-block-cta { background: #ffffff; border: 1px solid #ddd; padding: 30px; margin: 20px 0; h2 { color: #333; margin-top: 0; } }
5. Building and Testing the Block
Compile your block:
npm run buildThen:
- Upload the entire
custom-blockfolder to/wp-content/plugins/ - Activate the plugin in WordPress admin
- Add your new block in the Gutenberg editor
6. Advanced Customizations
Add Block Controls
Add a color picker to the block toolbar:
import { PanelColorSettings } from '@wordpress/block-editor'; // Add to your Edit component <InspectorControls> <PanelColorSettings title="Color Settings" colorSettings={[ { value: attributes.bgColor, onChange: (bgColor) => setAttributes({ bgColor }), label: "Background Color", } ]} /> </InspectorControls>
Add Block Variations
Create multiple style variations in block.json:
"styles": [ { "name": "default", "label": "Default", "isDefault": true }, { "name": "outline", "label": "Outline" } ]
7. Best Practices for Block Development
- Use WordPress Components (RichText, InspectorControls, etc.)
- Make Blocks Accessible (proper ARIA labels, keyboard navigation)
- Optimize Performance (avoid unnecessary re-renders)
- Follow WordPress Coding Standards
- Test Across Devices (mobile, tablet, desktop)
Conclusion
You’ve now created a fully functional custom WordPress block from scratch! This foundation can be extended with:
- Dynamic content rendering
- InnerBlocks for nested content
- Server-side rendering for complex blocks
- Block patterns for pre-designed layouts
🚀 Next Steps:
- Explore the Block Editor Handbook
- Learn about block templates and patterns
- Experiment with dynamic blocks using PHP
This guide gives you everything needed to start building professional-grade WordPress blocks. Happy coding! 💻
