Blueprints
Blueprints is the "full site in one click" feature. A user browses a gallery of pre-built site layouts served from a remote API, selects one, steps through a configuration wizard, and ends up with a fully functional site — header, footer, layout templates, pages, categories, sidebars, and theme options all applied in sequence.
Preset PHP files (header, footer, single post, archive) are bundled inside the plugin. The Blueprint JSON only references preset slugs and data — no PHP files are downloaded from the remote server.
Screen Flow
The React app controls which screen is visible via a mode value in the Zustand store. Screens layer on top of the gallery — the gallery stays mounted at all times.
| Mode | Screen | What it does |
|---|---|---|
gallery |
Gallery | Grid of blueprint cards; user picks a blueprint to apply |
preflight |
Pre-flight Modal | Runs compatibility checks before the wizard opens |
wizard |
Wizard | Multi-step configuration — user makes choices for each layer |
progress |
Progress Screen | Applies each layer in sequence, shows real-time status |
success |
Success Screen | Install complete summary with quick-action links |
Blueprint JSON Structure
The remote API returns this shape for each blueprint. The plugin never modifies it — it is stored as-is in a transient for the duration of the install session.
{
"name": "The Daily",
"slug": "the-daily",
"version": "1.0",
"requires_plugin_version": "x.x",
"requires_theme_version": "x.x",
"category": "news",
"header_preset": "modern-news",
"header_settings": {},
"footer_preset": "news-footer",
"footer_settings": {},
"theme_options": {},
"templates": {
"single_post": {},
"category": {},
"archive": {}
},
"pages": [
{ "title": "Home", "slug": "home", "set_as_front": true, "builder_data": [] },
{ "title": "Contact", "slug": "contact", "set_as_front": false, "builder_data": [] }
],
"categories": [
{ "name": "Politics", "slug": "politics" }
],
"sidebars": {}
}
Remote API and Caching
Class: includes/class-sanilwb-blueprints-api.php
Two endpoints on the Sanil server:
GET /blueprints— list of blueprints (name, slug, thumbnail URL, category, version requirements)GET /blueprints/{slug}— full blueprint JSON for one blueprint
The list is cached locally as a WordPress transient so the gallery loads even without a live internet connection. The full blueprint JSON is only fetched when the user clicks Apply on a card, and again at the start of the install session.
| Method | Description |
|---|---|
get_list() |
Returns the cached list, or fetches and caches it if stale |
get_blueprint( $slug ) |
Fetches and returns one full blueprint array, or null on failure |
bust_cache() |
Deletes the cached list so the next get_list() call re-fetches |
Pre-flight Checks
Class: includes/class-sanilwb-blueprints-preflight.php
SANILWB_Blueprints_Preflight::run( $blueprint ) runs all checks against a full blueprint array and returns an array of result objects, each with label, passed, and message fields.
Checks run:
| Check | What it verifies |
|---|---|
| Plugin version | Installed plugin version ≥ requires_plugin_version |
| Theme version | Installed theme version ≥ requires_theme_version |
| Header preset | The header_preset slug folder exists on disk |
| Footer preset | The footer_preset slug folder exists on disk |
| Content presets | Each preset slug referenced in templates exists on disk |
| Theme options | The theme_options key is present (optional data check) |
Every check must pass before the wizard opens. The Pre-flight Modal disables its "Proceed to Install" button until all_passed is true.
Snapshot and Rollback
Class: includes/class-sanilwb-blueprints-snapshot.php
A snapshot of all affected data is captured before any layer runs, stored as the sanilwb_blueprint_snapshot WordPress option. If any layer fails, the snapshot is restored immediately and the install stops.
| Method | Description |
|---|---|
capture( $overwrite_page_ids ) |
Reads and stores current values for all layer targets |
restore() |
Writes all captured values back to the DB; returns true on success |
exists() |
Returns true if a snapshot is stored |
clear() |
Deletes the snapshot option |
What the snapshot captures per layer:
| Layer | What is captured |
|---|---|
header |
sanilwb_header_preset + sanilwb_header_preset_settings |
footer |
sanilwb_footer_preset + sanilwb_footer_preset_settings |
theme_options |
sanilwb_theme_options |
content_presets |
sanilwb_{type}_preset + sanilwb_{type}_preset_settings for each type |
db_templates |
Nothing — orphan template rows are acceptable on failure |
pages (action=new) |
Nothing — orphan pages are acceptable on failure |
pages (action=map) |
sanilwb_data + _wp_page_template for each mapped page ID |
categories |
Nothing — orphan categories are acceptable on failure |
sidebars |
sidebars_widgets + all widget instance options touched |
One snapshot at a time — applying a new blueprint overwrites the previous snapshot. A "Restore Previous Blueprint" button is visible in the gallery whenever a snapshot exists.
Install Status Tracking
The sanilwb_blueprint_install_status WordPress option tracks whether the last install completed cleanly:
| Value | Meaning |
|---|---|
in_progress |
Set when blueprint_start is called |
completed |
Set when finishInstall succeeds, or when a failed install is rolled back |
If install_status is in_progress when the Pre-flight screen opens, a warning section appears at the bottom of the modal explaining that the previous install was incomplete, with a "Restore Previous State" button and an "I understand, continue anyway" checkbox.
The "Proceed to Install" button is disabled until all checks pass and (when the warning is shown) the checkbox is ticked.
Installation Layers
Class: includes/class-sanilwb-blueprints-applier.php
Each layer is applied by a static method. The Progress Screen calls them one at a time via the sanilwb_blueprint_apply_layer AJAX action, passing the layer name.
| Layer name | Applier method | What it does |
|---|---|---|
header |
apply_header() |
Writes sanilwb_header_preset and sanilwb_header_preset_settings; syncs fonts |
footer |
apply_footer() |
Writes sanilwb_footer_preset and sanilwb_footer_preset_settings; syncs fonts |
theme_options |
apply_theme_options() |
Merges blueprint colors and typography into sanilwb_theme_options; syncs Google Fonts |
content_presets |
apply_content_presets() |
Sets the preset slug + settings for single, category, archive, and any other content types in the blueprint |
db_templates |
apply_db_templates() |
Inserts layout templates into wp_sanilwb_templates; compiles them; builds a ref map for page data |
pages |
apply_pages() |
Creates new pages or overwrites existing mapped pages with the blueprint's page builder data |
categories |
apply_categories() |
Creates any categories that do not already exist |
sidebars |
apply_sidebars() |
Replaces widget content in each sidebar named in the blueprint |
Rules:
- Never delete existing data — only overwrite or add.
- Pages are additive — new pages are created; existing pages are only overwritten when the user explicitly mapped them in the wizard and confirmed the overwrite.
- Stop on error — if any layer throws, the Progress Screen restores the snapshot and halts.
Idempotency Behavior
What happens when the same blueprint is installed more than once, or when data from a previous install already exists.
Per-layer behavior on re-install
| Layer | Re-install behavior |
|---|---|
header / footer / content_presets |
update_option() overwrites the saved preset slug and settings. Fully idempotent. |
theme_options (color preset) |
The blueprint's color preset is matched against existing presets by id. If a preset with the same id exists it is replaced in-place; otherwise it is appended. The blueprint preset is always made the active preset. No duplicates accumulate. |
db_templates |
Always calls SANILWB_DB::insert(). Every re-install creates new rows. Running the same blueprint twice produces duplicate templates in wp_sanilwb_templates. |
pages |
Depends on the wizard choice. Choosing "Create new page" again calls wp_insert_post() and produces a new page. Choosing "Map to existing" overwrites the existing page's meta — idempotent. |
categories |
wp_insert_term() silently discards the error if the slug already exists. Idempotent. |
sidebars |
Replaces the sidebar's widget list, but always creates new widget instances in widget_block / widget_text options first. Old instances are not cleaned up — they become orphans in the options table after repeated installs. |
Color preset name vs. id
The deduplication check compares preset id values, not name values. Two presets that share a display name but have different ids will both appear in the color presets list. To avoid duplicate entries in the UI, blueprint color presets must use a stable, unique id (e.g. the-daily-colors) rather than a human-readable name.
Known accumulation issues
- Duplicate DB templates — re-running a blueprint is the only way to produce them. They are harmless but invisible; the only cleanup path is a manual database delete.
- Orphaned widget instances —
widget_blockandwidget_textoptions grow by the number of widgets in the blueprint'ssidebarsblock on each re-install. They do not affect the live site but increase option table size over time.
Installation Wizard
The wizard is a single-screen modal (mode === 'wizard') with a step indicator. The user works through configuration choices for each layer before applying. All choices are stored in wizardChoices in the Zustand store and sent to the server as a single JSON object when the install begins.
File: admin/assets/js/src/blueprints/screens/Wizard.jsx
The wizard currently has one configurable step: Pages. For each page in the blueprint, the user chooses one of:
- Create new page — a fresh page will be created.
- Map to existing page — pick from a dropdown of current published pages; the existing page's builder data will be overwritten (an inline confirmation message is shown before the user can proceed).
The wizard validates that every page has a choice set before enabling "Proceed to Apply".
AJAX Actions
All blueprint server calls go through SANILWB_Ajax. Each action verifies the sanilwb_templates nonce and requires edit_pages capability.
| Action | Handler method | Description |
|---|---|---|
sanilwb_blueprints_list |
get_blueprints_list() |
Returns the cached blueprint list |
sanilwb_blueprint_preflight |
blueprint_preflight() |
Runs pre-flight checks; returns results + full blueprint data |
sanilwb_blueprint_start |
blueprint_start() |
Fetches the full blueprint JSON, captures the snapshot, sets status to in_progress, stores blueprint and wizard choices in transients |
sanilwb_blueprint_apply_layer |
blueprint_apply_layer() |
Applies one named layer using the stored blueprint and choices |
sanilwb_blueprint_finish |
blueprint_finish() |
Sets status to completed, deletes transients, updates lastBlueprintName |
sanilwb_blueprint_restore |
blueprint_restore() |
Calls SANILWB_Blueprints_Snapshot::restore() |
sanilwb_blueprint_snapshot_exists |
blueprint_snapshot_exists() |
Returns whether a snapshot is stored |
Edge cases handled in blueprint_start:
- If the JSON fetch fails before the snapshot is captured,
install_statusis NOT set toin_progress— nothing has changed yet. - The "Apply Blueprint" button is disabled on first click and stays disabled for the duration so a double-click cannot start two concurrent installs.
PHP Infrastructure
| File | Class | Purpose |
|---|---|---|
includes/class-sanilwb-blueprints-api.php |
SANILWB_Blueprints_API |
Remote API client with local list caching |
includes/class-sanilwb-blueprints-preflight.php |
SANILWB_Blueprints_Preflight |
Compatibility checks before install |
includes/class-sanilwb-blueprints-snapshot.php |
SANILWB_Blueprints_Snapshot |
Capture and restore pre-install site state |
includes/class-sanilwb-blueprints-applier.php |
SANILWB_Blueprints_Applier |
One static method per layer; called by the AJAX handler |
admin/class-sanilwb-admin-blueprints.php |
SANILWB_Admin_Blueprints |
Admin page registration, asset enqueue, window.SanilWbBlueprints injection |
React App Architecture
Entry point: admin/assets/js/src/blueprints/index.jsx
BlueprintsApp ← root: fetches blueprint list on mount, renders active screen
├── Gallery ← blueprint card grid, category filter, "Restore" button
├── PreflightModal ← runs pre-flight checks, broken-install warning
├── Wizard ← step-by-step page mapping choices
├── ProgressScreen ← applies layers in sequence, handles failure + rollback
└── SuccessScreen ← install complete summary + quick links
State is managed by a single Zustand store (store.js). All API calls go through the thin api.js wrapper which reads ajaxUrl and nonce from window.SanilWbBlueprints.
Gallery is always mounted. Other screens are conditionally rendered on top of it based on mode.
Window Data Object
window.SanilWbBlueprints is injected by SANILWB_Admin_Blueprints::enqueue_blueprints_assets() before the React bundle loads.
| Key | Type | Description |
|---|---|---|
nonce |
string | sanilwb_templates nonce — used for all AJAX calls |
ajaxUrl |
string | WordPress admin-ajax.php URL |
adminUrl |
string | WordPress admin root URL |
pluginVersion |
string | Installed plugin version string |
snapshotExists |
bool | Whether a previous blueprint snapshot is stored |
installStatus |
string | 'completed' or 'in_progress' — last known install status |
lastBlueprintName |
string | Name of the last successfully applied blueprint |
existingPages |
array | [{id, title}] — all published pages, used by the wizard page-mapping step |
Key Files
| File | Purpose |
|---|---|
admin/class-sanilwb-admin-blueprints.php |
Admin page, asset enqueue, data injection |
admin/assets/js/src/blueprints/BlueprintsApp.jsx |
React root; screen router |
admin/assets/js/src/blueprints/store.js |
Zustand store; all UI state |
admin/assets/js/src/blueprints/api.js |
AJAX wrapper functions |
admin/assets/js/src/blueprints/screens/Gallery.jsx |
Blueprint card grid |
admin/assets/js/src/blueprints/screens/PreflightModal.jsx |
Pre-flight check modal |
admin/assets/js/src/blueprints/screens/Wizard.jsx |
Page mapping wizard |
admin/assets/js/src/blueprints/screens/ProgressScreen.jsx |
Layer-by-layer install progress |
admin/assets/js/src/blueprints/screens/SuccessScreen.jsx |
Install complete screen |
admin/assets/css/blueprints.scss |
Blueprints admin styles |
admin/templates/blueprints/page.php |
PHP mount point for the React app |
includes/class-sanilwb-blueprints-api.php |
Remote API client |
includes/class-sanilwb-blueprints-preflight.php |
Pre-flight checker |
includes/class-sanilwb-blueprints-snapshot.php |
Snapshot capture and restore |
includes/class-sanilwb-blueprints-applier.php |
Layer applier methods |