Description
Normally, WordPress theme templates are created by adding PHP files to the active theme. Developersd Custom Theme Templates lets administrators build custom templates directly from wp-admin, with a visual drag-and-drop builder, and have them appear in the native Template dropdown when editing Pages, Posts, or supported Custom Post Types.
The plugin never creates or modifies theme files. Templates are stored as structured JSON and rendered dynamically, so they survive theme switches and updates.
Key Features
- Visual drag-and-drop builder — every row is one HTML element
- Safe, whitelisted structural tags only (div, section, header, footer, article, aside, main, nav, headings, p, span, strong)
- Unlimited nesting with drag-and-drop re-parenting
- Content types: Static Text, Dynamic Title, Dynamic Content, Dynamic Featured Image (choose Background — for hero/banner sections — or a Normal inline image), Shortcode, and Button (text + URL + optional new-tab)
- Hero/banner sections: use a Featured Image background with a “center content” option to vertically/horizontally position a title, text, and button stacked on top of it
- Per-element spacing (margin/padding), alignment, colors, width/max-width/min-height, and container controls
- Independent Desktop / Tablet / Mobile responsive overrides, with the breakpoints themselves configurable site-wide from Settings
- Assign each template to Pages, Posts, or specific Custom Post Types
- Optional Sidebar — its own drag-and-drop element tree, positioned left or right of the main content, with an adjustable width percentage (main content automatically fills the rest) and its own configurable responsive stacking breakpoint
- Optional “global default” per post type — e.g. every blog post automatically uses the same template without picking it individually, while any single post can still override it explicitly
- Templates take priority over other plugins’ template logic — enforced as early as possible in the request so nothing else can override an assigned template
- Enable/disable any template with a toggle switch, from the list table or the edit screen, without losing its configuration
- Group templates into Categories (with WordPress’s native, clickable Categories column)
- Templates always render fully closed, valid markup — never broken HTML
- Live preview while building
- Duplicate templates with one click
- Clean uninstall — removes all plugin data when you choose to delete it
Security
- All output is escaped; all input is sanitized before storage
- Every admin action is nonce-verified and capability-checked (
manage_options) - No inline
<script>,<style>,<iframe>, or PHP is ever permitted inside a template - Custom attributes go through a strict whitelist — no
on*event handlers, nostyle/src/hrefoverrides
Developers
Every function, class, hook, option, database key, and AJAX action is prefixed with developersd_ to avoid naming collisions. The codebase follows WordPress Coding Standards and an OOP, single-responsibility architecture:
Developersd_Post_Types— CPT + taxonomy registration, meta boxes, savingDevelopersd_Template_Manager— data access, recursive sanitizationDevelopersd_Renderer— JSON HTML rendering, template_include hookDevelopersd_Admin— settings screen, list table, plugin linksDevelopersd_Assets— scoped script/style enqueueingDevelopersd_Ajax— preview + duplicate endpointsDevelopersd_Database— prepared-query helpers, cache management
Extend the builder via filters:
developersd_allowed_tags— add/remove permitted HTML tagsdevelopersd_content_types— add new content type handlersdevelopersd_rendered_template— filter final template HTML
Installation
- Upload the
developersd-custom-theme-templatesfolder to/wp-content/plugins/, or install the zip via Plugins Add New Upload Plugin. - Activate the plugin through the Plugins screen.
- Go to Custom Theme Templates Add New (its own top-level menu item in the admin sidebar) to build your first template.
- Under Template Assignment, choose which post types the template should be available for.
- Edit a Page, Post, or supported CPT, and choose your new template from the Template dropdown in the Page Attributes / Summary panel.
FAQ
-
Does this plugin modify my theme files?
-
No. Templates are stored as JSON in the database and rendered at request time through a
template_includehook. Nothing is ever written to your theme’s directory. -
What happens if I switch themes?
-
Templates keep working, since your theme’s
get_header()andget_footer()are still used — only the main content area is generated by the plugin. -
div, section, header, footer, article, aside, main, nav, h1–h6, p, span, and strong. Script tags, iframes, inline styles, and PHP are never allowed.
-
What happens to my data if I delete the plugin?
-
All templates, categories, and settings are permanently removed when the plugin is deleted from the Plugins screen (not on simple deactivation).
-
Will another plugin (like a page builder) override my assigned template?
-
No. Once a template is assigned to a page/post (either explicitly, or as a post type’s global default), the plugin takes over rendering as early as possible in the request — before other plugins’ own template logic typically runs — and stops the request from continuing to any other template resolution. This is intentionally the highest-priority mechanism available to a normal WordPress plugin.
-
Yes. On a template’s edit screen, under Template Assignment, check “Use as global default” next to a post type. Every post of that type will use it automatically unless that specific post explicitly picks a different template. Only one template can be the global default per post type at a time.
-
How does the Dynamic Featured Image content type work?
-
Set an element’s Content Type to “Dynamic Featured Image”, then choose Image Display: “Background Image” applies the current post’s featured image as that element’s CSS background (with Background Size/Position/Repeat, and a Min Height so it’s actually visible — 150px by default if left blank) — check “Center content over this image” to vertically/horizontally position child elements (a title, text, a button) on top of it for a hero/banner section. “Normal Image” instead renders it as a plain, ordinary
<img>, with an optional Image Fit control. -
Yes. On a template’s edit screen, the Sidebar metabox lets you enable a sidebar with its own drag-and-drop element tree (built exactly like the main content), choose which side it sits on, set its width as a percentage (main content automatically fills the rest), and set the screen width at and below which it stacks under the content as full width instead of sitting beside it.
Reviews
There are no reviews for this plugin.
Contributors & Developers
“Developersd Custom Theme Templates” is open source software. The following people have contributed to this plugin.
ContributorsTranslate “Developersd Custom Theme Templates” into your language.
Interested in development?
Browse the code, check out the SVN repository, or subscribe to the development log by RSS.
Changelog
1.5.0
- Added: an optional “Element Label” field for every element, so you can name what something actually is (e.g. “Hero Section”, “Welcome Section”) instead of only seeing its HTML tag in the tree. The tag always shows first as a fixed, colored prefix (e.g. “DIV:”), followed by your label if you’ve set one — elements without a label display exactly as before.
1.4.3
- Fixed: a template’s dynamic CSS (responsive rules, sidebar layout) was being output as an inline
<style>tag embedded directly in the page body, instead of through WordPress’s proper style-enqueuing system. It’s now attached viawp_add_inline_style()onwp_enqueue_scripts, so it’s correctly present in<head>like any other stylesheet. (The admin builder’s live preview, which renders inside a standalone iframe with no real page orwp_headto hook into, still uses an inline<style>tag — that’s the correct approach for that isolated context specifically.)
1.4.2
- Removed the discouraged
load_plugin_textdomain()call — translations are now auto-loaded by WordPress based on the plugin’s headers. - Updated “Tested up to” for the current WordPress release.
- Fixed several WordPress Coding Standards naming-convention warnings: a handful of variables in included view/template files are now properly prefixed, and the deliberate reuse of WordPress core’s own
the_contentfilter (to apply standard content processing to dynamic content) is now documented in place rather than flagged as a new hook.
1.4.1
- Fixed: several WordPress Coding Standards sanitization warnings in the AJAX preview handler and the template save handler (nonce values now explicitly sanitized; sidebar setting fields now properly unslashed and sanitized; the deliberate raw-JSON handling — which is fully sanitized recursively deeper in the pipeline — is now documented in place rather than flagged).
- Added: a floating tooltip that follows the cursor while dragging an element, showing exactly what will happen before you let go — e.g. “Element 4 (div) moving above Element 5 (h2)” or “…moving inside Element 6 (section)”.
1.4.0
- Added: an optional Sidebar for any template. It has its own independent element tree (add, nest, and style elements exactly like the main content builder), a Left/Right position choice, an adjustable width percentage (main content automatically fills the remaining space), and its own configurable stacking breakpoint — below that width, both the sidebar and main content become full width and stack instead of sitting side by side.
- Changed: the Preview modal now shows the sidebar too (laid out exactly like the front-end) whenever it’s enabled, not just the main content.
- Fixed: a latent cache-invalidation bug (present since the “global template” feature was added) where, with “Cache rendered HTML” turned on in Settings, saving a template could leave stale rendered output cached. Cache invalidation now correctly clears everything on save regardless of how many different posts a global template has been rendered for.
1.3.3
- Fixed: the hover background on each element’s action icons (collapse, duplicate, delete) and the drag handle looked clipped/uneven instead of a clean, evenly-centered highlight.
- Added: a clear, plain-language explanation directly in the builder — shown when an element’s Content Type is Dynamic Featured Image in Background mode — describing that nested children automatically appear over the image, and how “Center content over this image” positions them as a group.
1.3.2
- Fixed: toggle switches on the edit screen (Enabled, Available, Global) still didn’t match the list table’s Enabled toggle. There were two separate CSS implementations that had quietly drifted apart — consolidated into one single shared stylesheet used identically by both screens, so there is now exactly one toggle switch design, everywhere, permanently in sync.
- Changed: elements now start collapsed by default when opening an existing template, instead of every element being expanded at once. Elements added during the current editing session (via Add Element / Add Child) still start expanded, since you just asked to create and configure one.
1.3.1
- Fixed: toggle switches (Enabled, Available, Global) could render as a bare, unstyled circle instead of a proper pill switch. WordPress admin’s own default checkbox styling has higher CSS specificity than a plain class selector and was partially overriding ours — the toggle styles are now protected against that.
- Fixed: dragging and dropping an element always expanded its new parent, even if you had deliberately left it collapsed. Collapse/expand state is now tracked independently of the tree’s DOM (which is fully rebuilt on every change) and persists correctly across drag-and-drop, add, delete, and duplicate — collapsed stays collapsed, expanded stays expanded.
- Fixed: the Template Assignment table could display “Global” on with “Available” off for templates saved before the 1.2.1 checkbox fix. Available now always displays as on whenever Global is on, regardless of when the data was originally saved.
- Added: a brief highlight flash confirms where a dragged element landed, without ever changing collapse state.
1.3.0
- Improved: drag-and-drop has been rebuilt with precise drop zones. Dragging is now started only from the dedicated handle (so clicking or selecting text in a field never accidentally starts a drag), and hovering over the top, middle, or bottom of another element shows a live indicator for “drop before”, “nest inside”, or “drop after” before you let go.
- Added: every element now shows a numbered badge reflecting its position (e.g. 1, 2, 2.1, 2.2) that updates instantly whenever elements are added, reordered, or nested, so it’s always clear which element is which.
- Redesigned: the Template Assignment metabox is now a clean table with toggle switches for “Available” and “Global” per post type, instead of plain checkboxes — the row highlights when a post type is set as that template’s global default.
- Redesigned: the element list is now card-based with clearer spacing, hover states, and visual grouping throughout the builder for a cleaner, more modern editing experience.
1.2.2
- Fixed: the Preview modal appeared blank for any element using Dynamic Title, Dynamic Content, or Dynamic Featured Image, since the preview has no real post to pull data from. These now show placeholder content in the preview only — “Dynamic Title”, sample Lorem ipsum text, and a neutral gray placeholder box for a Featured Image (Background mode gets a solid placeholder color; Normal Image mode gets a labeled placeholder box) — so the actual layout and sizing can be judged before publishing. None of this affects real front-end rendering, which always uses the real post’s data.
- Changed: renamed the “Dynamic Featured Image (Background)” content type to simply “Dynamic Featured Image”, since Background vs Normal Image is now its own separate Image Display choice.
1.2.1
- Changed: Dynamic Featured Image is no longer forced to render as a background. A new “Image Display” choice lets the admin pick Background Image (for hero/banner sections) or Normal Image (a plain, ordinary
<img>, with its own optional Image Fit control). - Fixed: a background image had no default height, so it was invisible unless the admin happened to set Min Height manually. Background mode now defaults to a 150px Min Height (still fully adjustable).
- Added: “Center content over this image” plus Vertical/Horizontal Position controls for a Featured Image (Background mode) element, to cleanly position a title/text/button stack on top of a hero image.
- Fixed: the “Use as global default” checkbox appeared to revert after saving. It was being silently dropped whenever the separate “Available for” checkbox for that post type wasn’t also checked. Checking “Use as global default” now automatically implies availability for that post type, and the two checkboxes stay visually in sync in the builder.
- Fixed: the Preview button could fail silently with no visible feedback (a failed security check returned a raw, non-JSON response the browser couldn’t use). Preview now always returns a proper response and shows a clear error message if something goes wrong.
- Changed: Preview now opens as a full-screen modal (closable via its Close button, clicking the backdrop, or Escape) instead of a small inline pane.
1.2.0
- Added: templates now take priority over other plugins’ (e.g. page builders like Divi) template-rendering logic — enforced via the earliest reliable hook available, with an
exit()guard so nothing registered later in the request can override an assigned template. - Fixed: the All Templates list table showed two overlapping category columns (“Category” and “Categories”). Removed the redundant plain-text one; the native, clickable “Categories” column remains.
- Added: an Enabled/Disabled toggle switch for every template, available both in the All Templates list (inline, no page reload) and on the template’s own edit screen. Disabled templates disappear from the Template dropdown and any post using one falls back to the theme’s normal template.
- Added: “global default” template assignment per post type — e.g. every blog post can automatically use the same template without picking it individually — while any single post can still explicitly choose a different template to override it. Only one template may be the global default for a given post type at a time.
- Added: a “Dynamic Featured Image” content type, which applies the current post’s featured image as a CSS background (with Background Size/Position/Repeat and Min Height controls) — for building hero/banner sections.
- Added: a “Button” content type (button text, URL, and optional open-in-new-tab), nestable anywhere in the tree, including inside a Dynamic Featured Image hero section.
1.1.2
- Fixed: Tablet and Mobile style overrides had no visible effect — only Desktop styles ever showed, at any screen width. Desktop values were being applied as an inline
styleattribute, which always wins the CSS cascade over stylesheet rules regardless of matching media queries. Desktop, Tablet, and Mobile are now all emitted as equal-specificity class rules in the same stylesheet, so each breakpoint correctly overrides the wider one as the viewport narrows.
1.1.1
- Fixed: an element whose saved data was missing or had a malformed
stylesobject (possible on templates created in earlier 1.0.x/1.1.0 testing) would throw a JavaScript error while rendering the builder, silently preventing that element’s margin/padding/color/alignment fields — and in some cases all of its fields — from having their changes captured for saving. The builder now normalizes any loaded template data on open, and isolates rendering errors per-element so one bad node can never block the rest of the tree from working.
1.1.0
- Fixed: per-element spacing/color values without an explicit unit (e.g. typing “10” instead of “10px”, or “ffffff” instead of “#ffffff”) were being silently discarded instead of saved.
- Added: site-wide, configurable Tablet and Mobile breakpoints (Settings screen), used consistently by every template’s responsive controls.
- Simplified capability handling to a plain
manage_optionscheck throughout, and moved the plugin to its own top-level admin menu.
1.0.0
- Initial release.