Create a Manager
A Manager in WNCMS acts as the logic layer between controllers and models. It encapsulates query logic, caching, and filtering rules so your controllers remain clean and consistent.
This guide shows how to create a custom manager extending WNCMS’s ModelManager.
Purpose of Managers
Managers are responsible for:
- Building and filtering database queries.
- Handling cache logic via
wncms()->cache(). - Applying tag, keyword, and website filters.
- Returning data as Eloquent collections or paginated lists.
- Ensuring consistent behavior across backend, frontend, and API.
Location and Naming
Managers are stored under:
app/Services/Managers/Each manager should follow the naming pattern:
{ModelName}Manager.phpFor example:
PostManager.php
ProductManager.php
FaqManager.phpBasic Example
<?php
namespace App\Services\Managers;
use Wncms\Services\Managers\ModelManager;
use Illuminate\Database\Eloquent\Builder;
class ProductManager extends ModelManager
{
protected string $cacheKeyPrefix = 'wncms_product';
protected string $defaultTagType = 'product_category';
protected bool $shouldAuth = false;
protected string|array $cacheTags = ['products'];
public function getModelClass(): string
{
// Return the Product model (custom or WNCMS default)
return wncms()->getModelClass('product');
}
protected function buildListQuery(array $options): mixed
{
$q = $this->query();
// Apply filters
$this->applyStatus($q, 'status', $options['status'] ?? 'active');
$this->applyTagFilter($q, $options['tags'] ?? [], $options['tag_type'] ?? 'product_category');
$this->applyKeywordFilter($q, $options['keywords'] ?? [], ['title', 'description']);
$this->applyIds($q, 'id', $options['ids'] ?? []);
$this->applyExcludeIds($q, 'id', $options['excluded_ids'] ?? []);
$this->applyWebsiteId($q, $options['website_id'] ?? null);
// Sorting and limit
$sort = $options['sort'] ?? 'id';
$direction = $options['direction'] ?? 'desc';
$this->applyOrdering($q, $sort, $direction, $sort === 'random');
$this->applyLimit($q, $options['count'] ?? 0);
$this->applyOffset($q, $options['offset'] ?? 0);
return $q;
}
}Overridable Methods
When extending ModelManager, you can override these core methods:
| Method | Purpose |
|---|---|
getModelClass() | Return the model class handled by the manager. |
buildListQuery(array $options) | Define how queries are built. |
get() | Modify how a single record is fetched. |
getList() | Modify how list results are retrieved. |
applyOrdering() | Customize ordering logic. |
Common Helper Methods
You can use built-in query helpers inherited from ModelManager:
| Method | Description |
|---|---|
applyIds($q, $column, $ids) | Filter by IDs |
applyExcludeIds($q, $column, $ids) | Exclude IDs |
applyTagFilter($q, $tags, $type) | Filter by tag type |
applyExcludedTags($q, $excludedTagIds) | Exclude tag IDs |
applyKeywordFilter($q, $keywords, $columns) | Apply keyword search |
applyStatus($q, $column, $status) | Filter by status |
applyWebsiteId($q, $websiteId) | Scope query by website |
applyOrdering($q, $column, $sequence, $isRandom) | Apply sorting |
applyLimit($q, $count) | Apply limit |
applyOffset($q, $offset) | Skip records |
applyWiths($q, $relations) | Eager load relations |
These utilities ensure that all WNCMS managers behave consistently.
Example Usage in Controller
Once your manager is registered, you can use it directly through wncms():
$products = wncms()->product()->getList([
'status' => 'active',
'tags' => ['featured'],
'sort' => 'price',
'direction' => 'asc',
'count' => 10,
]);Or fetch a single record:
$product = wncms()->product()->get(['slug' => 'premium-plan']);Resolution Behavior
After creating app/Services/Managers/ProductManager.php, WNCMS resolves it automatically through wncms()->product().
App\Services\Managers\*Managerhas higher priority than core managers.- Managers are created through Laravel's container first, so constructor dependencies are supported.
- Singular/plural aliases are both valid (
wncms()->product()andwncms()->products()).
Tips for Custom Managers
- Always define a unique
$cacheKeyPrefixand$cacheTags. - Set
$defaultTagTypefor tag filtering consistency. - Reuse
ModelManagerhelpers instead of raw Eloquent conditions. - Use
applyWebsiteId()when your model supports multi-website scope. - Use
distinct()in the query if joining tags or counts. - When supporting boolean filters, pass explicit
falsevalues directly (for example'status' => false) and letModelManagerhelpers apply them. - Use
sort/directionin public options.
Example Folder Structure
app/
└── Services/
└── Managers/
├── ProductManager.php
├── PostManager.php
└── LinkManager.phpEach manager handles its respective model while sharing consistent caching, filtering, and list-building logic.
Core Starter Template
Core provides Wncms\Services\Managers\StarterManager as a copy-ready scaffold that already extends ModelManager.
When copying it:
- Rename class/file to
{ModelName}Manager. - Replace
getModelClass()model key. - Adjust default tag type, searchable fields, and option mapping in
buildListQuery().
Do not use StarterManager directly in production without replacing its model key.
Special Case: SettingManager
SettingManager is intentionally not a ModelManager subclass. It is a key-value service used by helpers like gss() / uss() and keeps a different API signature (get($key, $fallback)).