Welcome to the Spectra Blocks team! This documentation covers everything you need to know about developing for both Spectra Blocks (free) and Spectra Blocks Pro.
Spectra Blocks is the next-generation rewrite (V3) of the original Spectra/UAG plugin. It is built from the ground up using modern WordPress APIs — the Interactivity API, block.json API v3, CSS custom properties, and PSR-4 autoloading.
- Prerequisites
- Working with Gutenberg
- Working with Spectra Blocks
- File Structure — Spectra Blocks (Free)
- File Structure — Spectra Blocks Pro
- Architecture & Key Concepts
- Block Anatomy (V3)
- Creating a Spectra Block
- Extensions
- Dynamic CSS & Interactivity API
- Admin Dashboard
- Working with Spectra Blocks Pro
- Coding Standards
- Build System
- Testing
- Spectra SDLC
- FAQs
- Node.js — v23.5.0 (use a version manager like nvm)
- PHP — 8.1+ (spectra-blocks), 7.4+ (spectra-blocks-pro)
- WordPress — 6.6+ (required for Interactivity API and nested block variations)
- Composer — for PHP dependencies (requires SSH access to BSF private repos)
- Code Editor — VS Code recommended (with ESLint, Stylelint, PHP Intelephense)
- Local — Local by Flywheel for WordPress development
- Git — GitHub Desktop or CLI; repos at
github.com/brainstormforce/
| Category | Technologies |
|---|---|
| Base | HTML, CSS, JavaScript (ES6+), PHP 8.1+ |
| Frontend | React, WordPress Interactivity API, Swiper, CountUp.js |
| Styling | SCSS, Tailwind CSS (admin), CSS Custom Properties |
| State | @wordpress/data, React Redux (admin) |
| Build | @wordpress/scripts (webpack), Grunt (release tasks) |
| PHP | WordPress Plugin API, PSR-4 autoloading, WPCS |
| Testing | PHPUnit, Playwright (E2E), PHPStan, ESLint, Stylelint, PHPCS |
- WordPress block development (Block Editor Handbook)
- WordPress Interactivity API (
data-wp-interactive,data-wp-bind, etc.) register_block_type_from_metadata()andblock.jsonAPI v3- WordPress hooks and filters
- React functional components with hooks
- Git branching and PR workflow
If you're new to Gutenberg block development, start here:
- Plugin Development — Read the official WordPress Plugin Developer Handbook
- Block Development — Work through the Block Editor Handbook tutorials
- Interactivity API — Study the Interactivity API Reference (this is core to V3)
| Package | Purpose |
|---|---|
@wordpress/blocks |
Block registration |
@wordpress/block-editor |
Editor components (InspectorControls, BlockControls) |
@wordpress/components |
UI components (PanelBody, TextControl, etc.) |
@wordpress/data |
Data stores and selectors |
@wordpress/interactivity |
Frontend interactivity (V3 core) |
@wordpress/element |
React wrapper |
@wordpress/i18n |
Internationalization |
@wordpress/compose |
Higher-order components and hooks |
Before working on Spectra, create a standalone Gutenberg block plugin using @wordpress/create-block. Build one of:
- A closeable message block with SVG icon, editable message, and dismiss button
- A price card with title, description, image, and variant selectors
- An interactive user profile with media library picture and social media icons
Spectra Blocks is a fresh, standalone WordPress Gutenberg block plugin built on the V3 architecture. It is NOT a continuation of the legacy UAG plugin — it's a clean rewrite.
| Property | Value |
|---|---|
| Plugin slug | spectra-blocks |
| Text domain | spectra-blocks |
| Block prefix | spectra/ (e.g., spectra/container) |
| PHP namespace | Spectra\ |
| Option prefix | spectra_blocks_ |
| Constant prefix | SPECTRA_BLOCKS_ |
| Requires | PHP 8.1+, WordPress 6.6+ |
The admin dashboard is at Dashboard > Settings > Spectra Blocks (wp-admin/admin.php?page=spectra-blocks).
It consists of:
- Blocks — Enable/disable individual blocks
- Settings — Global configuration organized in tabs:
- Editor Options — Templates button, on-page CSS, block conditions, copy-paste, panel collapse, visibility mode, quick action sidebar
- Performance — Google Fonts loading (local/preload), asset generation, Font Awesome 5 toggle
- Block Settings — Container global padding, elements gap, button theme inheritance, editor spacing
- Extensions — Animations, Global Block Styles (GBS), responsive controls, masonry gallery
- Integrations — Social login (Facebook/Google), reCAPTCHA v2/v3 keys, analytics opt-in
- Font Management — Global FSE fonts
When editing a post/page:
- Spectra blocks appear in the block inserter under "Spectra Blocks" category
- Each block's settings panel has 3 tabs: General, Style, Advanced
- The
spectra/containerblock replacescore/group,core/columns, andcore/coverwith a flexbox/grid layout system - The
spectra/contentblock replacescore/headingandcore/paragraphusing atagNameattribute (h1-h6, p, div, span)
Spectra Blocks (Free) — 46 blocks:
| Category | Blocks |
|---|---|
| Layout | container |
| Content | content, separator, list (+ list-child-icon, list-child-item), icon (+ icons) |
| Interactive | accordion (+ 5 child blocks), tabs (+ 4 child blocks), modal (+ 7 child blocks), slider (+ slider-child) |
| Data | counter (+ 3 child blocks), countdown (+ 7 child blocks), google-map |
| Navigation | button, buttons |
| Popup | popup-builder |
Spectra Blocks Pro — 35 blocks:
| Category | Blocks |
|---|---|
| Loop Builder | loop-builder (+ 12 child blocks: template, filter, filter-button, filter-checkbox, filter-select, pagination + 3 children, search, sort, no-results, reset-all-button) |
| Forms | form-wrapper (+ 10 child blocks: input-field, input-label, input-wrapper, field-wrapper, button, checkbox, icon, link, message, recaptcha) |
| User Auth | login, register (+ 7 child blocks: username, email, password, confirm-password, first-name, last-name, terms-and-conditions) |
| Countdown | countdown-child-expiry-wrapper (extends free countdown) |
Free Extensions (in src/extensions/):
animations— AOS-based scroll animationsimage-mask— SVG mask shapes for imagesresponsive-conditions— Show/hide blocks per deviceresponsive-controls— Per-device padding/margin/typographysticky-container— Sticky positioning for containersvideo-popup-nudge— Video popup promotionz-index— Z-index control per block
Pro Extensions (in spectra-blocks-pro src/extensions/):
animations— Extended animation optionscountdown— Countdown expiry actionsdynamic-content— Dynamic field bindingsglobal-styles— Global Block Styles systemmodal— Extended modal functionalitypopup-builder— Extended popup triggers/conditionsresponsive-controls— Extended responsive optionsslider— Extended slider settings
spectra-blocks/
├── spectra-blocks.php # Main entry point — constants, version checks
├── spectra-blocks-init.php # V3 bootstrap — loads Spectra\ classes
├── classes/ # Infrastructure PHP (Spectra_Blocks_* prefix)
│ ├── class-spectra-blocks-loader.php # Plugin loader, hooks, autoloader
│ ├── class-spectra-blocks-admin-helper.php # Admin settings get/update, localization
│ ├── class-spectra-blocks-helper.php # General utilities
│ ├── class-spectra-blocks-rest-api.php # REST API field registrations
│ ├── class-spectra-blocks-settings.php # Settings wrapper (spectra_blocks_ prefix)
│ ├── class-spectra-blocks-filesystem.php # WP_Filesystem wrapper
│ └── class-spectra-blocks-security-helper.php # Security utilities
├── includes/ # V3 PHP (Spectra\ namespace, PSR-4)
│ ├── autoload.php # Composer classmap autoloader
│ ├── class-block-manager.php # Block registration from build/blocks/**/block.json
│ ├── class-extension-manager.php # Extension initialization
│ ├── class-asset-loader.php # CSS/JS enqueuing, inline styles
│ ├── class-font-manager.php # Google Fonts, local fonts, FSE fonts
│ ├── class-analytics-manager.php # Block/extension usage tracking
│ ├── class-pattern-css-refactored.php # Pattern CSS generation
│ ├── utils.php # Utility functions
│ ├── Blocks/ # Block-specific PHP
│ │ ├── class-popup-builder.php # Popup post type, AJAX, scripts
│ │ ├── class-modal.php # Modal block coordination
│ │ └── class-countdown.php # Countdown REST endpoint
│ ├── Extensions/ # Extension PHP
│ │ ├── ResponsiveControls/ # Responsive CSS attribute handling
│ │ └── Animations/ # Animation asset loading
│ ├── Helpers/ # Utility classes
│ │ ├── class-core.php # Core helpers (CSS generation, escaping)
│ │ ├── class-html-sanitizer.php # SVG/HTML sanitization (enshrined/svg-sanitize)
│ │ ├── class-renderer.php # Block render helpers
│ │ └── class-svg-sprite.php # SVG sprite management
│ ├── Analytics/ # BSF Analytics integration
│ └── Traits/
│ └── Singleton.php # Singleton trait used across all managers
├── src/ # JS/SCSS source
│ ├── blocks/ # 46 block implementations
│ │ └── {block-name}/ # See "Block Anatomy" section
│ ├── extensions/ # 7 editor extensions
│ ├── helpers/ # JS helpers
│ │ ├── plugin-config.js # Plugin URL, RTL detection
│ │ ├── block-icons.js # Block SVG icons
│ │ └── ...
│ └── components/ # Shared editor components
├── admin/ # Admin dashboard (separate build)
│ ├── class-admin-loader.php # PHP: enqueue, localize, autoload
│ ├── inc/class-admin-helper.php # Admin settings localization
│ ├── ajax/ # AJAX handlers
│ │ ├── class-ajax-init.php # AJAX event registration
│ │ ├── class-ajax-base.php # Base class (nonce verification)
│ │ └── class-common-settings.php # Settings save handlers
│ ├── api/ # REST API endpoints
│ │ ├── class-api-init.php # Route registration
│ │ └── class-common-settings.php # REST settings controllers
│ ├── src/ # React SPA source
│ │ ├── dashboard-app/ # Dashboard pages
│ │ ├── store/ # React Redux store
│ │ └── utils/ # Utilities
│ ├── views/ # PHP template wrappers
│ ├── webpack.config.js # Admin webpack config
│ ├── tailwind.config.js # Tailwind for admin UI
│ └── package.json # Admin dependencies
├── assets/ # Static assets
│ ├── fonts/ # Font Awesome, icon fonts
│ ├── images/ # Block images
│ ├── icons/ # SVG icon sprites
│ └── masks/ # Image mask SVGs
├── lib/ # Third-party libraries (via Composer)
│ ├── bsf-analytics/ # Analytics opt-in UI
│ ├── zip-ai/ # AI assistant integration
│ ├── gutenberg-templates/ # Template library
│ ├── astra-notices/ # Admin notices
│ ├── nps-survey/ # NPS survey
│ ├── utm-analytics/ # UTM tracking
│ └── zipwp-images/ # Image library
├── build/ # Compiled output (git-ignored)
├── vendor/ # Composer autoload (git-ignored)
├── languages/ # Translation .pot files
├── composer.json # PHP dependencies
├── package.json # JS dependencies + build scripts
├── webpack.config.js # Main webpack config
├── phpcs.xml.dist # PHPCS ruleset
├── phpunit.xml.dist # PHPUnit config
└── Gruntfile.js # Release, i18n, version bump tasks
spectra-blocks-pro/
├── spectra-blocks-pro.php # Main entry — constants, dependency checks
├── includes/ # PHP (SpectraBlocksPro\ namespace)
│ ├── autoload.php # PSR-4 autoloader
│ ├── BlockManager.php # Pro block registration
│ ├── ExtensionManager.php # Pro extension initialization
│ ├── AssetLoader.php # Pro CSS/JS enqueuing
│ ├── AnalyticsManager.php # Pro analytics tracking
│ ├── Helpers/
│ │ ├── register.php # User registration handler
│ │ ├── login.php # Login handler
│ │ ├── LoopBuilder.php # Loop/query builder logic
│ │ ├── BlockStyleManager.php # Block style management
│ │ └── ColorConverter.php # Color format conversion
│ ├── RestApi/
│ │ ├── RestApi.php # REST route registration
│ │ └── Controllers/ # REST controllers
│ ├── Extensions/ # Pro extension PHP
│ ├── Analytics/ # Pro analytics
│ ├── Queries/ # WP_Query builders
│ └── Utils/ # Utility classes
├── src/ # JS/SCSS source
│ ├── blocks/ # 35 pro block implementations
│ ├── extensions/ # 8 pro extensions
│ ├── helpers/ # Pro JS helpers
│ └── components/ # Pro editor components
├── build/ # Compiled output (git-ignored)
├── composer.json # PHP dependencies
├── package.json # JS dependencies
├── Gruntfile.js # Release tasks
└── phpcs.xml.dist # PHPCS ruleset
Spectra Blocks Pro is not standalone — it requires Spectra Blocks (free) to be active.
Initialization flow:
- Free loads at default priority via
spectra-blocks.php→class-spectra-blocks-loader.php - Pro loads at
plugins_loadedpriority 20 viaspectra_blocks_pro_init() - Pro checks
SPECTRA_BLOCKS_VERconstant exists and meets minimum version - Pro uses the
Spectra\Traits\Singletontrait from free'sincludes/Traits/ - Pro registers its own blocks under
spectra-pro/prefix andspectra-blocks-procategory
Shared resources:
- Pro uses free's Singleton trait:
use Spectra\Traits\Singleton; - Pro extends free's block categories
- Pro hooks into free's asset loading pipeline
- Admin settings for pro features use free's admin infrastructure
Both free and pro use a manager pattern with the Singleton trait:
namespace Spectra;
use Spectra\Traits\Singleton;
class BlockManager {
use Singleton;
public function init() {
add_action( 'init', array( $this, 'register_blocks' ) );
add_filter( 'block_categories_all', array( $this, 'add_block_category' ) );
}
}
// Usage:
( BlockManager::instance() )->init();Key managers:
BlockManager— Registers blocks frombuild/blocks/**/block.jsonExtensionManager— Initializes editor extensionsAssetLoader— Enqueues block CSS/JS, generates inline stylesFontManager— Handles Google Fonts, local font hosting, FSE global fontsAnalyticsManager— Tracks block/extension usage (BSF Analytics)
These use a static ::init() pattern (no Singleton):
class Spectra_Blocks_Loader {
public static function init() {
// register hooks, load dependencies
}
}All blocks are registered via register_block_type_from_metadata() from compiled block.json files:
$block_files = glob( SPECTRA_BLOCKS_DIR . 'build/blocks/**/block.json' );
foreach ( $block_files as $block_file ) {
register_block_type_from_metadata( $block_file );
}This means each block's block.json is the single source of truth for:
- Block name, title, description, keywords, category
- Attributes with types and defaults
- Supports (border, color, spacing, typography, etc.)
- Script/style handles
viewScriptModulefor Interactivity API frontend scriptsrenderfor server-side PHP rendering (controller.php)
Settings use a wrapper class with spectra_blocks_ prefix:
// Get: returns option or default
Spectra_Blocks_Settings::get( 'file_generation' );
// Internally: get_option( 'spectra_blocks_file_generation' )
// Update
Spectra_Blocks_Settings::update( 'file_generation', 'enabled' );
// Delete
Spectra_Blocks_Settings::delete( 'file_generation' );| Option | Default | Purpose |
|---|---|---|
spectra_blocks_enable_templates_button |
yes |
Show templates in editor |
spectra_blocks_enable_on_page_css_button |
yes |
On-page CSS generation |
spectra_blocks_enable_block_condition |
disabled |
Block visibility conditions |
spectra_blocks_enable_masonry_gallery |
enabled |
Masonry gallery feature |
spectra_blocks_enable_animations_extension |
enabled |
AOS animations |
spectra_blocks_enable_gbs_extension |
enabled |
Global Block Styles |
spectra_blocks_enable_block_responsive |
enabled |
Responsive controls |
spectra_blocks_load_gfonts_locally |
disabled |
Host Google Fonts locally |
spectra_blocks_container_global_padding |
default |
Container default padding |
spectra_blocks_container_global_elements_gap |
20 |
Container elements gap |
spectra_blocks_analytics_optin |
no |
Analytics opt-in |
spectra_blocks_select_font_globally |
[] |
Global font selections |
spectra_blocks_visibility_mode |
disabled |
Visibility mode |
window.spectra_blocks_info— Plugin config (url, ajax_url, rtl, version, settings)window.spectraBlocksSvgIcons— Full SVG icon librarywindow.spectraBlocksIconCategoryList— Icon category mappings
In block JS, use import { pluginUrl, isRTL } from '@spectra-config' for typed access.
Each block lives in src/blocks/{block-name}/ and contains:
src/blocks/container/
├── block.json # Block metadata (API v3) — name, attributes, supports
├── index.js # Registration — registerBlockType(metadata.name, { icon, edit, save })
├── edit.js # Editor component — <Settings> + <Render>
├── save.js # Save function — static HTML output or null for dynamic
├── render.js # Editor render component — block markup
├── settings.js # InspectorControls — General/Style/Advanced tabs
├── controller.php # Server-side render callback (dynamic blocks)
├── view.php # Frontend PHP template (Interactivity API context)
├── style.scss # Static styles (editor + frontend)
├── editor.scss # Editor-only styles (optional)
├── toolbar.js # BlockControls toolbar buttons (optional)
├── variations.js # Block variations (optional, e.g., container layouts)
├── shapes.js # JS shape definitions (optional, container-specific)
└── shapes.php # PHP shape renderer (optional)
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "spectra/container",
"version": "3.0.0",
"title": "Container",
"category": "spectra-blocks",
"textdomain": "spectra-blocks",
"supports": { ... },
"attributes": { ... },
"viewScriptModule": "file:./view.js",
"render": "file:./controller.php"
}import { registerBlockType } from '@wordpress/blocks';
import edit from './edit';
import save from './save';
import metadata from './block.json';
import './style.scss';
import blockIcons from '@spectra-helpers/block-icons';
registerBlockType( metadata.name, {
icon: blockIcons.container(),
edit,
save,
} );import Settings from './settings';
import Render from './render';
export default function Edit( props ) {
return (
<>
<Settings { ...props } />
<Render { ...props } />
</>
);
}Uses InspectorControls with tab-based layout:
import { InspectorControls } from '@wordpress/block-editor';
import { PanelBody } from '@wordpress/components';
export default function Settings( { attributes, setAttributes } ) {
return (
<InspectorControls>
{/* General Tab */}
<PanelBody title="Layout">
{/* Controls that call setAttributes() */}
</PanelBody>
</InspectorControls>
);
}import { useBlockProps, useInnerBlocksProps } from '@wordpress/block-editor';
export default function Render( { attributes } ) {
const blockProps = useBlockProps();
const innerBlocksProps = useInnerBlocksProps( blockProps );
return <div { ...innerBlocksProps } />;
}For static blocks, returns HTML markup. For dynamic blocks, returns null:
// Static save
export default function Save( { attributes } ) {
const blockProps = useBlockProps.save();
return <div { ...blockProps }>{ /* markup */ }</div>;
}
// Dynamic save (rendered by controller.php)
export default function Save() {
return null;
}For dynamic blocks, recreates the block markup in PHP:
<?php
$block_id = $attributes['block_id'] ?? '';
$classes = 'spectra-container spectra-block-' . esc_attr( $block_id );
?>
<div <?php echo wp_kses_data( get_block_wrapper_attributes( array( 'class' => $classes ) ) ); ?>>
<?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</div>For blocks needing frontend interactivity (accordion, counter, tabs, etc.):
<?php
wp_interactivity_state( 'spectra/accordion', array(
'isOpen' => $attributes['defaultOpen'] ?? false,
) );
?>
<div
data-wp-interactive="spectra/accordion"
data-wp-context='<?php echo wp_json_encode( $context ); ?>'
data-wp-bind--class="state.className"
data-wp-on--click="actions.toggle"
>
<?php echo $content; ?>
</div>| Aspect | V2 (Legacy UAG) | V3 (Spectra Blocks) |
|---|---|---|
| Registration | registerBlockType('uagb/...') with full config |
registerBlockType(metadata.name, { icon, edit, save }) — metadata from block.json |
| Frontend | styling.js → PHP frontend.css.php |
CSS custom properties via --spectra-{attr} |
| Interactivity | jQuery/vanilla JS in assets/js/ |
WordPress Interactivity API (data-wp-interactive) |
| Block ID | block_id attribute, .uagb-block-{id} |
block_id attribute, .spectra-block-{id} |
| PHP render | blocks-config/{name}/class-uagb-{name}.php |
src/blocks/{name}/controller.php |
| Attributes | attributes.js + attributes.php duplicated |
block.json single source of truth |
| PHP namespace | UAGB_* prefix (no namespace) |
Spectra\ namespace, PSR-4 |
Create a new folder in src/blocks/ named with your block's slug (kebab-case):
src/blocks/my-block/
Define your block metadata:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "spectra/my-block",
"version": "3.0.0",
"title": "My Block",
"category": "spectra-blocks",
"description": "Description of your block.",
"textdomain": "spectra-blocks",
"keywords": ["my", "block"],
"supports": {
"html": false,
"anchor": true
},
"attributes": {
"block_id": {
"type": "string",
"default": ""
}
}
}Create index.js, edit.js, save.js, render.js, settings.js, and style.scss following the patterns in the Block Anatomy section above.
Add your block's SVG icon to src/helpers/block-icons.js:
myBlock: () => (
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
{/* SVG path */}
</svg>
),If your block requires server-side rendering, create controller.php and reference it in block.json:
{
"render": "file:./controller.php"
}For frontend interactivity, create view.php with Interactivity API directives and reference the view script module:
{
"viewScriptModule": "file:./view.js"
}npm run start # Dev mode with hot reload
npm run build # Production buildYour block will automatically appear in the editor's block inserter under "Spectra Blocks".
Extensions add cross-cutting functionality to blocks (animations, responsive controls, etc.). They live in src/extensions/{name}/.
src/extensions/animations/
├── index.js # Extension registration
├── editor.js # Editor panel/controls
├── style.scss # Styles
└── view.js # Frontend Interactivity API (optional)
Extensions are loaded by ExtensionManager:
namespace Spectra;
class ExtensionManager {
use Singleton;
public function init() {
// Loads extension PHP from includes/Extensions/
// Registers extension scripts/styles
}
}Extensions use WordPress block filters to add attributes and controls to all compatible blocks:
- Attributes — Added via
block.jsonsupportsorblock_type_metadatafilter - Editor UI — Injected via
editor.BlockEditfilter (Advanced tab) - Frontend — Applied via
render_blockfilter or Interactivity API directives
Some extension attributes keep the UAG prefix for content compatibility with legacy saved posts:
UAGDisplayConditions,UAGUserRole,UAGBrowser,UAGSystem,UAGDayUAGHideDesktop,UAGHideMob,UAGHideTabUAGAnimationType,UAGAnimationTime,UAGAnimationDelay, etc.
Do NOT rename these — they exist in saved post content across user sites.
V3 blocks use CSS custom properties instead of generating unique CSS per block:
/* Block sets variables */
.spectra-block-abc123 {
--spectra-padding-top: 20px;
--spectra-font-size: 16px;
--spectra-color: #333;
}
/* Styles consume variables */
.spectra-container {
padding-top: var(--spectra-padding-top);
font-size: var(--spectra-font-size);
color: var(--spectra-color);
}Variable naming: --spectra-{attribute-name}
Class naming: spectra-{attribute-name}
Blocks with frontend behavior use the WordPress Interactivity API:
// view.js
import { store, getContext } from '@wordpress/interactivity';
const { state, actions } = store( 'spectra/accordion', {
state: {
get isOpen() {
return getContext().isOpen;
},
},
actions: {
toggle() {
const ctx = getContext();
ctx.isOpen = ! ctx.isOpen;
},
},
} );Blocks using Interactivity API: accordion, counter, countdown, tabs, modal, popup-builder, slider.
The admin dashboard is a React SPA in admin/:
admin/
├── src/
│ ├── dashboard-app/ # Main React app
│ │ └── pages/ # Route pages (blocks, settings, welcome)
│ ├── store/ # React Redux (globalDataStore, globalDataReducer)
│ └── utils/ # Initial state from localized PHP data
├── ajax/ # AJAX handlers for settings save
├── api/ # REST API endpoints
└── inc/ # PHP: enqueue scripts, localize data
-
PHP — Add to
get_common_settings()inadmin/inc/class-admin-helper.php:'spectra_blocks_my_option' => self::get_admin_settings_option( 'spectra_blocks_my_option', 'default' ),
-
Redux Store — Add initial state in
admin/src/store/globalDataStore.js -
Redux Reducer — Add case in
admin/src/store/globalDataReducer.js -
AJAX Handler — Add save method in
admin/ajax/class-common-settings.php -
React UI — Create component in
admin/src/dashboard-app/pages/settings/
Namespace: spectra-blocks/v1
| Endpoint | Method | Purpose |
|---|---|---|
/spectra-blocks/v1/common-settings |
GET/POST | Read/update admin settings |
Prefix: spectra_blocks_
| Action | Purpose |
|---|---|
spectra_blocks_update_popup_status |
Toggle popup active/inactive |
spectra_blocks_recaptcha_* |
reCAPTCHA key management |
spectra_blocks_social |
Social login settings |
spectra_blocks_fse_font_globally |
Global FSE font management |
All AJAX handlers:
- Verify nonce via
check_ajax_referer() - Check
current_user_can( 'manage_options' ) - Sanitize input
- Return via
wp_send_json_success()/wp_send_json_error()
Spectra Blocks Pro extends the free plugin with premium blocks and extensions. It uses the SpectraBlocksPro\ namespace and its own build/blocks/ output directory.
| Property | Value |
|---|---|
| Plugin slug | spectra-blocks-pro |
| Text domain | spectra-blocks-pro |
| Block prefix | spectra-pro/ |
| PHP namespace | SpectraBlocksPro\ |
| Constant prefix | SPECTRA_BLOCKS_PRO_ |
| Requires | PHP 7.4+, WordPress 6.6+, Spectra Blocks (free) active |
Pro checks for the free plugin at plugins_loaded priority 20:
function spectra_blocks_pro_init() {
if ( ! defined( 'SPECTRA_BLOCKS_VER' ) ) {
// Show "install/activate Spectra Blocks" notice
return;
}
if ( version_compare( SPECTRA_BLOCKS_VER, SPECTRA_BLOCKS_PRO_REQUIRED_SPECTRA_BLOCKS_VER, '<' ) ) {
// Show "update Spectra Blocks" notice
return;
}
// Initialize pro managers...
}Pro block development follows the same V3 pattern as free blocks. Key differences:
- Block directory:
spectra-blocks-pro/src/blocks/{name}/ - Block name prefix:
spectra-pro/{name}(e.g.,spectra-pro/loop-builder) - Text domain:
spectra-blocks-pro - Category:
spectra-blocks-pro - PHP namespace:
SpectraBlocksPro\
Loop Builder — WP_Query-based block for displaying post lists with filtering, pagination, and search. Uses SpectraBlocksPro\Helpers\LoopBuilder for query construction and SpectraBlocksPro\Queries\ for query builders.
User Registration — Complete registration form with customizable fields. Uses SpectraBlocksPro\Helpers\register.php with role validation and forbidden role checking.
Login — Authentication form with redirect handling. Uses SpectraBlocksPro\Helpers\login.php.
Dynamic Content — Binds block attributes to dynamic WordPress data (post fields, custom fields, etc.). Implemented as a pro extension.
Global Block Styles — Reusable style presets applied across blocks. Uses SpectraBlocksPro\Helpers\BlockStyleManager.
Namespace: spectra/pro/v2/
Registered in SpectraBlocksPro\RestApi\RestApi::init() with controllers in includes/RestApi/Controllers/.
- Branches:
feat/block-name,fix/issue-description,chore/task-name - Base branches:
devfor bug fixes,next-releasefor new features - Commits: Frequent, descriptive messages in imperative mood
- Build before PR: Always run
npm run buildand test before creating a PR
- Follow WordPress PHP Coding Standards (WPCS)
- Tabs for indentation
- Yoda conditions:
if ( 'value' === $variable ) - Spaces inside parentheses:
if ( $condition ),function_name( $param ) - Single quotes for strings (unless interpolation needed)
- Snake_case for variables and functions
- Open
<?phptag, no closing?>tag - All PHP files start with
defined( 'ABSPATH' ) || exit; @since x.x.xplaceholder for new code- PHPCS:
composer lint/composer lint:fix - PHPStan for static analysis
- ES6+ syntax, camelCase naming
- Functional components with hooks (no class components)
- Double quotes for JSX attributes, single quotes for other strings
- Trailing commas in arrays, objects, function parameters
- Import from
@wordpress/*packages (never directly from React) - All user-facing strings wrapped with
__()or_n()from@wordpress/i18n - ESLint:
npm run lint:js
- BEM naming convention:
.spectra-block__element--modifier - CSS custom properties:
--spectra-{name} - Avoid
!important— use selector specificity instead - Stylelint:
npm run lint:css - Tailwind CSS used only in admin dashboard (not block frontend)
- Block directories: kebab-case (
my-block) - PHP files:
class-{name}.phpfor classes, kebab-case for others - JS files: camelCase for React components, kebab-case for utilities
- SCSS files: kebab-case matching their JS counterpart
| Type | Free Convention | Pro Convention |
|---|---|---|
| Block name | spectra/{name} |
spectra-pro/{name} |
| Option key | spectra_blocks_{name} |
— |
| PHP namespace | Spectra\ |
SpectraBlocksPro\ |
| PHP class prefix | Spectra_Blocks_ (classes/) |
— |
| AJAX action | spectra_blocks_{name} |
— |
| REST namespace | spectra-blocks/v1 |
spectra/pro/v2/ |
| Script handle | spectra-blocks-{name} |
spectra-blocks-pro-{name} |
| Constants | SPECTRA_BLOCKS_{NAME} |
SPECTRA_BLOCKS_PRO_{NAME} |
| Text domain | spectra-blocks |
spectra-blocks-pro |
Both plugins use @wordpress/scripts (webpack) for JS/CSS builds and Grunt for release tasks.
# Spectra Blocks (free)
cd spectra-blocks/
npm install
npm run start # Dev watch mode with hot reload
# Spectra Blocks Pro
cd spectra-blocks-pro/
npm install
npm run start # Dev watch mode
# Admin Dashboard (separate build)
cd spectra-blocks/admin/
npm install
npm run startnpm run build # Build blocks to build/ directory
npm run build:fresh # Clean build/ first, then build- Entry points auto-discovered from
src/blocks/**/index.js block.jsonand PHP files copied via--webpack-copy-php- Aliases:
@spectra-helpers,@spectra-config,@spectra-components - Output:
build/blocks/{block-name}/with index.js, style-index.css, view.js, block.json, controller.php
grunt release # Clean → copy → compress → cleanup (creates .zip)
grunt release-no-clean # Copy without cleanup (for debugging)
grunt readme # Convert readme.txt → README.md
grunt i18n # Add textdomain + generate .pot file
grunt textdomain # Add textdomain to PHP files
grunt bump-version --ver=X.Y.Z # Bump version in all filesnpm run release # → grunt release
npm run bump-version # → grunt bump-version
npm run readme # → grunt readme
npm run makepot # → grunt i18n
npm run zip # → bash bin/create-zip.shcomposer install # Install PHP dependencies (requires BSF SSH access)
composer lint # Run PHPCS
composer lint:fix # Auto-fix PHPCS issuesImportant: BSF shared libraries are private repos requiring SSH access:
git@github.com:brainstormforce/bsf-analytics.gitgit@github.com:brainstormforce/zip-ai.gitgit@github.com:brainstormforce/gutenberg-templates.git- etc.
They install to lib/ (not vendor/) via Composer's installer-paths.
# JavaScript
npm run lint:js # ESLint
npm run lint:css # Stylelint
npm run format # Prettier formatting
# PHP
composer lint # PHPCS with WPCS rules
composer lint:fix # Auto-fix PHPCS issues./vendor/bin/phpunit # Full test suite
./vendor/bin/phpunit --filter TestClassName # Single test classConfig: phpunit.xml.dist
npx playwright test # Full suite
npx playwright test --ui # Interactive UI mode
npx playwright test tests/e2e/block # Specific test
npx playwright codegen http://localhost:8888 # Record new testConfig: playwright.config.js
Before creating a pull request:
npm run lint:js— fix all JS lint errorsnpm run lint:css— fix all CSS lint errorscomposer lint— fix all PHP lint errorsnpm run build— ensure clean build- Test block in editor (all settings, all devices)
- Test block on frontend (markup, styles, interactivity)
- Test with Spectra Pro active AND inactive (free blocks)
- Check browser console for JS errors
Spectra follows Scrum with 2-week sprints. Project management is done in Infinity.
| Type | Description | Branch Prefix |
|---|---|---|
| New | New block or major feature | feat/ |
| Fix | Bug fix | fix/ |
| Feat | New feature for existing block | feat/ |
| Improvement | Enhancement to existing code | chore/ or feat/ |
- To Do — Created, assigned, not started
- WIP — Active development
- In Review — PR created, code review in progress
- In QA — Quality assurance testing
- Ready to Merge — Passed review and QA
- Done — Merged to target branch
When creating a PR:
- Build your files:
npm run build - Pull latest from target branch and resolve conflicts
- Run all linters and fix errors
- Create PR with:
- Description — What changed and why
- Test cases — Link to test documentation
- Labels — bug, enhancement, needs review, etc.
- Reviewers — As assigned by your manager
- Update the Infinity task accordingly
Every 2 weeks. Prepare by:
- Building your branch (
npm run build) - Having a demo-ready local site
- Preparing a summary of completed and upcoming work
- Slack:
#spectra-discussion— All Spectra communication - Daily Scrum: Share yesterday's progress, today's goals
- Scrum goals: Send to designated team member after each scrum
What is a block's slug?
The kebab-case identifier used in the block name. For spectra/social-profile, the slug is social-profile.
How do I access admin settings in my block?
Settings are localized to window.spectra_blocks_info via class-spectra-blocks-admin-helper.php. Use import { pluginUrl } from '@spectra-config' for typed access.
When should I use a dynamic block vs static?
Use static when the frontend markup is fully determined at save time. Use dynamic (controller.php + save() => null) when the block needs server-side data (e.g., latest posts, user info) or Interactivity API behavior.
How do child blocks work?
Parent-child relationships are defined in block.json via parent attribute. For example, spectra/accordion-child-item has "parent": ["spectra/accordion"]. Child block categories use spectra-blocks-inner.
How do I add a block preview image to the admin?
Add a .webp image to admin/assets/block-previews/{block-name}.webp. It appears automatically on the Blocks admin page.
Where does SVG sanitization happen?
includes/Helpers/class-html-sanitizer.php uses the enshrined/svg-sanitize library. SVG uploads require the upload_files capability. Script tags are gated by unfiltered_html capability.
How do I test with Pro active?
Ensure both plugins are in wp-content/plugins/, both activated. Pro blocks only appear when Pro is active. Free blocks should work identically with or without Pro.
What's the difference between classes/ and includes/?
classes/ contains infrastructure code using the Spectra_Blocks_ prefix (no namespace). includes/ contains V3 code using the Spectra\ namespace with PSR-4 autoloading. New code should go in includes/.