Content Types
Wunderframe Applications use a flexible content type system that allows you to define different page types and their associated templates. Content types determine how different kinds of content are rendered and what fields are available for editing.
What are Content Types?
Content types are Lua modules that define:
- Template rendering logic - How the content appears on the page
- Field definitions - What data can be edited
- Validation rules - How to ensure content is valid
- Default values - Starting content for new pages
Built-in Content Types
Wunderframe comes with several pre-built content types:
page
- Basic Page
The default content type for simple pages with rich text content.
-- lib/content_types/page.lua
local luat = require("luat")
local function render(node, runtime)
return luat.compile("lib/pages/page.luat", {
title = node.properties.title or "Untitled Page",
content = node.properties.content or "",
node = node
}, runtime)
end
return {
render = render,
fields = {
{
name = "title",
type = "text",
label = "Page Title",
required = true
},
{
name = "content",
type = "richtext",
label = "Page Content"
}
}
}
homepage
- Landing Page
Specialized content type for site homepages with hero sections and feature areas.
article
- Blog Post
Content type for blog posts with metadata, tags, and publishing features.
gallery
- Image Gallery
Content type for showcasing collections of images with captions.
Creating Custom Content Types
You can create custom content types by adding modules to the lib/content_types/
directory:
-- lib/content_types/product.lua
local luat = require("luat")
local function render(node, runtime)
local props = node.properties
return luat.compile("lib/pages/product.luat", {
name = props.name,
price = props.price,
description = props.description,
images = props.images or {},
node = node
}, runtime)
end
return {
render = render,
fields = {
{
name = "name",
type = "text",
label = "Product Name",
required = true
},
{
name = "price",
type = "number",
label = "Price ($)",
required = true
},
{
name = "description",
type = "richtext",
label = "Product Description"
},
{
name = "images",
type = "media",
label = "Product Images",
multiple = true
}
}
}
Content Type Registration
Content types are automatically discovered and registered based on the file structure in lib/content_types/
. The filename becomes the content type identifier.
File Structure
lib/content_types/
├── page.lua # content_type: "page"
├── homepage.lua # content_type: "homepage"
├── article.lua # content_type: "article"
└── product.lua # content_type: "product"
Field Types
Wunderframe supports various field types for content editing:
Text Fields
{
name = "title",
type = "text",
label = "Title",
placeholder = "Enter title...",
required = true,
maxLength = 100
}
Rich Text
{
name = "content",
type = "richtext",
label = "Content",
toolbar = {"bold", "italic", "link", "heading"}
}
Media Upload
{
name = "image",
type = "media",
label = "Featured Image",
accept = "image/*",
multiple = false
}
Number Input
{
name = "price",
type = "number",
label = "Price",
min = 0,
step = 0.01
}
Select Dropdown
{
name = "category",
type = "select",
label = "Category",
options = {
{value = "tech", label = "Technology"},
{value = "design", label = "Design"},
{value = "business", label = "Business"}
}
}
Boolean Toggle
{
name = "featured",
type = "boolean",
label = "Featured Item",
default = false
}
Template Integration
Content types work seamlessly with LUAT templates. The render function passes data to templates which can access it using familiar syntax:
<!-- lib/pages/product.luat -->
<div class="product">
<h1>{name}</h1>
<p class="price">${price}</p>
<div class="description">
{content}
</div>
{#if images && #images > 0}
<div class="gallery">
{#each images as image}
<img src="{image.url}" alt="{image.alt}" />
{/each}
</div>
{/if}
</div>
Validation
Content types can include validation logic to ensure data integrity:
local function validate(properties)
local errors = {}
if not properties.name or properties.name == "" then
table.insert(errors, "Product name is required")
end
if properties.price and properties.price < 0 then
table.insert(errors, "Price must be positive")
end
return errors
end
return {
render = render,
validate = validate,
fields = {
-- field definitions
}
}
Advanced Features
Dynamic Fields
Fields can be conditionally shown based on other field values:
{
name = "sale_price",
type = "number",
label = "Sale Price",
showIf = function(props)
return props.on_sale == true
end
}
Field Groups
Organize related fields into collapsible groups:
fields = {
{
type = "group",
label = "SEO Settings",
fields = {
{name = "meta_title", type = "text", label = "Meta Title"},
{name = "meta_description", type = "text", label = "Meta Description"}
}
}
}
What's Next?
- Project Structure - Learn about file organization
- Development Workflow - Building and testing your app
- Built-in Functions - Available Lua functions