CMS Framework - v2.2.2
Content Types Developer Guide
Overview
Content types allow you to define custom post types in Digital Shopfront CMS. This guide covers how to register content types programmatically, configure their behavior, and integrate them with the admin interface.
Table of Contents
- Registering Content Types
- Available Options
- Table Naming Conventions
- Admin Pages Configuration
- Best Practices
- Examples
Registering Content Types
Via Service Provider
Register content types in your service provider's boot() method:
<?php
namespace App\Providers;
use ArtisanPackUI\CMSFramework\Modules\ContentTypes\Managers\ContentTypeManager;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
public function boot(): void
{
$contentTypeManager = app(ContentTypeManager::class);
$contentTypeManager->register([
'name' => 'Products',
'slug' => 'products',
'table_name' => 'products',
'model_class' => 'App\\Models\\Product',
'description' => 'Manage your product catalog',
'hierarchical' => false,
'has_archive' => true,
'archive_slug' => 'shop',
'supports' => ['title', 'content', 'excerpt', 'featured_image'],
'public' => true,
'show_in_admin' => true,
'icon' => 'fas-shopping-cart',
'menu_position' => 30,
'admin_pages' => [
'listing' => [
'enabled' => true,
'title' => 'Products',
'slug' => 'products',
'component' => 'Modules\\Shop\\Livewire\\Products\\Index',
'capability' => 'products.view',
'icon' => 'fas-shopping-cart',
'position' => 30,
],
'create' => [
'enabled' => true,
'title' => 'Add New Product',
'slug' => 'products.create',
'component' => 'Modules\\Shop\\Livewire\\Products\\Create',
'capability' => 'products.create',
'parent_slug' => 'products',
],
'edit' => [
'enabled' => true,
'title' => 'Edit Product',
'slug' => 'products.edit',
'component' => 'Modules\\Shop\\Livewire\\Products\\Edit',
'capability' => 'products.edit',
'parent_slug' => 'products',
'hidden' => true,
],
],
]);
}
}
Via Filter Hook
Register content types using the filter hook (useful for plugins):
addFilter('ap.contentTypes.registeredContentTypes', function ($contentTypes) {
$contentTypes['products'] = [
'name' => 'Products',
'slug' => 'products',
'table_name' => 'products',
'model_class' => 'App\\Models\\Product',
'supports' => ['title', 'content', 'featured_image'],
'has_archive' => true,
'archive_slug' => 'shop',
'public' => true,
'show_in_admin' => true,
];
return $contentTypes;
});
Via Database
Create content types through the admin UI or via API:
$contentType = ContentType::create([
'name' => 'Events',
'slug' => 'events',
'table_name' => 'events',
'model_class' => 'App\\Models\\Event',
'hierarchical' => false,
'has_archive' => true,
'public' => true,
'show_in_admin' => true,
]);
Available Options
Required Options
| Option | Type | Description |
|---|---|---|
name |
string | Display name (e.g., "Blog Posts") |
slug |
string | Machine name (e.g., "posts") |
table_name |
string | Database table name (e.g., "posts") |
model_class |
string | Fully qualified model class |
Optional Options
| Option | Type | Default | Description |
|---|---|---|---|
description |
string | null | Description shown in admin |
hierarchical |
boolean | false | Supports parent-child relationships |
has_archive |
boolean | true | Has archive pages |
archive_slug |
string | null | Archive URL slug (e.g., "blog") |
supports |
array | null | Supported features |
metadata |
array | null | Additional custom settings |
public |
boolean | true | Visible on frontend |
show_in_admin |
boolean | true | Show in admin menu |
icon |
string | null | FontAwesome icon (e.g., "fas-newspaper") |
menu_position |
integer | null | Admin menu position |
admin_pages |
array | null | Admin page configurations |
Supports Options
The supports array defines which features are available:
'supports' => [
'title', // Title field
'content', // Content editor
'excerpt', // Excerpt field
'featured_image', // Featured image
'author', // Author assignment
'comments', // Comments (if implemented)
'revisions', // Revisions (if implemented)
]
Table Naming Conventions
Follow these conventions when naming your content type tables:
1. Use Snake Case
✓ 'table_name' => 'products'
✓ 'table_name' => 'product_reviews'
✗ 'table_name' => 'Products'
✗ 'table_name' => 'productReviews'
2. Use Plural Forms
✓ 'table_name' => 'products'
✓ 'table_name' => 'events'
✗ 'table_name' => 'product'
✗ 'table_name' => 'event'
3. Taxonomy Tables
Prefix taxonomy tables with the content type:
✓ 'product_categories'
✓ 'product_tags'
✓ 'event_types'
✗ 'categories'
✗ 'tags'
4. Pivot Tables
Use descriptive names for pivot tables:
✓ 'post_category_pivots'
✓ 'product_tag_pivots'
✗ 'category_post'
✗ 'tag_product'
Admin Pages Configuration
Admin pages allow automatic registration of CRUD interfaces in the admin menu.
Configuration Structure
'admin_pages' => [
'listing' => [
'enabled' => true,
'title' => 'Products', // Menu title
'slug' => 'products', // Route slug
'component' => 'Modules\\Shop\\Livewire\\Products\\Index',
'capability' => 'products.view', // Required capability
'icon' => 'fas-shopping-cart', // FontAwesome icon
'position' => 30, // Menu position
'parent_slug' => null, // Top-level menu
],
'create' => [
'enabled' => true,
'title' => 'Add New',
'slug' => 'products.create',
'component' => 'Modules\\Shop\\Livewire\\Products\\Create',
'capability' => 'products.create',
'parent_slug' => 'products', // Child of listing
],
'edit' => [
'enabled' => true,
'title' => 'Edit Product',
'slug' => 'products.edit',
'component' => 'Modules\\Shop\\Livewire\\Products\\Edit',
'capability' => 'products.edit',
'parent_slug' => 'products',
'hidden' => true, // Don't show in menu
],
]
Routes
Routes are automatically registered based on admin pages configuration:
- Listing:
/admin/{slug} - Create:
/admin/{slug}/create - Edit:
/admin/{slug}/{id}/edit
Best Practices
1. Consistent Naming
Use consistent naming across slug, table, and model:
// Good
'slug' => 'products',
'table_name' => 'products',
'model_class' => 'App\\Models\\Product',
// Bad
'slug' => 'product',
'table_name' => 'product_items',
'model_class' => 'App\\Models\\ProductModel',
2. Use Capabilities Format
Follow the feature.capability format:
✓ 'products.view'
✓ 'products.create'
✓ 'products.edit'
✗ 'view_products'
✗ 'can_edit_product'
3. Set Appropriate Defaults
Configure sensible defaults for your content type:
'hierarchical' => false, // Only true if needed
'has_archive' => true, // Most content types need archives
'public' => true, // Unless it's internal only
'show_in_admin' => true, // Unless managing via code only
4. Create Migration First
Always create the database table before registering the content type:
php artisan make:migration create_products_table
5. Use Admin Pages
Configure admin pages to automatically create admin UI:
'admin_pages' => [
'listing' => ['enabled' => true, ...],
'create' => ['enabled' => true, ...],
'edit' => ['enabled' => true, ...],
]
Examples
Simple Content Type (Events)
$contentTypeManager->register([
'name' => 'Events',
'slug' => 'events',
'table_name' => 'events',
'model_class' => 'App\\Models\\Event',
'description' => 'Manage upcoming events',
'supports' => ['title', 'content', 'excerpt', 'featured_image'],
'has_archive' => true,
'archive_slug' => 'events',
'public' => true,
'show_in_admin' => true,
'icon' => 'fas-calendar',
'menu_position' => 25,
]);
Hierarchical Content Type (Documentation)
$contentTypeManager->register([
'name' => 'Documentation',
'slug' => 'docs',
'table_name' => 'docs',
'model_class' => 'App\\Models\\Doc',
'hierarchical' => true, // Enable parent-child
'has_archive' => true,
'archive_slug' => 'documentation',
'supports' => ['title', 'content'],
'public' => true,
'show_in_admin' => true,
'icon' => 'fas-book',
]);
Internal Content Type (Form Submissions)
$contentTypeManager->register([
'name' => 'Form Submissions',
'slug' => 'submissions',
'table_name' => 'form_submissions',
'model_class' => 'App\\Models\\FormSubmission',
'hierarchical' => false,
'has_archive' => false, // No public archives
'public' => false, // Admin only
'show_in_admin' => true,
'icon' => 'fas-envelope',
'supports' => [], // Custom fields only
]);
Retrieving Content Types
Get All Registered Content Types
$contentTypeManager = app(ContentTypeManager::class);
$contentTypes = $contentTypeManager->getRegisteredContentTypes();
Get Specific Content Type
$contentType = $contentTypeManager->getContentType('products');
Check if Content Type Exists
if ($contentTypeManager->contentTypeExists('products')) {
// Content type exists
}
Get Model Instance
$contentType = ContentType::where('slug', 'products')->first();
$modelInstance = $contentType->getModelInstance();
Check Supported Features
if ($contentType->supportsFeature('featured_image')) {
// Content type supports featured images
}
Content Status Enum (v1.1.0)
Content types that support publishing (posts, pages) use the ContentStatus enum instead of plain strings:
use ArtisanPackUI\CMSFramework\Modules\ContentTypes\Enums\ContentStatus;
// Query with enum
$posts = Post::where('status', ContentStatus::Published)->get();
// Use scopes via HasContentStatus trait
$published = Post::published()->get();
$drafts = Post::draft()->get();
// Check status
if ($post->isPublished()) {
// ...
}
Available statuses: Draft, Published, Scheduled, Private.
See developer/enums for the complete enum reference and developer/traits for the HasContentStatus and HasContentFilters traits.