Post Types Module ​
The Post Types module (CPT) adds typed content on top of the Blog module: a registry of content types, validated custom_fields, and per-type behaviors (approval, scheduling, visibility, formats).
This page explains what is core, what is optional, how to activate the feature, and where to read the API.
Depends on Blog ​
Install blog core first. Post Types extends posts with post_type and custom_fields and adds post_type_definitions.
Core vs Extensions ​
| Area | Type | Required to use CPT? | Notes |
|---|---|---|---|
post_type_definitions registry | Core | Yes | Type keys, field schema, behaviors |
posts.post_type + posts.custom_fields | Core | Yes | Columns added by module base.sql |
SEO per type (post_type_seo) | Extension | No | Schema only in v1 — no dedicated CRUD API |
Type restrictions (post_type_restrictions) | Extension | No | Schema only in v1 — no dedicated CRUD API |
| Sample type catalog | Docs only | No | See Examples — Module Hub never auto-installs sample types |
Friendly rule ​
- Install the module schema via Module Hub.
- Enable the feature with env (
POST_TYPES_ENABLEDor MCU). - Create the types you need via
POST /api/v1/post-types(use the Examples catalog as a starting point).
Install ≠enable. Schema can exist while the API still returns 503 MODULE_DISABLED until the flag is on.
Activation flow ​
- Install Blog, then install
post-typesfrom Module Hub (target: "all"installs core + SEO + restrictions extensions). - Dry-run (optional) then run — use
Content-Type: application/jsonand plain ASCII JSON:
POST /api/v1/modules/install/post-types/dry-run
Content-Type: application/json{
"target": "all",
"runtime_scope": "flowless-core"
}POST /api/v1/modules/install/post-types
Content-Type: application/json{
"target": "all",
"runtime_scope": "flowless-core"
}If you get 400 with Invalid JSON body, the request never reached schema validation — usually NBSP/smart quotes from copy-paste, or a missing/wrong Content-Type. Invalid input with fields means the JSON parsed but a field failed validation. See Module Install Dry Run.
- Set:
BLOG_ENABLED=true
POST_TYPES_ENABLED=true
# optional: POST_TYPES_MCU=post-types://enabled- Restart the Flowless instance.
- Create types, then create posts with
post_type+custom_fields(or filter withGET /api/v1/posts?type=).
Examples ​
Starter catalog of common content types. Module Hub does not install these automatically — create them with POST /api/v1/post-types (or copy the JSON below).
Blog Post (post) ​
- Slug prefix:
blog/· Icon:file-text· Color:#3B82F6 - Fields: none (
field_schema: []) - Behaviors: SEO, comments, reactions, bookmarks, views, scheduling on; password visibility allowed; approval off; formats: markdown, html, tiptap_json
Case Study (case-study) ​
- Slug prefix:
case-studies/· Icon:briefcase· Color:#10B981 - Fields:
client_name(text, required),industry(select),challenge/solution/results(textarea; results required),duration,project_url(url),technologies - Behaviors: SEO, reactions, bookmarks, views, scheduling on; comments off;
requires_approval: true; password visibility off
FAQ (faq) ​
- Slug prefix:
faq/· Icon:help-circle· Color:#F59E0B - Fields:
answer(textarea, required) - Behaviors: Lightweight — SEO and engagement flags off; formats: markdown, html
Knowledge Base (knowledge-base) ​
- Slug prefix:
kb/· Icon:book-open· Color:#8B5CF6 - Fields:
difficulty(select),estimated_time(number),product,version - Behaviors: Full engagement + SEO + scheduling; password visibility off
Team Member (team-member) ​
- Slug prefix:
team/· Icon:users· Color:#EC4899 - Fields:
job_title(required),department,bio,linkedin/twitter/github(url),join_date(date),skills - Behaviors: No engagement stack; markdown only
Changelog (changelog) ​
- Slug prefix:
changelog/· Icon:list· Color:#6366F1 - Fields:
version(required),change_type(select, required),impact(select) - Behaviors: Reactions + scheduling on; SEO/comments off; markdown only
Testimonial (testimonial) ​
- Slug prefix:
testimonials/· Icon:message-square· Color:#14B8A6 - Fields:
author_name(required),author_title,author_company,author_avatar(url),rating(number),source - Behaviors:
requires_approval: true; no engagement stack; markdown only
Create example (case-study) ​
{
"type_key": "case-study",
"type_name": "Case Study",
"description": "Customer success / case study",
"slug_prefix": "case-studies/",
"icon": "briefcase",
"color": "#10B981",
"is_active": true,
"sort_order": 10,
"field_schema": [
{
"name": "client_name",
"label": "Client Name",
"type": "text",
"required": true,
"max_length": 120
},
{
"name": "industry",
"label": "Industry",
"type": "select",
"required": false,
"options": ["Tech", "Finance", "Healthcare", "Retail", "Education", "SaaS", "E-commerce"]
},
{
"name": "challenge",
"label": "The Challenge",
"type": "textarea",
"required": false
},
{
"name": "solution",
"label": "Our Solution",
"type": "textarea",
"required": false
},
{
"name": "results",
"label": "Results Achieved",
"type": "textarea",
"required": true
},
{
"name": "duration",
"label": "Project Duration",
"type": "text",
"required": false
},
{
"name": "project_url",
"label": "Live Project URL",
"type": "url",
"required": false
},
{
"name": "technologies",
"label": "Technologies Used",
"type": "text",
"required": false
}
],
"behaviors": {
"public_by_default": true,
"enables_seo": true,
"enables_comments": false,
"enables_reactions": true,
"enables_bookmarks": true,
"enables_views": true,
"enables_scheduling": true,
"requires_approval": true,
"allows_password_visibility": false,
"default_visibility": "public",
"allowed_body_formats": ["markdown", "html", "tiptap_json"]
}
}Prefer API create for production. Adapt fields and behaviors per product needs.
Roles and publish approval ​
| Env | Default | Purpose |
|---|---|---|
BLOG_ALLOWED_POST_ROLES | admin,superadmin,author,editor | Create/edit posts |
BLOG_ADMIN_ROLES | admin,superadmin | Blog admins |
POST_TYPES_ADMIN_ROLES | inherits blog admins | Manage type definitions + publish when approval is required |
POST_TYPES_REQUIRE_APPROVAL | false | Global: force non-admin publishes to draft |
When POST_TYPES_REQUIRE_APPROVAL or the type’s behaviors.requires_approval is true, non-admins cannot publish (draft forced / 403 APPROVAL_REQUIRED). Admins can.
Other common behaviors: password visibility gate, default visibility, scheduling gate, max_per_author, allowed_body_formats. post_type is locked after create.
Read the API docs ​
- Post Types operations
- Post Types API overview
- Blog operations (posts with
?type=andcustom_fields) - Module Hub operations
- Blog module