menu_book Navigation menu

Content Types

Creating a Content Type defines the blueprint for your data. It instructs the CMS on how to store, retrieve, and present information to the user.

The Core Architecture (The "Passport" System)

Before diving into specific types, it is crucial to understand that every piece of content in Pragma CMS shares a unified core. Regardless of the Content Type you choose, the system will always create a base record in two central tables:

  • entries: Manages the IDs, publishing status, author, hierarchy (parent_id), and timestamps.
  • entries_translation: Manages the localized "identity" of the content (Title, URL Slug, and SEO Meta data).

This guarantees lightning-fast global routing and search capabilities. The specific fields you create are then stored using one of the three strategies below.

Single

Singles are used for unique pages that do not repeat in your system (e.g., Homepage, About Us, Blog Listing Page).

  • Data Storage: Custom fields are stored in a generic EAV (Entity-Attribute-Value) table: entries_fields.
  • Why? Creating a dedicated database table with 50 columns for a single homepage is highly inefficient and creates database bloat. The EAV model offers maximum flexibility here: adding a new field to your homepage requires zero structural database changes (no ALTER TABLE), keeping the system fast and flexible.

Collection

Collections are used for repetitive content like Blog Posts, Products, or Portfolio items.

  • Data Storage: Custom fields are stored in dedicated tables generated on the fly (e.g., articles and articles_translation).
  • Why? Performance. When you need to filter, sort, or search through thousands of records, the EAV model becomes a bottleneck. Dedicated tables allow for strict SQL indexing, native data types (INT, VARCHAR, JSON), and raw execution speed.

Structure

Structures are identical to Collections in terms of data storage (dedicated tables), but they introduce a hierarchy.

  • Use Case: Documentation (Chapter > Page), nested navigation menus, or corporate organization charts.
  • Why? Structures utilize the parent_id in the core entries table, enabling highly optimized recursive SQL queries (CTE) to build trees and automatic breadcrumbs without heavy PHP processing.

System Content Types (is_system => true)

By default, Pragma CMS automatically manages the physical database tables for Collections and Structures during file synchronization. However, when building advanced features that require highly customized SQL constraints, unique indexes, or complex relational pivot tables (e.g., recipes with custom ingredient relationships), you can decouple the logical Content Type definition from the database schema management.

Adding 'is_system' => true to your Content Type configuration file alters this behavior:

  • Schema Protection: The ContentTypeManager is instructed never to automatically create, alter (ALTER TABLE), or drop the physical database tables associated with this Content Type during file synchronizations or back-office deletions.
  • Manual Migration Control: You assume full control over the database schema. All physical tables, columns, indexes, and foreign keys must be managed entirely through manual SQL migrations (your up and down migration scripts). This is the recommended approach for production environments where database integrity must be strictly controlled and immutable through back-office actions.
  • Ecosystem Integration: Despite physical schema decoupling, the Content Type remains registered in the system metadata. It continues to leverage the core passport system (entries and entries_translation), automated admin CRUD form rendering, permissions generation, routing, and sitemap hooks transparently.

Example Blueprint Configuration:

PHP
// content-types/collections/recipe.php
return [
  'handle' => 'recipe',
  'title' => 'Recipes',
  'type' => 'collection',
  'is_system' => true, // Stops the CMS from altering the physical tables automatically
  'table' => 'recipes',
  'table_translation' => 'recipes_translation',
  'primary_key' => 'recipe_id',
  // ... schema and other settings
];