Skip the WordPress theme system entirely. Build templates using plain HTML, PHP and CSS. Zero bloat. 100% control.
Completely disables the active theme. No fighting `style.css` or overriding hooks. You start with a blank slate.
Write plain PHP directly in the builder. Logic runs before the HTML renders. Full access to WP and WooCommerce functions.
A built-in translation system inspired by Polylang. Build language-specific templates with no extra plugins.
Build your own Product, Archive, Cart and Checkout templates. Full control over the shopping experience.
Manage global snippets (GTM, Meta Pixel, CSS resets) with precise control over location and priority.
Design your own post or product cards using HTML variables, then display them anywhere with a shortcode.
Join developers building lighter, faster WordPress websites.
The full technical reference. Open only the part you actually need — everything else stays collapsed.
PURITY replaces the WordPress theme system. Instead of fighting a
theme's style.css, you take full control of the HTML
document.
/wp-content/plugins/purity/.purity — with no
version suffix. Auto-updates identify the plugin by its folder name and
stop working if you rename it.
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
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.
Each section renders in a fixed order — this is not cosmetic, it is how the whole thing works:
<style> tag.<script> tag.function_exists().
<style> element,
and a global snippet's CSS always loses the cascade to a section's own CSS
at equal specificity.
The template type decides where it appears. When several templates match, PURITY takes the newest one whose display conditions pass.
| Type | Renders on |
|---|---|
header | The top of every PURITY-driven page |
footer | The bottom of every PURITY-driven page |
single_post | A single blog post |
archive | Post lists, archives, the blog index |
404 | The "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.
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.
PURITY creates no custom tables for content — everything lives in
standard post meta. These are the keys used by the
current version.
| Key | Holds |
|---|---|
_smb_sections | Array of {html, php, css, js} sections — live version |
_smb_sections_draft | Draft version of the same array |
_smb_template_type | Template type (header, footer, 404…) |
_smb_conditions | Display conditions |
_smb_use_builder | 1 = a normal WP page taken over by the builder |
_smb_language | Content language code |
_smb_translation_group | Links translations of the same page |
_smb_seo_description | Manual meta description (overrides the automatic one) |
_smb_html_code | Legacy format: single HTML section |
_smb_php_code | Legacy format: single PHP section |
_smb_css_code | Legacy format: single CSS section |
_smb_js_code | Legacy format: single JS section |
_draft suffix.
New work should use _smb_sections.
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.
| Location | Use for |
|---|---|
init | Server-side logic, registering post types |
wp_head | Global styles, verification tags, analytics |
wp_body_open | Code right after <body> opens |
wp_footer | Scripts that must not block rendering |
admin_head | Admin 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.
Design the look of a single post or product card, then output the list anywhere with a shortcode:
[smb_loop] // query-driven repeated contentA 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.hreflang tags, so search engines understand the pages are
language variants rather than duplicates.
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.
robots directive./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.
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' );
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.
| Endpoint | Does |
|---|---|
GET /list | All pages, templates and snippets |
GET /element/{id} | Read an element's code |
POST /element/{id} | Write code (supports drafts) |
POST /create | Create a new template or page |
GET|POST /media | Media library access |
These bugs recurred across build after build, and none of them could be diagnosed from the CSS alone. Worth checking before something breaks.
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.
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.
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.
position: sticky fails silentlySymptom 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.
align-items: center does not guarantee alignmentSymptom 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.
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.