Collections & Content

Collections are the heart of ZephyrPHP. Create any content type — blog posts, products, events, portfolios — with custom fields, relations, and workflows.

What Are Collections?

A collection is a content type you define through the CMS admin panel. Each collection gets its own database table, entry list, and editor form — all generated automatically from the fields you configure.

Creating a Collection

  1. Go to CMS Admin > Collections
  2. Click Create Collection
  3. Enter a name (e.g., "Blog Posts") — slug auto-generates (e.g., "blog_posts")
  4. Configure options:
    • Enable REST API — expose entries via API endpoints
    • Publishable — adds draft/published status and scheduled publishing
    • Enable Slug Field — adds a URL-friendly slug to each entry
    • SEO Meta Fields — adds meta title, description, OG tags per entry
    • Public Submit — allow visitors to submit entries via frontend forms
    • Translatable — enable multi-language entries
  5. Save — your collection is ready for fields

Field Types

Add fields to define the structure of your content:

Field Type Database Column Use Case
TextVARCHAR(255)Titles, names, short text
TextareaTEXTDescriptions, excerpts
Rich TextLONGTEXTFull content with HTML formatting
NumberINTQuantities, ratings, order
DecimalDECIMAL(10,2)Prices, measurements
BooleanTINYINTToggles (featured, active)
DateDATEEvent dates, deadlines
Date & TimeDATETIMETimestamps, scheduling
EmailVARCHAR(255)Email addresses
URLVARCHAR(255)Website links
SelectVARCHAR(255)Dropdown choices (status, category)
ImageVARCHAR(500)Featured images, thumbnails
FileVARCHAR(500)Document uploads (PDF, etc.)
SlugVARCHAR(255)URL-friendly identifier — auto-becomes the slug source field
JSONJSONStructured data, metadata
RelationINT / JOIN tableLink to other collections (author, category)

The Slug Field Type

When you enable "Enable Slug Field" on a collection and add a field with type Slug, that field automatically becomes the slug source. The system generates URL-friendly slugs from that field's value for each entry.

For example, if you have a "Title" field of type Slug and enter "Hello World", the entry's slug becomes hello-world.

No Slug Source?

If you enable slugs but haven't added a Slug-type field, a yellow warning appears in the Fields tab directing you to add one.

Relation Fields

Link entries across collections using three relation types:

  • One to One — Each entry links to one entry in the related collection
  • One to Many — Each entry links to multiple entries
  • Many to Many — Entries in both collections can link to each other (uses a join table)

When adding a Relation field, select the related collection and a display field (the field shown as the label in the entry editor).

System Fields

Every collection automatically includes:

FieldTypeDescription
idInteger or UUIDPrimary key (auto-increment or UUID, chosen at creation)
slugVARCHAR(255)URL-friendly identifier (when enabled)
created_byIntegerUser who created the entry
created_atDateTimeCreation timestamp
updated_atDateTimeLast update timestamp
statusStringDraft/Published (when publishable)
published_atDateTimePublish date (when publishable)

Managing Entries

Go to Collections > [Collection Name] > View Entries to manage content:

  • Create — Fill out the auto-generated form with your custom fields
  • Edit — Update any entry's fields, status, or SEO metadata
  • Delete — Remove entries individually or in bulk
  • Search & Filter — Search by any searchable field, sort by any sortable field
  • Bulk Actions — Publish, unpublish, or delete multiple entries
  • Import/Export — CSV and JSON import/export with field mapping
  • Saved Views — Save filter/sort presets for quick access
  • Entry History — View and restore previous revisions

Frontend Routing

Set a URL Prefix on a collection to auto-register frontend routes:

  • /prefix — List page showing paginated entries
  • /prefix/{slug} — Detail page showing a single entry

For example, setting URL prefix to blog creates /blog (listing) and /blog/hello-world (detail).

Querying Collections in Templates

Use the collection() and entry() Twig functions to display content:

{# List entries #}
{% set posts = collection('blog_posts', {per_page: 6, sort_dir: 'DESC'}) %}
{% for item in posts.data %}
    <h3>{{ item.title }}</h3>
    <p>{{ item.excerpt|striptags|slice(0, 120) }}</p>
{% endfor %}

{# Single entry #}
{% set post = entry('blog_posts', 'hello-world') %}
<h1>{{ post.title }}</h1>
{{ post.content|raw }}

See the Twig Reference for all available functions and options.

SEO Fields

Enable SEO on any collection to add meta title, meta description, and Open Graph fields to every entry. Use the SEO Twig functions in your templates:

{{ seo_meta(item, 'blog_posts') }}
{{ og_tags(item, 'blog_posts') }}
{{ json_ld(item, 'blog_posts') }}

Content Workflows

Enable workflows on the Workflow tab to require entries to pass through approval stages before publishing. Define custom stages (e.g., draft → review → approved → published) and assign reviewers per stage.

API Access

Enable API access per collection to expose entries via REST endpoints:

  • GET /api/cms/{collection} — List entries with pagination
  • GET /api/cms/{collection}/{id} — Get single entry
  • POST /api/cms/{collection} — Create entry
  • POST /api/cms/{collection}/{id} — Update entry
  • POST /api/cms/{collection}/{id}/delete — Delete entry

Configure rate limiting from the collection settings. See the REST API docs for authentication details.

Public Form Submission

Enable "Public Submit" to let visitors submit entries from the frontend. Use the Twig helper to render a form:

{{ render_collection_form('contact_form') }}

Configure submission settings: success message, redirect URL, email notifications, honeypot bot protection, and rate limiting per IP.

Table Prefixes

CMS system tables use the cms_ prefix. User-created collection tables use the app_ prefix (e.g., app_blog_posts) to keep them clearly separated.