Skip to content

Commit 4fbb0f2

Browse files
committed
Merge branch 'develop'
* develop: docs wip: docs wip: docs wip: docs wip docs, need review wip docs wip: docs Fix styling wip:docs wip :docs add docs Fix styling wip docs Fix styling update Blade.md and ites functions
2 parents c53b72f + e520465 commit 4fbb0f2

26 files changed

+4730
-1173
lines changed

docs/advanced/Customization.md

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
# Customization
2+
3+
This guide explains how to customize InspireCMS with custom publishing states, Filament components, and model overrides.
4+
5+
## Creating Custom Publish States
6+
7+
InspireCMS provides a flexible publishing system that you can extend with your own custom states for workflow management.
8+
9+
### Implementation Steps
10+
11+
1. Create a class implementing `PublishStateInterface`
12+
2. Register your new state in a service provider
13+
3. (Optional) Add custom styling and behavior
14+
15+
## Example: Content Approval Workflow
16+
17+
### Adding a Custom Content Status
18+
19+
```php
20+
use SolutionForest\InspireCms\Facades\ContentStatusManifest;
21+
use SolutionForest\InspireCms\DataTypes\Manifest\ContentStatusOption;
22+
use Filament\Actions\Action;
23+
use SolutionForest\InspireCms\Models\Content;
24+
use SolutionForest\InspireCms\Helpers\ContentHelper;
25+
26+
// Register "approved" state with value 5
27+
ContentStatusManifest::replaceOption(
28+
new ContentStatusOption(
29+
value: 5,
30+
name: 'approved',
31+
formAction: fn () => Action::make('approved')
32+
->authorize('approved')
33+
->action(function (null | Content $record, Action $action, $livewire) {
34+
if (is_null($record)) {
35+
$action->cancel();
36+
return;
37+
}
38+
39+
$publishableState = 'approved';
40+
41+
if (! ContentHelper::handlePublishableRecord($record, $publishableState, $livewire, [])) {
42+
return;
43+
}
44+
45+
$action->success();
46+
}),
47+
)
48+
);
49+
```
50+
51+
### Setting Up Permissions
52+
53+
After adding new Filament components:
54+
55+
```bash
56+
php artisan inspirecms:repair-permissions
57+
```
58+
59+
### Creating Content Approval Policies
60+
61+
**Option 1: Add a Policy Using Gate**
62+
63+
```php
64+
// In your service provider
65+
public function boot(): void
66+
{
67+
Gate::policy(Content::class, YourContentPolicy::class);
68+
}
69+
```
70+
71+
**Option 2: Override Default Policy in Config**
72+
73+
```php
74+
// config/inspirecms.php
75+
return [
76+
'models' => [
77+
'policies' => [
78+
'content' => \App\Policies\YourContentPolicy::class,
79+
]
80+
],
81+
];
82+
```
83+
84+
### Policy Class Example
85+
86+
```php
87+
namespace App\Policies;
88+
89+
use App\Models\User;
90+
use Illuminate\Contracts\Auth\Authenticatable;
91+
use Illuminate\Database\Eloquent\Model;
92+
use SolutionForest\InspireCms\Models\Contracts\Content;
93+
94+
class YourContentPolicy
95+
{
96+
/**
97+
* Determine if user can approve content
98+
*/
99+
public function approved($user, $content)
100+
{
101+
return $user->hasAnyRole(['editor', 'senior_editor']);
102+
}
103+
104+
/**
105+
* Determine if user can publish content
106+
*/
107+
public function publish($user, $content)
108+
{
109+
return $user->hasRole('senior_editor');
110+
}
111+
}
112+
```
113+
114+
### Overriding the Content Model
115+
116+
1. **Create Extended Model**
117+
118+
```php
119+
namespace App\Models;
120+
121+
use SolutionForest\InspireCms\Models\Content as BaseModel;
122+
use SolutionForest\InspireCms\Models\Contracts\Content as ContentContract;
123+
124+
class Content extends BaseModel implements ContentContract
125+
{
126+
public function isPublished(): bool
127+
{
128+
// Published if status is 1 (published) or 5 (approved)
129+
return $this->status === 1 || $this->status === 5;
130+
}
131+
132+
public function scopeWhereIsPublished($query, bool $condition = true)
133+
{
134+
if ($condition) {
135+
return $query->where(function($query) {
136+
$query->where('status', 1)->orWhere('status', 5);
137+
});
138+
}
139+
140+
return $query->where(function($query) {
141+
$query->where('status', '!=', 1)->where('status', '!=', 5);
142+
});
143+
}
144+
}
145+
```
146+
147+
2. **Update Configuration**
148+
149+
```php
150+
// config/inspirecms.php
151+
return [
152+
'models' => [
153+
'content' => \App\Models\Content::class,
154+
],
155+
];
156+
```
157+
158+
### Complete Implementation Example
159+
160+
**Service Provider Setup**
161+
162+
```php
163+
namespace App\Providers;
164+
165+
use Illuminate\Support\ServiceProvider;
166+
use SolutionForest\InspireCms\Facades\ContentStatusManifest;
167+
use SolutionForest\InspireCms\DataTypes\Manifest\ContentStatusOption;
168+
use Filament\Actions\Action;
169+
use SolutionForest\InspireCms\Models\Content;
170+
use Illuminate\Support\Facades\Gate;
171+
172+
class ContentPublishingServiceProvider extends ServiceProvider
173+
{
174+
public function boot(): void
175+
{
176+
// Register custom status
177+
ContentStatusManifest::replaceOption(
178+
new ContentStatusOption(
179+
value: 5,
180+
name: 'approved',
181+
formAction: fn () => Action::make('approved')
182+
->label('Approve')
183+
->color('success')
184+
->icon('heroicon-o-check-circle')
185+
->authorize('approved')
186+
->action(function (null | Content $record, Action $action, $livewire) {
187+
if (is_null($record)) {
188+
$action->cancel();
189+
return;
190+
}
191+
192+
$record->status = 5;
193+
$record->save();
194+
195+
$action->success();
196+
$livewire->notify('success', 'Content has been approved!');
197+
}),
198+
)
199+
);
200+
201+
// Register policy
202+
Gate::policy(Content::class, \App\Policies\ContentApprovalPolicy::class);
203+
}
204+
}
205+
```
206+
207+
**Workflow Configuration**
208+
209+
This creates a workflow where:
210+
- Authors create and submit content (draft)
211+
- Editors review and approve content (approved)
212+
- Senior editors make final publishing decisions (published)
213+
214+
Content is visible on the frontend if either approved or published.
215+
216+
## Adding Filament Components
217+
218+
### Adding Clusters
219+
220+
**Option 1: Using Artisan**
221+
```bash
222+
php artisan make:filament-cluster YourClusterName --panel=cms
223+
```
224+
225+
**Option 2: Manual Creation**
226+
Create your cluster and add it to `filament.cluster` in the config file.
227+
228+
**Required Implementation:**
229+
```php
230+
use Filament\Clusters\Cluster;
231+
use SolutionForest\InspireCms\Filament\Concerns\ClusterSectionTrait;
232+
use SolutionForest\InspireCms\Filament\Contracts\ClusterSection;
233+
234+
class Test extends Cluster implements ClusterSection
235+
{
236+
use ClusterSectionTrait;
237+
}
238+
```
239+
240+
### Adding Resources
241+
242+
**Option 1: Using Artisan**
243+
```bash
244+
php artisan make:filament-resource YourResourceName --panel=cms
245+
```
246+
247+
**Option 2: Manual Creation**
248+
Create your resource and add it to `filament.resources` in the config file.
249+
250+
**Required Implementation:**
251+
```php
252+
use Filament\Resources\Resource;
253+
use SolutionForest\InspireCms\Filament\Concerns\ClusterSectionResourceTrait;
254+
use SolutionForest\InspireCms\Filament\Contracts\ClusterSectionResource;
255+
256+
class TestResource extends Resource implements ClusterSectionResource
257+
{
258+
use ClusterSectionResourceTrait;
259+
260+
protected static ?string $cluster = \App\Clusters\Test::class;
261+
}
262+
```
263+
264+
### Adding Pages
265+
266+
**Option 1: Using Artisan**
267+
```bash
268+
php artisan make:filament-page YourPageName --panel=cms
269+
```
270+
271+
**Option 2: Manual Creation**
272+
Create your page and add it to `filament.pages` in the config file.
273+
274+
**Required Implementation:**
275+
```php
276+
use Filament\Pages\Page;
277+
use SolutionForest\InspireCms\Filament\Concerns\ClusterSectionPageTrait;
278+
use SolutionForest\InspireCms\Filament\Contracts\ClusterSectionPage;
279+
use SolutionForest\InspireCms\Filament\Contracts\GuardPage;
280+
281+
class Test extends Page implements ClusterSectionPage, GuardPage
282+
{
283+
use ClusterSectionPageTrait;
284+
285+
protected static ?string $cluster = \App\Clusters\Test::class;
286+
287+
public static function getPermissionName(): string
288+
{
289+
return 'view_test_page';
290+
}
291+
292+
public static function getPermissionDisplayName(): string
293+
{
294+
return 'View test page';
295+
}
296+
}
297+
```
298+
299+
> [!IMPORTANT]
300+
> Always ensure your Cluster implements the `SolutionForest\InspireCms\Filament\Contracts\ClusterSection` interface.
301+
302+
## Customize Model
303+
304+
```php
305+
public function register(): void
306+
{
307+
\SolutionForest\InspireCms\Facades\ModelManifest::replace(
308+
\SolutionForest\InspireCms\Models\Contracts\Content::class,
309+
Your\Model\Class::class,
310+
);
311+
}
312+
```

0 commit comments

Comments
 (0)