Content Model
A content model in WNCMS represents a type of data entity that stores user-generated or website-managed content — such as Links, Channels, Posts, or Pages. Each content model extends the BaseModel class to gain WNCMS-wide features such as multi-site support, tag handling, and translatable attributes.
Typical Structure
A standard content model in WNCMS may include:
HasFactory— for Laravel factory support.HasTranslations— for multilingual field support.InteractsWithMedia— for image or file uploads.- Constants such as
ICONS,ROUTES, andSTATUSESfor backend metadata. - Optional accessors for derived attributes (like thumbnails or icons).
Example: Link Model
namespace Wncms\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Wncms\Models\BaseModel;
use Wncms\Translatable\Traits\HasTranslations;
class Link extends BaseModel implements HasMedia
{
use HasFactory;
use InteractsWithMedia;
use HasTranslations;
protected static string $packageId = 'wncms';
protected $guarded = [];
protected $translatable = ['name', 'description', 'slogan'];
protected $casts = [
'expired_at' => 'datetime',
'hit_at' => 'datetime',
];
public const ICONS = [
'fontawesome' => 'fa-solid fa-link'
];
public const ROUTES = [
'index',
'create',
];
public const STATUSES = [
'active',
'inactive',
];
public function registerMediaCollections(): void
{
$this->addMediaCollection('link_thumbnail')->singleFile();
$this->addMediaCollection('link_icon')->singleFile();
}
public function getThumbnailAttribute()
{
$media = $this->getMedia('link_thumbnail')->first();
if ($media) return $media->getUrl();
return $this->external_thumbnail;
}
public function getIconAttribute()
{
$media = $this->getMedia('link_icon')->first();
if ($media) return $media->getUrl();
}
}Key Concepts
1. Translatable Fields
The HasTranslations trait allows you to define which attributes support multilingual content.
protected $translatable = ['name', 'description', 'slogan'];WNCMS will automatically handle storing translations in the translations table, and you can access them directly:
$link->name; // Current locale
$link->getTranslation('name', 'en'); // Specific locale2. Media Collections
By implementing HasMedia and using InteractsWithMedia, models can manage file uploads through the Spatie Media Library.
public function registerMediaCollections(): void
{
$this->addMediaCollection('link_thumbnail')->singleFile();
$this->addMediaCollection('link_icon')->singleFile();
}Each collection can hold images, documents, or other file types. You can then retrieve URLs easily with accessors:
$link->thumbnail; // Returns media URL or fallback
$link->icon; // Returns icon image URL3. Constants for Metadata
Constants make your model more expressive and standardized across the CMS.
| Constant | Purpose | Example |
|---|---|---|
ICONS | Icon used for backend UI or menus | 'fontawesome' => 'fa-solid fa-link' |
ROUTES | Defines CRUD routes used in backend | ['index', 'create'] |
STATUSES | Defines possible states of the model | ['active', 'inactive'] |
4. Accessors for Dynamic Attributes
You can define custom attribute accessors to provide computed values.
Example:
public function getThumbnailAttribute()
{
$media = $this->getMedia('link_thumbnail')->first();
return $media ? $media->getUrl() : $this->external_thumbnail;
}This approach lets your templates access $link->thumbnail even if it is dynamically generated or externally stored.
5. Package Awareness
Each content model should declare which package it belongs to:
protected static string $packageId = 'wncms';This ensures that translation keys, configurations, and migrations are scoped correctly when the model is part of a composer package (e.g., wncms-faqs, wncms-ecommerce).
Example: Channel Model
A simpler content model without media or translation:
namespace Wncms\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Wncms\Models\BaseModel;
class Channel extends BaseModel
{
use HasFactory;
protected $guarded = [];
public const ICONS = [
'fontawesome' => 'fa-solid fa-star'
];
public const ROUTES = [
'index',
'create',
];
public function clicks()
{
return $this->hasMany(wncms()->getModelClass('click'));
}
}This example shows how a model can remain lightweight while still inheriting BaseModel features such as tags and multisite support.
Summary
| Feature | Description |
|---|---|
| Extends BaseModel | Inherits multisite, tag, and translation capabilities |
| Supports Translations | Easily manage localized content |
| Media Collections | Manage images and files using Spatie Media Library |
| Standard Constants | Define UI icons, route names, and statuses |
| Package-aware | Works seamlessly within WNCMS and custom packages |
| Custom Accessors | Add computed fields for templates and APIs |
Example Usage
$link = wncms()->getModel('link')->find(1);
echo $link->name; // Localized name
echo $link->thumbnail; // Media URL
echo $link->status; // Active or inactiveBy following this structure, your content models remain consistent, translatable, and fully integrated with the WNCMS ecosystem.