Webs Butler
Order a Website

The Anti-Theme Builder
for developers who know better.

Skip the WordPress theme system entirely. Build templates using plain HTML, PHP and CSS. Zero bloat. 100% control.

header.php
<header class="site-header"> <?php wp_nav_menu(); ?> </header> // No theme. No limits. Clean code.
Core Features

Built for purists

Theme-Agnostic

Completely disables the active theme. No fighting `style.css` or overriding hooks. You start with a blank slate.

🐘

Native PHP

Write plain PHP directly in the builder. Logic runs before the HTML renders. Full access to WP and WooCommerce functions.

🌍

Multilingual System

A built-in translation system inspired by Polylang. Build language-specific templates with no extra plugins.

🛍️

WooCommerce Ready

Build your own Product, Archive, Cart and Checkout templates. Full control over the shopping experience.

💉

Code Injection

Manage global snippets (GTM, Meta Pixel, CSS resets) with precise control over location and priority.

🔄

Loop Builder

Design your own post or product cards using HTML variables, then display them anywhere with a shortcode.

Ready to tidy up your workflow?

Join developers building lighter, faster WordPress websites.


Download PURITY for free
Documentation

Everything you need to get started

The full technical reference. Open only the part you actually need — everything else stays collapsed.

Version 3.90 WordPress 6.0+ PHP 7.4+ Licence Private
01 Quick start and installation

PURITY replaces the WordPress theme system. Instead of fighting a theme's style.css, you take full control of the HTML document.

  1. Upload the folder to /wp-content/plugins/purity/.
  2. Activate the plugin in the WordPress admin.
  3. Create your first template under PURITY → Templates.
  4. Set the Template Type (Header, Footer, Single Post…).
  5. Add display conditions and publish.
The folder must be named exactly purity — with no version suffix. Auto-updates identify the plugin by its folder name and stop working if you rename it.

File structure

purity/ ├── purity.php // entry point, loads the modules ├── includes/ │ ├── post-types.php // smb_template, smb_snippet post types │ ├── meta-boxes.php // editor: HTML/PHP/CSS/JS tabs │ ├── template-loader.php // template routing │ ├── conditions.php // display conditions │ ├── code-snippets.php // global snippets │ ├── loop-builder.php // [smb_loop] shortcode │ ├── multilingual.php // multilingual system │ ├── seo-head.php // SEO meta, hreflang, llms.txt │ ├── api-bridge.php // REST API │ └── toolkit.php // SMTP, WebP, logging, cookies ├── templates/ // canvas.php, custom-page.php └── plugin-update-checker/ // GitHub auto-updates
02 How rendering works

PURITY intercepts every request through the template_include filter (priority 99), detects the page type and looks for a matching template. Once a template takes over, the theme is switched off entirely.

Order within a single section

Each section renders in a fixed order — this is not cosmetic, it is how the whole thing works:

  1. PHP — runs first and prepares your variables.
  2. CSS — written into the document in a <style> tag.
  3. HTML — can use the variables from the PHP field.
  4. JS — last, in a <script> tag.
Every section has its own variable scope. A variable set in section 1 does not exist in section 2. Functions are global, variables are not — if you need shared data, wrap it in a function guarded by function_exists().
A section's CSS lands in the document before its HTML, inside the page body. Two consequences: an adjacent-sibling selector aimed at "the first block on the page" will hit a <style> element, and a global snippet's CSS always loses the cascade to a section's own CSS at equal specificity.
03 Template types and display conditions

The template type decides where it appears. When several templates match, PURITY takes the newest one whose display conditions pass.

TypeRenders on
headerThe top of every PURITY-driven page
footerThe bottom of every PURITY-driven page
single_postA single blog post
archivePost lists, archives, the blog index
404The "not found" page
single_{type}A single entry of a custom post type

The single_{type} pattern is dynamic — any public custom post type registered on the site shows up in the dropdown automatically.

Display conditions

The same template type can have several variants separated by conditions: language, specific page IDs, or page type. That is how one installation serves a different header for the English and Polish versions of a site.

04 Post meta keys — reference

PURITY creates no custom tables for content — everything lives in standard post meta. These are the keys used by the current version.

KeyHolds
_smb_sectionsArray of {html, php, css, js} sections — live version
_smb_sections_draftDraft version of the same array
_smb_template_typeTemplate type (header, footer, 404…)
_smb_conditionsDisplay conditions
_smb_use_builder1 = a normal WP page taken over by the builder
_smb_languageContent language code
_smb_translation_groupLinks translations of the same page
_smb_seo_descriptionManual meta description (overrides the automatic one)
_smb_html_codeLegacy format: single HTML section
_smb_php_codeLegacy format: single PHP section
_smb_css_codeLegacy format: single CSS section
_smb_js_codeLegacy format: single JS section
Legacy keys have draft counterparts with a _draft suffix. New work should use _smb_sections.
05 Code snippets and loops

Snippets are global pieces of code that run at a chosen point in the page lifecycle — ideal for Google Tag Manager, the Meta Pixel, or a global CSS reset.

LocationUse for
initServer-side logic, registering post types
wp_headGlobal styles, verification tags, analytics
wp_body_openCode right after <body> opens
wp_footerScripts that must not block rendering
admin_headAdmin panel tweaks

Snippets have a priority and an on/off switch. Each one runs inside a try/catch, so a broken snippet cannot take the site down.

Loop Builder

Design the look of a single post or product card, then output the list anywhere with a shortcode:

[smb_loop] // query-driven repeated content
06 Multilingual system

A built-in, Polylang-style translation system covering 12 languages — no extra plugins.

  • _smb_language marks a page's language.
  • _smb_translation_group ties the language versions of one page together.
  • Display conditions let you bind a header and footer to a language.
Since 3.90 those same two keys also drive automatic hreflang tags, so search engines understand the pages are language variants rather than duplicates.
07 SEO — new in 3.90

Because PURITY disables the theme, it also strips every tag WordPress would normally put in <head>. The SEO module puts them back and adds more.

  • Meta description — manual, from the excerpt, or generated from the section content.
  • Canonical URL and the robots directive.
  • Open Graph and X cards — proper link previews when shared.
  • hreflang — built from translation groups.
  • /llms.txt — a content index for AI search engines.

Set a custom description with the _smb_seo_description key. Without one, the module falls back to the excerpt, then to the opening sentences of the page content.

Turning it off

On sites running Yoast or Rank Math the module stands aside on non-PURITY pages by itself. You can also disable it completely:

add_filter( 'smb_seo_enabled', '__return_false' );
08 REST API

PURITY exposes its own API under the purity/v1 namespace. Every request needs an X-Purity-Token header carrying the key generated for that site.

EndpointDoes
GET /listAll pages, templates and snippets
GET /element/{id}Read an element's code
POST /element/{id}Write code (supports drafts)
POST /createCreate a new template or page
GET|POST /mediaMedia library access
The API key grants full access to the site's code. Treat it like a password: never commit it to a repository or expose it in the browser.
09 Traps from real builds

These bugs recurred across build after build, and none of them could be diagnosed from the CSS alone. Worth checking before something breaks.

1. Negative-margin "theme breakout" hacks

Symptom A hero section renders far too tall — you see only a cropped top slice — followed by a large unexplained blank gap.

Cause The code tries to cancel a theme wrapper's padding with a matched negative-margin / positive-padding pair. PURITY renders as a direct child of <body>, so there is nothing to cancel and the height simply grows by the padding you added.

Fix Delete those pairs entirely. Plain min-height: 100vh with zero margin is enough. Full-bleed horizontal breakout is a different, valid technique — do not confuse it with vertical compensation.

2. No global background = white flashes

Symptom A bright band appears between two dark sections, even though each looks correct on its own.

Cause Backgrounds do not cascade sideways between sibling sections. Any pixel not covered by a section's own background shows the browser's default white.

Fix Set a solid background on html, body as your first global rule. Any section using background-attachment: fixed also needs its own background-color fallback.

3. Two rounded boxes that should be one

Symptom A floating pill header shows a seam, a mismatched corner radius, or a coloured sliver when the mobile menu opens.

Cause The closed and open states were built as two separate elements, each with its own radius and background. Any tiny mismatch becomes visible.

Fix One container for both states, overflow: hidden on the outer element, and expand the inner content with max-height. When hiding a panel, pair max-height: 0 with opacity: 0 — zero height alone can leave rounded edges faintly visible.

4. position: sticky fails silently

Symptom A sticky header works on some pages and scrolls away on others, with identical CSS.

Cause sticky is broken by any ancestor with overflow other than visible, or one that creates a stacking context. The ancestor structure differs between page types.

Fix For headers, prefer position: fixed — it is relative to the viewport and sidesteps the entire problem.

5. align-items: center does not guarantee alignment

Symptom A logo and a menu button in the same row look vertically offset from each other.

Cause Each item's own box is centred. An image inside a link inherits line-height and gains invisible extra height that the button does not have.

Fix Give both an identical explicit height and set line-height: 0 on the image's wrapper.

General rule: when a layout does not match the CSS as written, stop guessing new rules. Check the computed values in your browser's developer tools. A screenshot cannot tell wrong CSS apart from overridden CSS or CSS held back by a cache — and each needs a different fix.
10 Migration and emergency rollback

Moving from Elementor or Breakdance

  1. Copy the rendered HTML from your browser's inspector.
  2. Paste it into the section's HTML field.
  3. Move styles into the CSS field, scripts into the JS field.
  4. Delete the old builder's shortcodes.
  5. Enable the builder on that page and compare both versions.
Migrate one page at a time. The builder is enabled per page, so the rest of the site keeps running on the old setup while you work.

When something goes wrong

Section PHP runs server-side, so a syntax error can stop a page from rendering. That is what the draft layer is for: test in the draft, publish once it works.

If a site stops loading, disable the plugin over FTP — rename the purity folder to anything else. WordPress deactivates it automatically and falls back to the theme. Your content stays untouched in the database and returns when you restore the name.

Never delete the post meta rows by hand. They are the only place PURITY-built content is stored — removing them cannot be undone.