Gutenberg Blocks System
Table of Contents
Gutenberg Blocks System
Modern Block Development with Atomic Design
Jankx 2.0 sử dụng kiến trúc Gutenberg-first với hệ thống block development hiện đại, tuân thủ atomic design principles và tối ưu performance.
🧩 Block Architecture
Block Structure
blocks/
├── testimonial/
│ ├── block.json
│ ├── TestimonialBlock.php
│ ├── assets/
│ │ ├── js/
│ │ │ ├── editor.js
│ │ │ └── frontend.js
│ │ ├── css/
│ │ │ ├── editor.css
│ │ │ └── frontend.css
│ │ └── images/
│ └── templates/
│ ├── editor.html
│ └── frontend.html
├── hero/
├── features/
└── contact/
Block Class Structure
<?php
namespace Jankx\Gutenberg\Blocks;
class TestimonialBlock extends AbstractBlock
{
protected static $attributes = [
'content' => [
'type' => 'string',
'default' => '',
],
'author' => [
'type' => 'string',
'default' => '',
],
'position' => [
'type' => 'string',
'default' => '',
],
'company' => [
'type' => 'string',
'default' => '',
],
'avatar' => [
'type' => 'object',
'default' => null,
],
'rating' => [
'type' => 'number',
'default' => 5,
],
'style' => [
'type' => 'string',
'default' => 'default',
],
'alignment' => [
'type' => 'string',
'default' => 'center',
],
'showAvatar' => [
'type' => 'boolean',
'default' => true,
],
'showRating' => [
'type' => 'boolean',
'default' => true,
],
'backgroundColor' => [
'type' => 'string',
'default' => '',
],
'textColor' => [
'type' => 'string',
'default' => '',
],
];
protected static $supports = [
'align' => ['wide', 'full'],
'html' => false,
'anchor' => true,
'customClassName' => true,
'spacing' => [
'margin' => true,
'padding' => true,
],
'color' => [
'background' => true,
'text' => true,
],
];
public static function getBlockName()
{
return 'testimonial';
}
public static function getTitle()
{
return __('Testimonial', 'jankx');
}
public static function getDescription()
{
return __('Display customer testimonials with author information and ratings.', 'jankx');
}
public static function getCategory()
{
return 'jankx-blocks';
}
public static function getIcon()
{
return 'format-quote';
}
public static function getKeywords()
{
return ['testimonial', 'quote', 'review', 'customer', 'feedback'];
}
public static function render($attributes, $content)
{
$block_id = self::getBlockId($attributes);
$class_name = self::getClassName($attributes);
// Get attributes with defaults
$content = self::getAttribute($attributes, 'content', '');
$author = self::getAttribute($attributes, 'author', '');
$position = self::getAttribute($attributes, 'position', '');
$company = self::getAttribute($attributes, 'company', '');
$avatar = self::getAttribute($attributes, 'avatar', null);
$rating = self::getAttribute($attributes, 'rating', 5);
$style = self::getAttribute($attributes, 'style', 'default');
$alignment = self::getAttribute($attributes, 'alignment', 'center');
$show_avatar = self::getAttribute($attributes, 'showAvatar', true);
$show_rating = self::getAttribute($attributes, 'showRating', true);
$background_color = self::getAttribute($attributes, 'backgroundColor', '');
$text_color = self::getAttribute($attributes, 'textColor', '');
// Build inline styles
$inline_styles = [];
if ($background_color) {
$inline_styles[] = "background-color: {$background_color}";
}
if ($text_color) {
$inline_styles[] = "color: {$text_color}";
}
$style_attr = !empty($inline_styles) ? ' style="' . implode('; ', $inline_styles) . '"' : '';
// Add style and alignment classes
$class_name .= " jankx-testimonial-style-{$style} jankx-testimonial-align-{$alignment}";
// Get avatar URL
$avatar_url = '';
if ($avatar && isset($avatar['url'])) {
$avatar_url = $avatar['url'];
}
// Render testimonial
ob_start();
?>
<div id="<?php echo esc_attr($block_id); ?>" class="<?php echo esc_attr($class_name); ?>"<?php echo $style_attr; ?>>
<div class="jankx-testimonial-content">
<?php if ($show_rating && $rating > 0): ?>
<div class="jankx-testimonial-rating">
<?php for ($i = 1; $i <= 5; $i++): ?>
<span class="jankx-star <?php echo $i <= $rating ? 'filled' : 'empty'; ?>">★</span>
<?php endfor; ?>
</div>
<?php endif; ?>
<blockquote class="jankx-testimonial-quote">
<?php echo wp_kses_post($content); ?>
</blockquote>
<?php if ($author || $position || $company): ?>
<div class="jankx-testimonial-author">
<?php if ($show_avatar && $avatar_url): ?>
<div class="jankx-testimonial-avatar">
<img src="<?php echo esc_url($avatar_url); ?>" alt="<?php echo esc_attr($author); ?>" />
</div>
<?php endif; ?>
<div class="jankx-testimonial-author-info">
<?php if ($author): ?>
<div class="jankx-testimonial-author-name"><?php echo esc_html($author); ?></div>
<?php endif; ?>
<?php if ($position || $company): ?>
<div class="jankx-testimonial-author-meta">
<?php if ($position): ?>
<span class="jankx-testimonial-position"><?php echo esc_html($position); ?></span>
<?php endif; ?>
<?php if ($position && $company): ?>
<span class="jankx-testimonial-separator">, </span>
<?php endif; ?>
<?php if ($company): ?>
<span class="jankx-testimonial-company"><?php echo esc_html($company); ?></span>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
</div>
</div>
<?php
return ob_get_clean();
}
}
📋 Block Registration System
JSON-Based Registration
// block.json
{
"apiVersion": 2,
"name": "jankx/testimonial",
"title": "Testimonial",
"category": "jankx",
"icon": "format-quote",
"description": "Display customer testimonials",
"supports": {
"html": false,
"align": ["wide", "full"]
},
"attributes": {
"author": {
"type": "string",
"default": ""
},
"content": {
"type": "string",
"default": ""
},
"avatar": {
"type": "string",
"default": ""
}
},
"textdomain": "jankx",
"editorScript": "file:./assets/js/editor.js",
"editorStyle": "file:./assets/css/editor.css",
"style": "file:./assets/css/frontend.css"
}
PHP Block Scanner
class BlockRegistry
{
private $blocks = [];
public function scanBlocks()
{
$blocksDir = get_template_directory() . '/blocks/';
$blockDirs = glob($blocksDir . '*/block.json');
foreach ($blockDirs as $blockJson) {
$blockData = json_decode(file_get_contents($blockJson), true);
$this->registerBlock($blockData);
}
}
public function generateGlobalConfig()
{
$config = [];
foreach ($this->blocks as $block) {
$config[$block['name']] = $block;
}
return $config;
}
}
JavaScript Global Config
// Generated global config
window.JankxBlocks = {
'jankx/testimonial': {
name: 'jankx/testimonial',
title: 'Testimonial',
category: 'jankx',
attributes: {
author: { type: 'string', default: '' },
content: { type: 'string', default: '' },
avatar: { type: 'string', default: '' }
}
},
'jankx/hero': {
// Hero block config
}
};
🎨 Block Development
Abstract Block Class
abstract class AbstractBlock
{
protected $blockName;
protected $blockPath;
abstract public function register();
abstract public function render($attributes, $content);
protected function getBlockPath()
{
return get_template_directory() . '/blocks/' . $this->getBlockDir();
}
protected function getEditorScript()
{
return 'jankx-block-' . $this->getBlockDir() . '-editor';
}
protected function getFrontendScript()
{
return 'jankx-block-' . $this->getBlockDir() . '-frontend';
}
protected function renderTemplate($template, $data = [])
{
$templatePath = $this->getBlockPath() . '/templates/' . $template . '.html';
return $this->renderTemplateFile($templatePath, $data);
}
}
Block Editor JavaScript
// assets/js/editor.js
(function() {
const { registerBlockType } = wp.blocks;
const { createElement } = wp.element;
const { InspectorControls, useBlockProps } = wp.blockEditor;
const { PanelBody, TextControl, TextareaControl } = wp.components;
registerBlockType('jankx/testimonial', {
edit: function(props) {
const { attributes, setAttributes } = props;
const blockProps = useBlockProps();
return createElement('div', blockProps, [
createElement(InspectorControls, {}, [
createElement(PanelBody, { title: 'Testimonial Settings' }, [
createElement(TextControl, {
label: 'Author',
value: attributes.author,
onChange: (author) => setAttributes({ author })
}),
createElement(TextareaControl, {
label: 'Content',
value: attributes.content,
onChange: (content) => setAttributes({ content })
})
])
]),
createElement('div', { className: 'testimonial-preview' }, [
createElement('blockquote', {}, attributes.content),
createElement('cite', {}, attributes.author)
])
]);
},
save: function(props) {
return null; // Server-side rendering
}
});
})();
Block Frontend JavaScript
// assets/js/frontend.js
(function() {
// Frontend interactions
document.addEventListener('DOMContentLoaded', function() {
const testimonials = document.querySelectorAll('.jankx-testimonial');
testimonials.forEach(testimonial => {
// Add frontend functionality
testimonial.addEventListener('click', function() {
// Handle testimonial interactions
});
});
});
})();
🎯 Block Categories
Core Blocks
- Content Blocks: Text, image, video, gallery
- Layout Blocks: Container, grid, columns
- Interactive Blocks: Forms, buttons, navigation
- Dynamic Blocks: Posts, comments, search
Custom Blocks
- Business Blocks: Testimonials, pricing, team
- Marketing Blocks: CTA, newsletter, social
- E-commerce Blocks: Products, cart, checkout
- Utility Blocks: Breadcrumbs, pagination, search
🔧 Block Configuration
Block Attributes
protected function getBlockAttributes()
{
return [
'title' => [
'type' => 'string',
'default' => '',
],
'description' => [
'type' => 'string',
'default' => '',
],
'image' => [
'type' => 'object',
'default' => null,
],
'alignment' => [
'type' => 'string',
'default' => 'left',
],
'backgroundColor' => [
'type' => 'string',
'default' => '',
],
];
}
Block Supports
protected function getBlockSupports()
{
return [
'html' => false,
'align' => ['wide', 'full'],
'spacing' => [
'margin' => true,
'padding' => true,
],
'color' => [
'background' => true,
'text' => true,
],
'typography' => [
'fontSize' => true,
'lineHeight' => true,
],
];
}
🎨 Block Styling
Editor Styles
// assets/css/editor.scss
.wp-block-jankx-testimonial {
.testimonial-preview {
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
blockquote {
font-style: italic;
margin-bottom: 15px;
}
cite {
font-weight: bold;
color: #666;
}
}
}
Frontend Styles
// assets/css/frontend.scss
.jankx-testimonial {
background: #f9f9f9;
padding: 30px;
border-radius: 12px;
margin: 20px 0;
.testimonial-content {
font-size: 18px;
line-height: 1.6;
margin-bottom: 20px;
}
.testimonial-author {
display: flex;
align-items: center;
.author-avatar {
width: 50px;
height: 50px;
border-radius: 50%;
margin-right: 15px;
}
.author-info {
.author-name {
font-weight: bold;
margin-bottom: 5px;
}
.author-title {
color: #666;
font-size: 14px;
}
}
}
}
🔄 Block Rendering
Server-Side Rendering
public function render($attributes, $content)
{
$data = [
'author' => $attributes['author'] ?? '',
'content' => $attributes['content'] ?? '',
'avatar' => $attributes['avatar'] ?? '',
'alignment' => $attributes['alignment'] ?? 'left',
'backgroundColor' => $attributes['backgroundColor'] ?? '',
];
return $this->renderTemplate('frontend', $data);
}
Template Rendering
<!-- templates/frontend.html -->
<div class="jankx-testimonial" style="text-align: ; background-color: ;">
<div class="testimonial-content">
<blockquote><h1 id="block-registration-system">Block Registration System</h1>
<blockquote>
<p><strong>JSON-Based Block Registration with PHP Scanner</strong></p>
</blockquote>
<p>Jankx 2.0 sử dụng hệ thống block registration hiện đại dựa trên JSON, với PHP scanner tự động và global JS config generation.</p>
<h2 id="-registration-architecture">🏗 Registration Architecture</h2>
<h3 id="registration-flow">Registration Flow</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────┐
│ PHP Block Scanner │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Scan │ │ Parse │ │
│ │ block.json │ │ JSON │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ Global Config Gen │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ PHP │ │ JS │ │
│ │ Config │ │ Config │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ WordPress Registration │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ register │ │ Enqueue │ │
│ │ block_type │ │ Assets │ │
│ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────┘
</code></pre></div></div>
<h2 id="-json-based-registration">📋 JSON-Based Registration</h2>
<h3 id="block-json-structure">Block JSON Structure</h3>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="nl">"apiVersion"</span><span class="p">:</span><span class="w"> </span><span class="mi">2</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"jankx/testimonial"</span><span class="p">,</span><span class="w">
</span><span class="nl">"title"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Testimonial"</span><span class="p">,</span><span class="w">
</span><span class="nl">"category"</span><span class="p">:</span><span class="w"> </span><span class="s2">"jankx"</span><span class="p">,</span><span class="w">
</span><span class="nl">"icon"</span><span class="p">:</span><span class="w"> </span><span class="s2">"format-quote"</span><span class="p">,</span><span class="w">
</span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Display customer testimonials with author information"</span><span class="p">,</span><span class="w">
</span><span class="nl">"keywords"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"testimonial"</span><span class="p">,</span><span class="w"> </span><span class="s2">"quote"</span><span class="p">,</span><span class="w"> </span><span class="s2">"customer"</span><span class="p">,</span><span class="w"> </span><span class="s2">"review"</span><span class="p">],</span><span class="w">
</span><span class="nl">"supports"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"html"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span><span class="w">
</span><span class="nl">"align"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"wide"</span><span class="p">,</span><span class="w"> </span><span class="s2">"full"</span><span class="p">],</span><span class="w">
</span><span class="nl">"spacing"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"margin"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"padding"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"color"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"background"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"text"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"typography"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"fontSize"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
</span><span class="nl">"lineHeight"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"attributes"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"author"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"content"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"avatar"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"authorTitle"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"alignment"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">"left"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"backgroundColor"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"string"</span><span class="p">,</span><span class="w">
</span><span class="nl">"default"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"textdomain"</span><span class="p">:</span><span class="w"> </span><span class="s2">"jankx"</span><span class="p">,</span><span class="w">
</span><span class="nl">"editorScript"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:./assets/js/editor.js"</span><span class="p">,</span><span class="w">
</span><span class="nl">"editorStyle"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:./assets/css/editor.css"</span><span class="p">,</span><span class="w">
</span><span class="nl">"script"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:./assets/js/frontend.js"</span><span class="p">,</span><span class="w">
</span><span class="nl">"style"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:./assets/css/frontend.css"</span><span class="p">,</span><span class="w">
</span><span class="nl">"render_callback"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Jankx</span><span class="se">\\</span><span class="s2">Gutenberg</span><span class="se">\\</span><span class="s2">Blocks</span><span class="se">\\</span><span class="s2">TestimonialBlock::render"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<h3 id="block-directory-structure">Block Directory Structure</h3>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>blocks/
├── testimonial/
│ ├── block.json
│ ├── TestimonialBlock.php
│ ├── assets/
│ │ ├── js/
│ │ │ ├── editor.js
│ │ │ └── frontend.js
│ │ ├── css/
│ │ │ ├── editor.css
│ │ │ └── frontend.css
│ │ └── images/
│ │ └── icon.svg
│ └── templates/
│ ├── editor.html
│ └── frontend.html
├── hero/
│ ├── block.json
│ ├── HeroBlock.php
│ └── assets/
│ ├── js/
│ ├── css/
│ └── images/
└── features/
├── block.json
├── FeaturesBlock.php
└── assets/
├── js/
├── css/
└── images/
</code></pre></div></div>
<h2 id="-php-block-scanner">🔧 PHP Block Scanner</h2>
<h3 id="block-registry-implementation">Block Registry Implementation</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?php</span>
<span class="kn">namespace</span> <span class="nn">Jankx\Gutenberg</span><span class="p">;</span>
<span class="kd">class</span> <span class="nc">BlockRegistry</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$blocks</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">private</span> <span class="nv">$globalConfig</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">private</span> <span class="nv">$scanned</span> <span class="o">=</span> <span class="kc">false</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">scanBlocks</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">scanned</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$blocksDir</span> <span class="o">=</span> <span class="nf">get_template_directory</span><span class="p">()</span> <span class="mf">.</span> <span class="s1">'/blocks/'</span><span class="p">;</span>
<span class="nv">$blockDirs</span> <span class="o">=</span> <span class="nb">glob</span><span class="p">(</span><span class="nv">$blocksDir</span> <span class="mf">.</span> <span class="s1">'*/block.json'</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$blockDirs</span> <span class="k">as</span> <span class="nv">$blockJson</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">processBlockJson</span><span class="p">(</span><span class="nv">$blockJson</span><span class="p">);</span>
<span class="p">}</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">generateGlobalConfig</span><span class="p">();</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">scanned</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">processBlockJson</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockJson</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$blockData</span> <span class="o">=</span> <span class="nb">json_decode</span><span class="p">(</span><span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$blockJson</span><span class="p">),</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$blockData</span><span class="p">)</span> <span class="p">{</span>
<span class="nb">error_log</span><span class="p">(</span><span class="s2">"Invalid JSON in block.json: </span><span class="si">{</span><span class="nv">$blockJson</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$blockName</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="k">empty</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">))</span> <span class="p">{</span>
<span class="nb">error_log</span><span class="p">(</span><span class="s2">"Missing block name in: </span><span class="si">{</span><span class="nv">$blockJson</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">blocks</span><span class="p">[</span><span class="nv">$blockName</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">;</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerBlock</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerBlock</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$blockData</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$blockName</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">];</span>
<span class="nv">$blockPath</span> <span class="o">=</span> <span class="nb">dirname</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="nf">findBlockJson</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">));</span>
<span class="nv">$args</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'editor_script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'editor_style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">),</span>
<span class="s1">'style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">),</span>
<span class="p">];</span>
<span class="c1">// Add render callback if specified</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$args</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">];</span>
<span class="p">}</span>
<span class="c1">// Register block with WordPress</span>
<span class="nf">register_block_type</span><span class="p">(</span><span class="nv">$blockPath</span><span class="p">,</span> <span class="nv">$args</span><span class="p">);</span>
<span class="c1">// Register assets</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerBlockAssets</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerBlockAssets</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$blockData</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$blockName</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">];</span>
<span class="c1">// Register editor script</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'editorScript'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerScript</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">,</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'editorScript'</span><span class="p">]);</span>
<span class="p">}</span>
<span class="c1">// Register editor style</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'editorStyle'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerStyle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">,</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'editorStyle'</span><span class="p">]);</span>
<span class="p">}</span>
<span class="c1">// Register frontend script</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'script'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerScript</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">,</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'script'</span><span class="p">]);</span>
<span class="p">}</span>
<span class="c1">// Register frontend style</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'style'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerStyle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">,</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'style'</span><span class="p">]);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerScript</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$context</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$scriptPath</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$handle</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="nv">$dependencies</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptDependencies</span><span class="p">(</span><span class="nv">$context</span><span class="p">);</span>
<span class="nf">wp_register_script</span><span class="p">(</span>
<span class="nv">$handle</span><span class="p">,</span>
<span class="nf">get_theme_file_uri</span><span class="p">(</span><span class="nv">$scriptPath</span><span class="p">),</span>
<span class="nv">$dependencies</span><span class="p">,</span>
<span class="err">\</span><span class="nc">Jankx\Jankx</span><span class="o">::</span><span class="nf">getFrameworkVersion</span><span class="p">(),</span>
<span class="kc">true</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerStyle</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$context</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$stylePath</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$handle</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="nv">$context</span><span class="p">);</span>
<span class="nf">wp_register_style</span><span class="p">(</span>
<span class="nv">$handle</span><span class="p">,</span>
<span class="nf">get_theme_file_uri</span><span class="p">(</span><span class="nv">$stylePath</span><span class="p">),</span>
<span class="p">[],</span>
<span class="err">\</span><span class="nc">Jankx\Jankx</span><span class="o">::</span><span class="nf">getFrameworkVersion</span><span class="p">()</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">getScriptHandle</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$context</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$sanitizedName</span> <span class="o">=</span> <span class="nf">sanitize_title</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="nv">$context</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">getStyleHandle</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$context</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$sanitizedName</span> <span class="o">=</span> <span class="nf">sanitize_title</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="nv">$context</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">getScriptDependencies</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$context</span><span class="p">):</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nv">$dependencies</span> <span class="o">=</span> <span class="p">[</span><span class="s1">'wp-blocks'</span><span class="p">,</span> <span class="s1">'wp-element'</span><span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$context</span> <span class="o">===</span> <span class="s1">'editor'</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$dependencies</span><span class="p">[]</span> <span class="o">=</span> <span class="s1">'wp-editor'</span><span class="p">;</span>
<span class="nv">$dependencies</span><span class="p">[]</span> <span class="o">=</span> <span class="s1">'wp-components'</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nv">$dependencies</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">findBlockJson</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$blocksDir</span> <span class="o">=</span> <span class="nf">get_template_directory</span><span class="p">()</span> <span class="mf">.</span> <span class="s1">'/blocks/'</span><span class="p">;</span>
<span class="nv">$blockDir</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'jankx/'</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="nv">$blocksDir</span> <span class="mf">.</span> <span class="nv">$blockDir</span> <span class="mf">.</span> <span class="s1">'/block.json'</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="-global-config-generation">🌐 Global Config Generation</h2>
<h3 id="php-config-generator">PHP Config Generator</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">GlobalConfigGenerator</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$registry</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span><span class="kt">BlockRegistry</span> <span class="nv">$registry</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">registry</span> <span class="o">=</span> <span class="nv">$registry</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">generateConfig</span><span class="p">():</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nv">$config</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">registry</span><span class="o">-></span><span class="nf">getBlocks</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$blockName</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$config</span><span class="p">[</span><span class="nv">$blockName</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">normalizeBlockData</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nv">$config</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">normalizeBlockData</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$blockData</span><span class="p">):</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="k">return</span> <span class="p">[</span>
<span class="s1">'name'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">],</span>
<span class="s1">'title'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'title'</span><span class="p">],</span>
<span class="s1">'category'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'category'</span><span class="p">],</span>
<span class="s1">'icon'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'icon'</span><span class="p">],</span>
<span class="s1">'description'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'description'</span><span class="p">],</span>
<span class="s1">'keywords'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'keywords'</span><span class="p">]</span> <span class="o">??</span> <span class="p">[],</span>
<span class="s1">'supports'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'supports'</span><span class="p">]</span> <span class="o">??</span> <span class="p">[],</span>
<span class="s1">'attributes'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'attributes'</span><span class="p">]</span> <span class="o">??</span> <span class="p">[],</span>
<span class="s1">'textdomain'</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'textdomain'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">'jankx'</span><span class="p">,</span>
<span class="p">];</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">outputJSConfig</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$config</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">generateConfig</span><span class="p">();</span>
<span class="nv">$jsonConfig</span> <span class="o">=</span> <span class="nb">json_encode</span><span class="p">(</span><span class="nv">$config</span><span class="p">,</span> <span class="no">JSON_PRETTY_PRINT</span><span class="p">);</span>
<span class="nf">add_action</span><span class="p">(</span><span class="s1">'wp_head'</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$jsonConfig</span><span class="p">)</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"<script>window.JankxBlocks = </span><span class="si">{</span><span class="nv">$jsonConfig</span><span class="si">}</span><span class="s2">;</script>"</span><span class="p">;</span>
<span class="p">});</span>
<span class="nf">add_action</span><span class="p">(</span><span class="s1">'admin_head'</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="k">use</span> <span class="p">(</span><span class="nv">$jsonConfig</span><span class="p">)</span> <span class="p">{</span>
<span class="k">echo</span> <span class="s2">"<script>window.JankxBlocks = </span><span class="si">{</span><span class="nv">$jsonConfig</span><span class="si">}</span><span class="s2">;</script>"</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="javascript-global-config">JavaScript Global Config</h3>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Generated global config</span>
<span class="nb">window</span><span class="p">.</span><span class="nx">JankxBlocks</span> <span class="o">=</span> <span class="p">{</span>
<span class="dl">'</span><span class="s1">jankx/testimonial</span><span class="dl">'</span><span class="p">:</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx/testimonial</span><span class="dl">'</span><span class="p">,</span>
<span class="na">title</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Testimonial</span><span class="dl">'</span><span class="p">,</span>
<span class="na">category</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx</span><span class="dl">'</span><span class="p">,</span>
<span class="na">icon</span><span class="p">:</span> <span class="dl">'</span><span class="s1">format-quote</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Display customer testimonials with author information</span><span class="dl">'</span><span class="p">,</span>
<span class="na">keywords</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">testimonial</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">quote</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">customer</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">review</span><span class="dl">'</span><span class="p">],</span>
<span class="na">supports</span><span class="p">:</span> <span class="p">{</span>
<span class="na">html</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">align</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">wide</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">full</span><span class="dl">'</span><span class="p">],</span>
<span class="na">spacing</span><span class="p">:</span> <span class="p">{</span>
<span class="na">margin</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">padding</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">},</span>
<span class="na">color</span><span class="p">:</span> <span class="p">{</span>
<span class="na">background</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">text</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">},</span>
<span class="na">typography</span><span class="p">:</span> <span class="p">{</span>
<span class="na">fontSize</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">lineHeight</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">attributes</span><span class="p">:</span> <span class="p">{</span>
<span class="na">author</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">content</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">avatar</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">authorTitle</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">alignment</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">'</span><span class="s1">left</span><span class="dl">'</span>
<span class="p">},</span>
<span class="na">backgroundColor</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">textdomain</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx</span><span class="dl">'</span>
<span class="p">},</span>
<span class="dl">'</span><span class="s1">jankx/hero</span><span class="dl">'</span><span class="p">:</span> <span class="p">{</span>
<span class="na">name</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx/hero</span><span class="dl">'</span><span class="p">,</span>
<span class="na">title</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Hero Section</span><span class="dl">'</span><span class="p">,</span>
<span class="na">category</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx</span><span class="dl">'</span><span class="p">,</span>
<span class="na">icon</span><span class="p">:</span> <span class="dl">'</span><span class="s1">align-wide</span><span class="dl">'</span><span class="p">,</span>
<span class="na">description</span><span class="p">:</span> <span class="dl">'</span><span class="s1">Display hero section with title, description and CTA</span><span class="dl">'</span><span class="p">,</span>
<span class="na">keywords</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">hero</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">banner</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">cta</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">section</span><span class="dl">'</span><span class="p">],</span>
<span class="na">supports</span><span class="p">:</span> <span class="p">{</span>
<span class="na">html</span><span class="p">:</span> <span class="kc">false</span><span class="p">,</span>
<span class="na">align</span><span class="p">:</span> <span class="p">[</span><span class="dl">'</span><span class="s1">wide</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">full</span><span class="dl">'</span><span class="p">],</span>
<span class="na">spacing</span><span class="p">:</span> <span class="p">{</span>
<span class="na">margin</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">padding</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">},</span>
<span class="na">color</span><span class="p">:</span> <span class="p">{</span>
<span class="na">background</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span>
<span class="na">text</span><span class="p">:</span> <span class="kc">true</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">attributes</span><span class="p">:</span> <span class="p">{</span>
<span class="na">title</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">description</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">backgroundImage</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">ctaText</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">},</span>
<span class="na">ctaUrl</span><span class="p">:</span> <span class="p">{</span>
<span class="na">type</span><span class="p">:</span> <span class="dl">'</span><span class="s1">string</span><span class="dl">'</span><span class="p">,</span>
<span class="na">default</span><span class="p">:</span> <span class="dl">''</span>
<span class="p">}</span>
<span class="p">},</span>
<span class="na">textdomain</span><span class="p">:</span> <span class="dl">'</span><span class="s1">jankx</span><span class="dl">'</span>
<span class="p">}</span>
<span class="p">};</span>
</code></pre></div></div>
<h2 id="-block-registration-flow">🎯 Block Registration Flow</h2>
<h3 id="registration-process">Registration Process</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">BlockRegistrationManager</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$registry</span><span class="p">;</span>
<span class="k">private</span> <span class="nv">$configGenerator</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">(</span><span class="kt">BlockRegistry</span> <span class="nv">$registry</span><span class="p">,</span> <span class="kt">GlobalConfigGenerator</span> <span class="nv">$configGenerator</span><span class="p">)</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">registry</span> <span class="o">=</span> <span class="nv">$registry</span><span class="p">;</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">configGenerator</span> <span class="o">=</span> <span class="nv">$configGenerator</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">registerAllBlocks</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="c1">// 1. Scan all block.json files</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">registry</span><span class="o">-></span><span class="nf">scanBlocks</span><span class="p">();</span>
<span class="c1">// 2. Generate global config</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">configGenerator</span><span class="o">-></span><span class="nf">outputJSConfig</span><span class="p">();</span>
<span class="c1">// 3. Register with WordPress</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerWithWordPress</span><span class="p">();</span>
<span class="c1">// 4. Enqueue assets</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">enqueueBlockAssets</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerWithWordPress</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">registry</span><span class="o">-></span><span class="nf">getBlocks</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$blockName</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">registerBlock</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">registerBlock</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$blockData</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$blockName</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">];</span>
<span class="nv">$blockPath</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getBlockPath</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">);</span>
<span class="nv">$args</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'editor_script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'editor_style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">),</span>
<span class="s1">'style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">,</span> <span class="s1">'frontend'</span><span class="p">),</span>
<span class="p">];</span>
<span class="k">if</span> <span class="p">(</span><span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$args</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">]</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'render_callback'</span><span class="p">];</span>
<span class="p">}</span>
<span class="nf">register_block_type</span><span class="p">(</span><span class="nv">$blockPath</span><span class="p">,</span> <span class="nv">$args</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">enqueueBlockAssets</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nf">add_action</span><span class="p">(</span><span class="s1">'wp_enqueue_scripts'</span><span class="p">,</span> <span class="k">function</span><span class="p">()</span> <span class="p">{</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">registry</span><span class="o">-></span><span class="nf">getBlocks</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$blockName</span> <span class="o">=></span> <span class="nv">$blockData</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="nf">isBlockUsed</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">))</span> <span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="nf">enqueueBlockAssets</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">isBlockUsed</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">):</span> <span class="kt">bool</span>
<span class="p">{</span>
<span class="k">global</span> <span class="nv">$post</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$post</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="nv">$content</span> <span class="o">=</span> <span class="nv">$post</span><span class="o">-></span><span class="n">post_content</span><span class="p">;</span>
<span class="k">return</span> <span class="nb">strpos</span><span class="p">(</span><span class="nv">$content</span><span class="p">,</span> <span class="s1">'<!-- wp:'</span> <span class="mf">.</span> <span class="nv">$blockName</span><span class="p">)</span> <span class="o">!==</span> <span class="kc">false</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">enqueueBlockAssets</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$sanitizedName</span> <span class="o">=</span> <span class="nf">sanitize_title</span><span class="p">(</span><span class="nv">$blockName</span><span class="p">);</span>
<span class="c1">// Enqueue frontend styles</span>
<span class="nf">wp_enqueue_style</span><span class="p">(</span><span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-frontend"</span><span class="p">);</span>
<span class="c1">// Enqueue frontend scripts</span>
<span class="nf">wp_enqueue_script</span><span class="p">(</span><span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-frontend"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="-block-class-integration">🔧 Block Class Integration</h2>
<h3 id="abstract-block-class">Abstract Block Class</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?php</span>
<span class="kn">namespace</span> <span class="nn">Jankx\Gutenberg\Blocks</span><span class="p">;</span>
<span class="k">abstract</span> <span class="kd">class</span> <span class="nc">AbstractBlock</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="nv">$blockName</span><span class="p">;</span>
<span class="k">protected</span> <span class="nv">$blockPath</span><span class="p">;</span>
<span class="k">protected</span> <span class="nv">$blockData</span><span class="p">;</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">__construct</span><span class="p">()</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">blockName</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getBlockName</span><span class="p">();</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">blockPath</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getBlockPath</span><span class="p">();</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">blockData</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">loadBlockData</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">abstract</span> <span class="k">protected</span> <span class="k">function</span> <span class="n">getBlockName</span><span class="p">():</span> <span class="kt">string</span><span class="p">;</span>
<span class="k">abstract</span> <span class="k">public</span> <span class="k">function</span> <span class="n">register</span><span class="p">():</span> <span class="kt">void</span><span class="p">;</span>
<span class="k">abstract</span> <span class="k">public</span> <span class="k">function</span> <span class="n">render</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$attributes</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$content</span><span class="p">):</span> <span class="kt">string</span><span class="p">;</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">getBlockPath</span><span class="p">():</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$blockDir</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">'jankx/'</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="nv">$this</span><span class="o">-></span><span class="n">blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="nf">get_template_directory</span><span class="p">()</span> <span class="mf">.</span> <span class="s1">'/blocks/'</span> <span class="mf">.</span> <span class="nv">$blockDir</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">loadBlockData</span><span class="p">():</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nv">$blockJsonPath</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="n">blockPath</span> <span class="mf">.</span> <span class="s1">'/block.json'</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">file_exists</span><span class="p">(</span><span class="nv">$blockJsonPath</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="err">\</span><span class="nf">Exception</span><span class="p">(</span><span class="s2">"Block JSON not found: </span><span class="si">{</span><span class="nv">$blockJsonPath</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nv">$blockData</span> <span class="o">=</span> <span class="nb">json_decode</span><span class="p">(</span><span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$blockJsonPath</span><span class="p">),</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nv">$blockData</span><span class="p">)</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="err">\</span><span class="nf">Exception</span><span class="p">(</span><span class="s2">"Invalid JSON in block.json: </span><span class="si">{</span><span class="nv">$blockJsonPath</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nv">$blockData</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">getScriptHandle</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$context</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$sanitizedName</span> <span class="o">=</span> <span class="nf">sanitize_title</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="nv">$context</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">getStyleHandle</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$context</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$sanitizedName</span> <span class="o">=</span> <span class="nf">sanitize_title</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">blockName</span><span class="p">);</span>
<span class="k">return</span> <span class="s2">"jankx-block-</span><span class="si">{</span><span class="nv">$sanitizedName</span><span class="si">}</span><span class="s2">-</span><span class="si">{</span><span class="nv">$context</span><span class="si">}</span><span class="s2">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">renderTemplate</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$template</span><span class="p">,</span> <span class="kt">array</span> <span class="nv">$data</span> <span class="o">=</span> <span class="p">[]):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$templatePath</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="n">blockPath</span> <span class="mf">.</span> <span class="s1">'/templates/'</span> <span class="mf">.</span> <span class="nv">$template</span> <span class="mf">.</span> <span class="s1">'.html'</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nb">file_exists</span><span class="p">(</span><span class="nv">$templatePath</span><span class="p">))</span> <span class="p">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="err">\</span><span class="nf">Exception</span><span class="p">(</span><span class="s2">"Template not found: </span><span class="si">{</span><span class="nv">$templatePath</span><span class="si">}</span><span class="s2">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nv">$templateContent</span> <span class="o">=</span> <span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$templatePath</span><span class="p">);</span>
<span class="c1">// Basic template engine</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$data</span> <span class="k">as</span> <span class="nv">$key</span> <span class="o">=></span> <span class="nv">$value</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$templateContent</span> <span class="o">=</span> <span class="nb">str_replace</span><span class="p">(</span><span class="s1">' . $key . '</span><span class="p">,</span> <span class="nv">$value</span><span class="p">,</span> <span class="nv">$templateContent</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nv">$templateContent</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="example-block-implementation">Example Block Implementation</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><?php</span>
<span class="kn">namespace</span> <span class="nn">Jankx\Gutenberg\Blocks</span><span class="p">;</span>
<span class="kd">class</span> <span class="nc">TestimonialBlock</span> <span class="kd">extends</span> <span class="nc">AbstractBlock</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">function</span> <span class="n">getBlockName</span><span class="p">():</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="k">return</span> <span class="s1">'jankx/testimonial'</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">register</span><span class="p">():</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$args</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'editor_script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'editor_style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="s1">'editor'</span><span class="p">),</span>
<span class="s1">'script'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getScriptHandle</span><span class="p">(</span><span class="s1">'frontend'</span><span class="p">),</span>
<span class="s1">'style'</span> <span class="o">=></span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getStyleHandle</span><span class="p">(</span><span class="s1">'frontend'</span><span class="p">),</span>
<span class="s1">'render_callback'</span> <span class="o">=></span> <span class="p">[</span><span class="nv">$this</span><span class="p">,</span> <span class="s1">'render'</span><span class="p">],</span>
<span class="p">];</span>
<span class="nf">register_block_type</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">blockPath</span><span class="p">,</span> <span class="nv">$args</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">render</span><span class="p">(</span><span class="kt">array</span> <span class="nv">$attributes</span><span class="p">,</span> <span class="kt">string</span> <span class="nv">$content</span><span class="p">):</span> <span class="kt">string</span>
<span class="p">{</span>
<span class="nv">$data</span> <span class="o">=</span> <span class="p">[</span>
<span class="s1">'author'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'author'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span>
<span class="s1">'content'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'content'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span>
<span class="s1">'avatar'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'avatar'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span>
<span class="s1">'authorTitle'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'authorTitle'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span>
<span class="s1">'alignment'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'alignment'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">'left'</span><span class="p">,</span>
<span class="s1">'backgroundColor'</span> <span class="o">=></span> <span class="nv">$attributes</span><span class="p">[</span><span class="s1">'backgroundColor'</span><span class="p">]</span> <span class="o">??</span> <span class="s1">''</span><span class="p">,</span>
<span class="p">];</span>
<span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">renderTemplate</span><span class="p">(</span><span class="s1">'frontend'</span><span class="p">,</span> <span class="nv">$data</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="-registration-monitoring">📊 Registration Monitoring</h2>
<h3 id="block-usage-tracking">Block Usage Tracking</h3>
<div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">class</span> <span class="nc">BlockUsageTracker</span>
<span class="p">{</span>
<span class="k">private</span> <span class="nv">$usage</span> <span class="o">=</span> <span class="p">[];</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">trackBlockUsage</span><span class="p">(</span><span class="kt">string</span> <span class="nv">$blockName</span><span class="p">):</span> <span class="kt">void</span>
<span class="p">{</span>
<span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">[</span><span class="nv">$blockName</span><span class="p">]</span> <span class="o">=</span> <span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">[</span><span class="nv">$blockName</span><span class="p">]</span> <span class="o">??</span> <span class="mi">0</span><span class="p">)</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">getBlockUsage</span><span class="p">():</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">getMostUsedBlocks</span><span class="p">(</span><span class="kt">int</span> <span class="nv">$limit</span> <span class="o">=</span> <span class="mi">10</span><span class="p">):</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nb">arsort</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">array_slice</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="nv">$limit</span><span class="p">,</span> <span class="kc">true</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">function</span> <span class="n">getUnusedBlocks</span><span class="p">():</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nv">$allBlocks</span> <span class="o">=</span> <span class="nv">$this</span><span class="o">-></span><span class="nf">getAllRegisteredBlocks</span><span class="p">();</span>
<span class="nv">$usedBlocks</span> <span class="o">=</span> <span class="nb">array_keys</span><span class="p">(</span><span class="nv">$this</span><span class="o">-></span><span class="n">usage</span><span class="p">);</span>
<span class="k">return</span> <span class="nb">array_diff</span><span class="p">(</span><span class="nv">$allBlocks</span><span class="p">,</span> <span class="nv">$usedBlocks</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">function</span> <span class="n">getAllRegisteredBlocks</span><span class="p">():</span> <span class="kt">array</span>
<span class="p">{</span>
<span class="nv">$blocks</span> <span class="o">=</span> <span class="p">[];</span>
<span class="nv">$blocksDir</span> <span class="o">=</span> <span class="nf">get_template_directory</span><span class="p">()</span> <span class="mf">.</span> <span class="s1">'/blocks/'</span><span class="p">;</span>
<span class="nv">$blockDirs</span> <span class="o">=</span> <span class="nb">glob</span><span class="p">(</span><span class="nv">$blocksDir</span> <span class="mf">.</span> <span class="s1">'*/block.json'</span><span class="p">);</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$blockDirs</span> <span class="k">as</span> <span class="nv">$blockJson</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$blockData</span> <span class="o">=</span> <span class="nb">json_decode</span><span class="p">(</span><span class="nb">file_get_contents</span><span class="p">(</span><span class="nv">$blockJson</span><span class="p">),</span> <span class="kc">true</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nv">$blockData</span> <span class="o">&&</span> <span class="k">isset</span><span class="p">(</span><span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$blocks</span><span class="p">[]</span> <span class="o">=</span> <span class="nv">$blockData</span><span class="p">[</span><span class="s1">'name'</span><span class="p">];</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nv">$blocks</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<hr />
<table>
<tbody>
<tr>
<td><strong>Next</strong>: <a href="/jankx/gutenberg/layout-system/">Layout System</a></td>
<td><a href="/jankx/gutenberg/ajax-system/">AJAX System</a></td>
<td><a href="./frontend-rendering.md">Frontend Rendering</a></td>
</tr>
</tbody>
</table>
</blockquote>
</div>
<div class="testimonial-author">
<img src="" alt="" class="author-avatar">
<div class="author-info">
<div class="author-name"></div>
<div class="author-title"></div>
</div>
</div>
</div>
🚀 Performance Optimization
Lazy Loading Blocks
class LazyBlockLoader
{
public function shouldLoadBlock($blockName)
{
return $this->isBlockUsed($blockName) || $this->isBlockRequested($blockName);
}
public function loadBlockAssets($blockName)
{
if ($this->shouldLoadBlock($blockName)) {
$this->enqueueBlockAssets($blockName);
}
}
}
Asset Optimization
class BlockAssetManager
{
public function optimizeAssets()
{
// Combine CSS files
$this->combineCSS();
// Minify JavaScript
$this->minifyJS();
// Optimize images
$this->optimizeImages();
// Generate critical CSS
$this->generateCriticalCSS();
}
}
🔒 Security Considerations
Input Sanitization
protected function sanitizeAttributes($attributes)
{
return [
'author' => sanitize_text_field($attributes['author'] ?? ''),
'content' => wp_kses_post($attributes['content'] ?? ''),
'avatar' => esc_url_raw($attributes['avatar'] ?? ''),
];
}
Output Escaping
protected function escapeOutput($data)
{
return [
'author' => esc_html($data['author']),
'content' => wp_kses_post($data['content']),
'avatar' => esc_url($data['avatar']),
];
}
🧪 Testing Blocks
Unit Testing
class TestimonialBlockTest extends TestCase
{
public function testBlockRegistration()
{
$block = new TestimonialBlock();
$block->register();
$this->assertTrue(block_type_exists('jankx/testimonial'));
}
public function testBlockRendering()
{
$block = new TestimonialBlock();
$attributes = ['author' => 'John Doe', 'content' => 'Great product!'];
$output = $block->render($attributes, '');
$this->assertStringContainsString('John Doe', $output);
$this->assertStringContainsString('Great product!', $output);
}
}
Integration Testing
class BlockIntegrationTest extends TestCase
{
public function testBlockInEditor()
{
// Test block in Gutenberg editor
$this->loginAsAdmin();
$this->visit('/wp-admin/post-new.php');
$this->assertSee('Testimonial');
$this->click('Testimonial');
$this->assertSee('Author');
$this->assertSee('Content');
}
}
📊 Block Analytics
Usage Tracking
class BlockAnalytics
{
public function trackBlockUsage($blockName)
{
$usage = get_option('jankx_block_usage', []);
$usage[$blockName] = ($usage[$blockName] ?? 0) + 1;
update_option('jankx_block_usage', $usage);
}
public function getBlockUsage()
{
return get_option('jankx_block_usage', []);
}
}
Performance Monitoring
class BlockPerformanceMonitor
{
public function measureBlockRenderTime($blockName, $callback)
{
$start = microtime(true);
$result = $callback();
$end = microtime(true);
$this->logRenderTime($blockName, $end - $start);
return $result;
}
}
Next: Block Registration | Layout System | AJAX System |