Base Model
BaseModel is the foundation class for all models in WNCMS Core v6.x.x.
It extends Laravel's native Illuminate\Database\Eloquent\Model and implements BaseModelInterface, providing essential features like multi-site support, tag handling, dynamic model naming, and attribute event hooks.
Requirements
- PHP 8.2+
- Laravel 12.0+
- WNCMS Core 6.x.x
Location
Wncms\Models\BaseModelPurpose
All WNCMS models (and your custom models) should extend this class to inherit:
- Multi-site awareness through
HasMultisitetrait - Tag relationship and filtering via
HasTagstrait - Required model key registration (
$modelKey) - Package identification (
$packageId) - Event dispatching when accessing attributes
- Translatable model name resolution
- Tag metadata definition support
Key Properties
Required Properties
abstract class BaseModel extends Model implements BaseModelInterface
{
use HasMultisite;
use HasTags;
// Package identifier (default: 'wncms')
public static $packageId = 'wncms';
// Required: unique model identifier
public static $modelKey = '';
// Tag metadata definitions (optional)
protected static array $tagMetas = [];
}Important
Every model extending BaseModel must define public static $modelKey. The booted() method will throw an exception if this is not set.
Example Model Setup
namespace App\Models;
use Wncms\Models\BaseModel;
class Product extends BaseModel
{
public static $modelKey = 'product';
protected static array $tagMetas = [
[
'key' => 'product_category',
'short' => 'category',
'route' => 'frontend.products.tag',
],
[
'key' => 'product_tag',
'short' => 'tag',
'route' => 'frontend.products.tag',
],
];
}Traits Used
HasMultisite
Adds support for multi-website data isolation.
Each record can belong to a specific website when multi-site mode is enabled via the website_id column.
HasTags
Provides a unified interface for tag assignment and filtering using the wncms-tags package.
Supports multiple tag types through the $tagMetas property.
Tag Metadata System
Defining Tag Metas
Instead of the old TAG_TYPES constant, WNCMS v6.x.x uses $tagMetas array:
protected static array $tagMetas = [
[
'key' => 'post_category', // Tag type key
'short' => 'category', // Short name for UI
'route' => 'frontend.posts.tag', // Frontend route
],
[
'key' => 'post_tag',
'short' => 'tag',
'route' => 'frontend.posts.tag',
],
];Getting Tag Metadata
The getTagMeta() method processes and enriches tag metadata:
public static function getTagMeta(): array
{
$raw = static::$tagMetas ?? [];
if (empty($raw)) {
return [];
}
$package = static::getPackageId();
$modelClass = static::class;
$metas = [];
foreach ($raw as $meta) {
$metas[] = array_merge($meta, [
'model' => $modelClass,
'model_key' => static::getModelKey(),
'package' => $package,
'label' => $package . "::word." . $meta['key'],
]);
}
return $metas;
}This returns enriched metadata with model class, package info, and translation keys.
Boot Logic
protected static function booted()
{
if (empty(static::$modelKey)) {
throw new \Exception(static::class . ' must define public static $modelKey.');
}
}The boot method ensures every model has a $modelKey defined. This is required for WNCMS's internal model registration system.
Attribute Event Hook
BaseModel overrides getAttribute() to dispatch a custom event whenever an attribute is retrieved:
public function getAttribute($key)
{
$value = parent::getAttribute($key);
if (array_key_exists($key, $this->attributes)) {
$event = new \Wncms\Events\ModelGettingAttribute($this, $key, $value);
event($event);
$value = $event->value;
}
if ($this->hasCast($key)) {
if (is_string($value) || is_null($value)) {
return $this->castAttribute($key, $value);
}
return $value;
}
return $value;
}This event-based approach allows listeners (e.g., keyword replacers, filters, plugins) to modify field values at runtime without altering database data.
Use Case
You can listen to ModelGettingAttribute to transform content, inject dynamic values, or apply global filters across all models.
Model Name Resolution
getModelName() returns a localized display name for the model based on priority fallbacks:
public static function getModelName(?string $locale = null): string
{
$short = strtolower(class_basename(static::class));
$packageId = static::getPackageId();
// 1. User override via settings
if (function_exists('gss') && $packageId) {
$override = gss("{$packageId}::{$short}_model_name");
if (!empty($override)) {
return $override;
}
}
// 2. Package translation
if ($packageId) {
$translated = __("{$packageId}::word.{$short}", locale: $locale);
if ($translated !== "{$packageId}::word.{$short}") {
return $translated;
}
}
// 3. Core translation
$core = __("wncms::word.{$short}", locale: $locale);
if ($core !== "wncms::word.{$short}") {
return $core;
}
// 4. Fallback to formatted class name
return ucfirst(str_replace('_', ' ', $short));
}Priority Order:
- User-defined override from settings (
gss()function) - Package-specific translation (e.g.,
wncms-faqs::word.faq) - Core translation (
wncms::word.post) - Fallback to formatted class name (e.g.,
Post→Post)
Example Usage:
Post::getModelName('zh_TW'); // → "文章"
Post::getModelName('en'); // → "Post"
## Multisite Mode Helper
`BaseModel` provides a centralized mode resolver so model-level checks do not duplicate raw config logic:
```php
public static function getMultiWebsiteMode(): string
public static function isWebsiteScopedModel(): boolgetMultiWebsiteMode() resolves mode in this order:
config('wncms.models.{model_key}.website_mode')config('wncms.model_website_modes.{model_key}')gss('model_website_modes')runtime overrides (when available)
Then normalizes to one of: global, single, multi.
## Default Constants
BaseModel provides default constants that can be overridden:
```php
public const ICONS = [
'fontawesome' => 'fa-solid fa-cube'
];
public const ROUTES = [
'index',
'create',
];
public const SORTS = [
'id',
'status',
'created_at',
'updated_at',
];These are used by backend controllers and views for consistent UI behavior.
Package Identification
public static function getPackageId(): ?string
{
return property_exists(static::class, 'packageId')
? static::$packageId
: null;
}Returns the package identifier, useful for translation lookups and plugin system integration.
Real-World Example
Here's a complete example from WNCMS Core - the Post model:
namespace Wncms\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Spatie\MediaLibrary\HasMedia;
use Spatie\MediaLibrary\InteractsWithMedia;
use Wncms\Translatable\Traits\HasTranslations;
class Post extends BaseModel implements HasMedia
{
use HasFactory;
use InteractsWithMedia;
use SoftDeletes;
use HasTranslations;
public static $modelKey = 'post';
protected $guarded = [];
protected $casts = [
'published_at' => 'datetime',
'expired_at' => 'datetime'
];
protected static array $tagMetas = [
[
'key' => 'post_category',
'short' => 'category',
'route' => 'frontend.posts.tag',
],
[
'key' => 'post_tag',
'short' => 'tag',
'route' => 'frontend.posts.tag',
],
];
protected $translatable = ['title', 'excerpt', 'keywords', 'content'];
}Summary
BaseModel provides: ✅ Required $modelKey validation
✅ Multi-site support via HasMultisite
✅ Tag system via HasTags + $tagMetas
✅ Attribute event hooks for runtime modifications
✅ Localized model names with fallbacks
✅ Package identification system
✅ Default constants for backend UI
All custom models should extend this class to leverage WNCMS's powerful features.