Skip to content
On this page

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 ​

AreaTypeRequired to use CPT?Notes
post_type_definitions registryCoreYesType keys, field schema, behaviors
posts.post_type + posts.custom_fieldsCoreYesColumns added by module base.sql
SEO per type (post_type_seo)ExtensionNoSchema only in v1 — no dedicated CRUD API
Type restrictions (post_type_restrictions)ExtensionNoSchema only in v1 — no dedicated CRUD API
Sample type catalogDocs onlyNoSee Examples — Module Hub never auto-installs sample types

Friendly rule ​

  1. Install the module schema via Module Hub.
  2. Enable the feature with env (POST_TYPES_ENABLED or MCU).
  3. 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 ​

  1. Install Blog, then install post-types from Module Hub (target: "all" installs core + SEO + restrictions extensions).
  2. Dry-run (optional) then run — use Content-Type: application/json and plain ASCII JSON:
http
POST /api/v1/modules/install/post-types/dry-run
Content-Type: application/json
json
{
  "target": "all",
  "runtime_scope": "flowless-core"
}
http
POST /api/v1/modules/install/post-types
Content-Type: application/json
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.

  1. Set:
bash
BLOG_ENABLED=true
POST_TYPES_ENABLED=true
# optional: POST_TYPES_MCU=post-types://enabled
  1. Restart the Flowless instance.
  2. Create types, then create posts with post_type + custom_fields (or filter with GET /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) ​

json
{
  "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 ​

EnvDefaultPurpose
BLOG_ALLOWED_POST_ROLESadmin,superadmin,author,editorCreate/edit posts
BLOG_ADMIN_ROLESadmin,superadminBlog admins
POST_TYPES_ADMIN_ROLESinherits blog adminsManage type definitions + publish when approval is required
POST_TYPES_REQUIRE_APPROVALfalseGlobal: 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 ​

Next ​