
Building nollejCraft: A Maintainable CMS Architecture
WordPress powers 40% of the web, but ask developers what it's like to maintain a WordPress site five years into production, and you'll hear stories about plugin conflicts, database bloat, and technical debt that accumulates quickly and becomes increasingly more difficult to maintain.
What if you could build a content management system (CMS) that actually stays maintainable? One that doesn't fight you when you need to extend it, doesn't hide complexity behind "magic," and doesn't require a PhD in WordPress internals to debug?
That's the engineering challenge behind nollejCraft: I had a specific need and wanted to build a content management system that I could continue maintaining years from now.
The Core Architecture
nollejCraft is radically simple:
- one SQL table
- three PHP scripts
- a consistent extension pattern
The _sitePages Table
All content lives in a single table. Pages, blog posts, dashboards, landing pages, everything uses the same schema:
CREATE TABLE _sitePages (
id INT PRIMARY KEY AUTO_INCREMENT,
doc_type VARCHAR(50), -- blog, page, dashboard
category VARCHAR(50), -- For navigation grouping
title VARCHAR(255),
slug VARCHAR(255), -- Auto-generated from doc_type/category/title
content TEXT, -- Markdown/HTML
status VARCHAR(20), -- draft, published, archived
access_level VARCHAR(20), -- public, registered, paid
created_at TIMESTAMP,
updated_at TIMESTAMP
);
That's it. No wp_posts, wp_postmeta, wp_terms, wp_term_relationships, and the other eleven tables WordPress uses for similar functionality.
Why single table?
- Direct SQL queries without joins:
SELECT * FROM _sitePages WHERE content LIKE '%shortcode%' - Transparent data model—you understand the structure in 30 seconds
- Trivial to backup, migrate, or inspect
- No hidden relationships to debug at 2am
The Three Scripts
1. index.php - Public Entry Point
Renders published content, parses Markdown via Parsedown, processes shortcodes, generates navigation links from doc_type, category, and title fields.
2. siteManager.php - CRUD Interface
Filter, draft, publish, archive pages. All content types managed in one interface.
3. pageEditForm.php - Content Editor
CodeMirror-powered editor for Markdown/HTML. Handles metadata, content lifecycle, and preview.
Three files. About 800 lines total. That's the entire CMS core.
The Extension Pattern: Shortcode Handlers
The real architectural insight is how nollejCraft extends without bloating: shortcode handlers with consistent signatures.
How It Works
Content can contain shortcodes:
## Member Directory
[[table dataset="members" columns="name,email,company" filter="status='paid'"]]
When index.php renders the page, it:
- Finds shortcodes via regex
- Extracts tag name (
table) and parameters - Calls
handle_table($params, $inner) - Replaces shortcode with returned HTML
The Handler Pattern
Every shortcode handler follows the same signature:
function handle_table($params, $inner) {
// $params = ['dataset'=>'members', 'columns'=>'name,email,company', ...]
// $inner = content between opening/closing tags (if any)
// Do whatever you need:
// - Query database
// - Call APIs
// - Process data
// - Generate HTML
return $html; // String of HTML to inject
}
That's the entire extension API. No hooks. No filters. No action priorities. No namespacing headaches.
Example: Building a Custom Handler
Want a shortcode that displays upcoming events? Write one function:
function handle_events($params, $inner) {
$limit = $params['limit'] ?? 5;
$category = $params['category'] ?? 'all';
$sql = "SELECT * FROM events
WHERE date >= CURDATE()
AND (category = ? OR ? = 'all')
ORDER BY date LIMIT ?";
$events = db_query($sql, [$category, $category, $limit]);
$html = '<div class="events-list">';
foreach ($events as $event) { // generate a card for each event
$html .= "<div class='event'>";
$html .= "<h3>{$event['title']}</h3>";
$html .= "<p>{$event['date']}</p>";
$html .= "</div>";
}
$html .= '</div>';
return $html;
}
Drop that function in your handlers file. Now this works:
[[events category="workshop" limit="3"]]
Time to implement: 15 minutes.
Compare to WordPress: Register shortcode, learn WordPress API conventions, handle attribute sanitization via WordPress methods, ensure compatibility with page builders, test against common plugins, debug Gutenberg interactions. Time: 2-4 hours if you know what you're doing.
My First Handlers
As I started creating my website with nollejCraft, I realized there are certain patterns that keep coming up, types of data things I need to include on web pages. So my first shortcode handlers were these four:
handle_form($params, $inner) - Generate HTML forms from simple definitions
handle_table($params, $inner) - Display data tables with filtering/sorting
handle_cards($params, $inner) - Card layouts for events, members, content
handle_dazl($params, $inner) - Execute data analytics workflows (integrated with DAZL)
Each handler is 50-150 lines of focused PHP. There's no framework overhead, no crazy abstraction layers, just functions that take parameters, do something, and return HTML.
Why This Matters for Maintenance
Debuggable
Something not rendering?
SELECT * FROM _sitePages WHERE id = 123;
See the exact content stored. You can get right to the page source without worrying about things like post meta to check, or revision history cluttering things. You just go straight to the data.
Shortcode not working? Open the projectLib.php file and go straight to handle_whatever() directly. No jumping through hooks to figure out execution order.
Testable
Want to test a handler? Call it:
$html = handle_table(['dataset'=>'test', 'columns'=>'a,b,c'], '');
assert(strpos($html, '<table>') !== false);
You don't need to boot WordPress, mock global state, or fight the testing infrastructure.
Extensible Without Complexity
Client needs custom functionality? Write a handler function. 30-60 minutes for most features.
No plugin development. No marketplace submission. No compatibility testing across WordPress versions.
Your business logic, your code, your timeline.
Navigation and URL Structure
Each row in the SQL table (page on the site) has a unique slug.
Site navigation is automatically generated from content structure:
- Top-level menu from
doc_typevalues - Dropdowns from
categorygroupings - Slugs from
doc_type/category/title
Add a page with doc_type="resources" and category="guides", get a menu item automatically. No manual menu management.
URLs follow the pattern: /resources/guides/getting-started
Clean, predictable, SEO-friendly.
Access Control
Three visibility levels built into the core:
public - Anyone can view
registered - Requires user account
paid - Requires paid subscription
Set access_level on any page. Middleware checks authentication before rendering.
For more complex permissions, extend the middleware. No plugin ecosystem to navigate.
Integration Points
nollejCraft doesn't try to be a complete business platform. It integrates with systems that manage business data.
The optional nollejVault integration demonstrates the pattern: handlers can query any database table or API endpoint. Return data in a standard format, and existing handlers (table, cards, charts) render it automatically.
This separation means nollejCraft stays focused on content presentation while business logic lives where it belongs—in your business systems.
Performance Characteristics
Single table queries are fast. Markdown parsing via Parsedown is efficient. Handler functions execute directly—no framework overhead.
For a typical site (hundreds of pages, moderate traffic), nollejCraft runs comfortably on shared hosting. No caching plugins needed for reasonable performance.
For higher traffic, add standard PHP optimization (opcache, edge caching). The simple architecture doesn't fight you.
When to Use nollejCraft
This architecture makes sense when:
You need custom functionality - Writing handlers is faster than configuring plugins
You value transparency - Direct SQL access and simple code beats "magic"
You're comfortable with PHP - Extending requires basic PHP skills
You want long-term maintainability - Simpler systems age better
Your content connects to business data - Handler pattern handles this naturally
It's not for everyone. If you need a massive plugin ecosystem or a drag-and-drop page builder, stick with established platforms.
But if you've spent years maintaining WordPress sites and wondered if there's a better way, there absolutely is.
The Design Philosophy
nollejCraft prioritizes:
Simplicity over features - Solve 80% of use cases exceptionally well
Transparency over abstraction - Understand what's happening by reading code
Extensibility over completeness - Make adding features straightforward
Maintainability over cleverness - Future you will thank present you
These guiding principles are actually architectural constraints on purpose. They prevent the system from becoming what it set out to replace.
Looking Forward
The core architecture is stable.
Extensions happen through handlers, not core modifications. Adding a new shortcode handler does not break anything that already works. Each handler only executes when a shortcode is placed in a document and the html is rendered. If the new shortcode you're testing is on a page flagged as DRAFT, you're the only one that can see the page. And therefore, the only person that will know if the shortcode does what it's supposed to do.
Future additions might include:
- Additional built-in handlers (charts, calendars)
- Template system improvements
- Enhanced developer tooling
- API for headless CMS usage
But the foundation is here now. A single table, three scripts, handler pattern.
Final Thoughts
Building yet another CMS wasn't the goal. Maintaining my website and articles in the most straight-forward way possible, that was the goal.
By rejecting the "everything for everyone" approach and focusing on a clean architecture with consistent extension patterns, nollejCraft demonstrates that simpler systems can be more capable where it counts: solving real problems without accumulating technical debt.
The test isn't whether it does everything WordPress does. Can I maintain my website without spending hours coding? That's the question. And I know the database structure in thorough, and the 3 core programs that manage the data and serve up the site are solid.
Insight: The real test is whether a website can be maintained confidently five years from now without touching much code.
For developers tired of fighting their tools, that makes all the difference.
nollejCraft is open to implementation partners and custom deployments. The architecture supports rapid customization for client-specific needs while maintaining the core simplicity that makes long-term maintenance feasible.