A look at what v1.6.0 will bring: a lightweight block editor inspired by Gutenberg but without the bloat, drag-and-drop content blocks, AI-powered title and meta suggestions, and integrated image generation. Here is the technical architecture.
Why a Block Editor
For the past year, JekCMS has used a standard TinyMCE rich text editor. It works, but it forces content into a single HTML blob with no structural awareness. You can't reorder sections without cut-and-paste. You can't save a product comparison table as a reusable component. You can't drag a gallery above a text section without manually editing HTML.
WordPress solved this with Gutenberg, but at enormous cost — 400KB of JavaScript, React dependency, a REST API surface area that triples the codebase complexity, and an editing experience that confuses non-technical users with too many options. We wanted the structural benefits of blocks without that overhead.
Design Constraints
We set three hard limits before writing any code:
- Under 60KB JavaScript (minified + gzipped). Gutenberg ships 400KB+. Our target is 85% smaller.
- No framework dependency. Vanilla JS with a thin reactive layer. No React, Vue, or Svelte.
- Backward compatible. Existing TinyMCE content must render correctly. Blocks are an option, not a requirement.
Block Architecture
Every block is a JSON object with a type, attributes, and inner content. The editor stores an array of these objects. On the frontend, a renderer converts each block to HTML.
// Block data structure
{
"blocks": [
{
"type": "heading",
"attrs": { "level": 2 },
"content": "Getting Started with JekCMS"
},
{
"type": "paragraph",
"attrs": {},
"content": "JekCMS is a lightweight content management system..."
},
{
"type": "image",
"attrs": {
"src": "images/2026/04/setup-guide.avif",
"alt": "JekCMS setup screen",
"width": 800,
"height": 500,
"caption": "The installation wizard"
}
},
{
"type": "code",
"attrs": { "language": "php" },
"content": "<?php
echo 'Hello World';
?>"
}
]
}
Storage is simple: the blocks JSON goes into a content_blocks column alongside the existing content column (which keeps the rendered HTML for backward compatibility and fast frontend serving). When a post is saved, the renderer converts blocks to HTML and writes both columns.
Block Types (Launch Set)
Version 1.6.0 will ship with ten block types:
- Paragraph — Standard text with inline formatting (bold, italic, link, code)
- Heading — H2 through H4 with automatic anchor ID generation for table of contents
- Image — Single image with caption, alt text, and alignment options
- Gallery — Grid of images with lightbox, configurable columns (2-4)
- Code — Syntax-highlighted code block with language selector
- Quote — Blockquote with optional citation
- Table — Editable rows and columns with header row toggle
- Columns — 2 or 3 column layout, each column accepts nested blocks
- List — Ordered and unordered lists with nesting
- Separator — Horizontal rule with style variants
Drag-and-Drop Reordering
Each block renders as a DOM element with a drag handle on the left edge. We're using the native HTML5 Drag and Drop API — no library. The implementation is 180 lines of JavaScript.
// block-editor.js - Drag handler (simplified)
class BlockEditor {
constructor(container) {
this.container = container;
this.blocks = [];
this.dragIndex = null;
}
initDrag(blockEl, index) {
blockEl.setAttribute('draggable', 'true');
blockEl.addEventListener('dragstart', (e) => {
this.dragIndex = index;
blockEl.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
});
blockEl.addEventListener('dragover', (e) => {
e.preventDefault();
const target = this.getBlockFromPoint(e.clientY);
if (target !== null && target !== this.dragIndex) {
this.moveBlock(this.dragIndex, target);
this.dragIndex = target;
}
});
blockEl.addEventListener('dragend', () => {
blockEl.classList.remove('dragging');
this.save();
});
}
}
The key decision was using dragover with vertical position calculation instead of drop zones between blocks. This gives real-time visual feedback as you drag — the blocks physically shift out of the way, exactly like reordering items in a mobile app.
AI Content Suggestions
This is where 1.6.0 gets interesting. We're integrating three AI features directly into the editor, all powered by the Gemini API (with a planned Groq fallback for speed-sensitive operations).
Feature 1: Title Generation
After writing content, click "Suggest Titles" in the toolbar. The system sends the first 500 words of your content to Gemini and requests five title variations optimized for CTR and SEO. Each suggestion shows an estimated character count (Google truncates at ~60 characters) and highlights the target keyword if one is set.
// AI title suggestion prompt (internal)
$prompt = "You are an SEO title writer. Given this article content, suggest 5 titles.
Rules:
- Under 60 characters each
- Include the keyword: {$keyword}
- Use numbers or power words when natural
- No clickbait, no questions unless genuinely useful
- Vary the structures (how-to, listicle, statement, comparison)
Content (first 500 words):
{$excerpt}";
Feature 2: Meta Description Generation
Same concept, but for the meta description field. The AI reads the full post content and generates three meta description options, each under 155 characters. It highlights the keyword and shows the character count in real time.
Feature 3: Alt Text Generation
When you upload an image to a block, the system can send the image to Gemini's vision model for automatic alt text generation. This is optional — triggered by clicking an "Auto Alt" button on the image block. The generated alt text is always editable.
We deliberately did not make this automatic on upload. Developers and content creators should review alt text, not blindly trust AI output. The button makes it a conscious choice.
AI Image Generation
The most requested feature from our beta testers: generate featured images and inline illustrations directly from the editor.
How It Works
A new "Generate Image" block type opens a modal with a text prompt field. The system sends the prompt to Gemini's image generation model and returns a 1200x630 image (optimized for Open Graph sharing). The generated image is automatically converted to AVIF, thumbnails are created, and the image is inserted into the media library.
// Image generation flow
1. User types prompt: "Professional photograph of a laptop showing PHP code editor"
2. System adds style constraints: "editorial photography, no text overlays, 1200x630"
3. Gemini generates image → returns base64 PNG
4. PHP processes:
a. Decode base64 → save temp PNG
b. Convert to AVIF (quality 80)
c. Generate WebP fallback
d. Create thumbnails (400x400, 800x500, 1600x1000)
e. Insert into media table with auto-generated alt text
5. Insert image block with all metadata
Cost Management
Image generation isn't free. We're implementing a token bucket system: each site gets a configurable monthly quota (default 50 generations/month for Pro license, 200 for Agency). The admin settings page shows current usage, remaining quota, and estimated cost.
Template Blocks
A template block is a saved combination of blocks that can be inserted as a group. For example, a "Product Review" template might include:
- H2 heading block (product name)
- Image block (product photo)
- Columns block with two columns: Pros list + Cons list
- Table block (specifications)
- Paragraph block (verdict)
Templates are stored in a block_templates table and appear in a dropdown when adding new blocks. They're per-site, so each installation can have its own templates.
Export/Import
Templates can be exported as JSON files and imported into other JekCMS installations. This lets agencies create a library of content templates and distribute them across client sites.
// Template export format
{
"name": "Product Review",
"description": "Standard product review layout with pros/cons",
"blocks": [
{ "type": "heading", "attrs": { "level": 2 }, "content": "{{product_name}}" },
{ "type": "image", "attrs": { "placeholder": true, "alt": "{{product_name}} photo" } },
{ "type": "columns", "attrs": { "count": 2 }, "children": [
{ "type": "list", "attrs": { "style": "ul", "title": "Pros" }, "content": "" },
{ "type": "list", "attrs": { "style": "ul", "title": "Cons" }, "content": "" }
]},
{ "type": "table", "attrs": { "header": true, "cols": 2 }, "content": [["Spec", "Value"]] },
{ "type": "paragraph", "content": "" }
],
"variables": ["product_name"]
}
The {{variable}} syntax in templates gets replaced with actual values when the template is inserted. A small modal prompts for each variable.
Technical Architecture
Database Changes
ALTER TABLE posts ADD COLUMN content_blocks JSON DEFAULT NULL AFTER content;
ALTER TABLE posts ADD COLUMN editor_type ENUM('classic','blocks') DEFAULT 'classic';
CREATE TABLE block_templates (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
description TEXT,
blocks JSON NOT NULL,
variables JSON DEFAULT NULL,
author_id INT UNSIGNED,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);
Editor Loading
The editor JavaScript file loads only on the post editor page — not on every admin page. It's a single file, no chunks or lazy loading complexity. On page load, it reads the content_blocks JSON from a hidden textarea and renders each block into an editable DOM structure. On save, it serializes the DOM back to JSON and simultaneously generates the HTML preview.
Frontend Rendering
The frontend never touches the blocks JSON. It reads the pre-rendered HTML from the content column, same as today. This means:
- Zero JavaScript required on the frontend for block content
- Existing themes work without modification
- RSS feeds, API responses, and search indexing all work unchanged
- Page load performance is identical to classic editor posts
Timeline
Version 1.6.0 is currently in internal testing. The block editor core and all ten block types are functional. AI features are in alpha — title and meta description generation work, alt text and image generation are still being tuned.
We're targeting a release in Q2 2026. The update will be available through the standard JekCMS update system. Existing content will not be affected — the classic editor remains the default until you explicitly switch a post to block mode.
If you want early access to test the block editor, reach out through the admin panel's support channel. We're accepting ten beta testers from active Pro and Agency license holders.