## Caching
---
title: Caching
slug: caching
path: docs/v1/caching
uri: /docs/v1/caching
heading: Caching
brief:
quick_links: []
---
## Overview
Caching in InspireCMS accelerates content delivery by storing frequently accessed data in fast-access storage. The system employs several caching strategies:
- **Language Cache**
- **Navigation Cache**: Makes menu loading faster
- **Route Cache**: Improves URL resolution
- **KeyValue Cache**: Stores simple configuration and settings data
---
## Cache Configuration
Configure caching in your application's configuration files.
### Main Cache Settings
Configure basic cache settings in `config/inspirecms.php`:
```php {title="config/inspirecms.php"}
'cache' => [
'languages' => [
'key' => 'inspirecms.languages',
'ttl' => 60 * 60 * 24, // 24 hours in seconds
],
'navigation' => [
'key' => 'inspirecms.navigation',
'ttl' => 60 * 60 * 24,
],
'content_routes' => [
'key' => 'inspirecms.content_routes',
'ttl' => 120 * 60 * 24, // 120 days in seconds
],
'key_value' => [
'ttl' => 60 * 60 * 24,
],
],
```
### Laravel Cache Driver Configuration
InspireCMS uses Laravel's caching system. Configure the cache driver in `config/cache.php`:
```php {title="config/cache.php"}
'default' => env('CACHE_DRIVER', 'file'),
'stores' => [
'file' => [
'driver' => 'file',
'path' => storage_path('framework/cache/data'),
],
'redis' => [
'driver' => 'redis',
'connection' => 'cache',
'lock_connection' => 'default',
],
'memcached' => [
'driver' => 'memcached',
'persistent_id' => env('MEMCACHED_PERSISTENT_ID'),
'sasl' => [
env('MEMCACHED_USERNAME'),
env('MEMCACHED_PASSWORD'),
],
'options' => [
// Memcached::OPT_CONNECT_TIMEOUT => 2000,
],
'servers' => [
[
'host' => env('MEMCACHED_HOST', '127.0.0.1'),
'port' => env('MEMCACHED_PORT', 11211),
'weight' => 100,
],
],
],
],
```
---
## Language Caching
### Working with Language Cache
Example of cached language retrieval:
```php
// This method internally uses caching
la = inspirecms()->getAllAvailableLanguages();
```
### Invalidating Language Cache
Clear the language cache manually:
```php
// Clear all language cache
\SolutionForest\InspireCms\Facades\InspireCms::forgetCachedLanguages();
```
---
## Navigation Caching
### Working with Navigation Cache
Example of cached navigation retrieval:
```php
// This method internally uses caching
$navigation = inspirecms()->getNavigation('main', 'en');
```
### Invalidating Navigation Cache
Clear the navigation cache manually:
```php
// Clear all navigation cache
\SolutionForest\InspireCms\Facades\InspireCms::forgetCachedNavigation();
```
---
## Route Caching
InspireCMS caches content routes for faster URL resolution.
### Route Cache Commands
In addition to Laravel's route caching, clear InspireCMS route cache:
```bash
php artisan route:clear
```
or
```bash
php artisan inspirecms:clear-cache --routes
```
---
## KeyValue Caching
InspireCMS provides a persistent key-value storage system with caching capabilities through the `KeyValue` model.
### Working with KeyValue Model
The `KeyValue` model provides a simple way to store and retrieve configuration values:
```php
[
/**
* Whether to include an X-Powered-By header in HTTP responses
*
* When true, InspireCMS adds an X-Powered-By HTTP header to responses.
*/
'send_powered_by_header' => true,
/**
* License configuration for InspireCMS
*
* These settings are required for the CMS to validate your license.
*/
'license' => [
// Your InspireCMS license key from your subscription
'key' => env('INSPIRECMS_LICENSE_KEY'),
],
/**
* Control how InspireCMS interacts with key plugins
*/
'override_plugins' => [
'field_group_models' => true, // Whether to override field group models
'spatie_permission' => true, // Whether to override Spatie Permission package functionality
],
],
```
### Authentication
Configure how users authenticate with your CMS \([learn more about laravel authentication](https://laravel.com/docs/12.x/authentication#adding-custom-guards)\):
```php
'auth' => [
/**
* Define the guard that InspireCMS will use for authentication
*/
'guard' => [
'name' => 'inspirecms', // The name of the guard - used in auth middleware
'driver' => 'session', // Authentication method (session or token)
'provider' => 'cms_users', // Which provider this guard uses
],
/**
* Define how users are retrieved from your database
*/
'provider' => [
'name' => 'cms_users', // Name of the provider
'driver' => 'eloquent', // Driver to use (eloquent or database)
'model' => \SolutionForest\InspireCms\Models\User::class, // User model - change to use a custom model
],
/**
* Password reset functionality
*/
'resetting_password' => [
'enabled' => true, // Set to false to disable password reset functionality
// other password reset settings...
],
/**
* Security settings to protect against brute-force attacks
*
* Number of failed attempts before lockout
*/
'failed_login_attempts' => 5, // Number of attempts before account lockout
/**
* The number of minutes to lock the user out for after the maximum number of failed login attempts is reached.
*/
'lockout_duration' => 120, // Duration of lockout in minutes
/**
* Controls when super admin checks are performed in the authentication flow
*
* Allowed values: before, after, none
*/
'skip_super_admin_check' => 'before',
/**
* Skip account verification for users.
*
* Set to true to skip account email verification requirements.
*/
'skip_account_verification' => false,
],
```
### Media Management
Configure media uploads, storage, and processing:
```php
'media' => [
/**
* User avatar storage configuration
*/
'user_avatar' => [
'disk' => 'public', // Storage disk to use (public, s3, etc.)
'directory' => 'avatars', // Subdirectory where avatars will be stored
],
/**
* Media library configuration
*/
'media_library' => [
'disk' => 'public', // Storage disk (public makes files accessible via URL)
// Use 's3' or other drivers for cloud storage
/**
* Allowed file types
*
* e.g. ['image/jpeg', 'image/png', 'video/mp4']
*/
'allowed_mime_types' => [],
/**
* Maximum file size in Bytes
*/
'max_file_size' => null,
/**
* Automatic thumbnail generation settings
*/
'thumbnail' => [
'width' => 300, // Width of generated thumbnails in pixels
'height' => 300, // Height of generated thumbnails in pixels
// Set both the same for square thumbnails
],
/**
* Whether to use FFmpeg to extract metadata from video files
*/
'should_map_video_properties_with_ffmpeg' => false, // Set to true to analyze video files
// Requires FFmpeg to be installed on the server
// Enables extraction of duration, dimensions, codec info
// Increases processing time for video uploads
/**
* Responsive image generation settings
*/
'responsive_images' => [
'small' => [
'enabled' => true,
'width' => 400,
],
'medium' => [
'enabled' => true,
'width' => 600,
],
],
],
],
```
### Caching
Optimize performance with caching configurations:
```php
'cache' => [
'languages' => [
'store' => null, // null: Fallback to default store
'key' => 'inspirecms.languages', // Cache key for storing language data
'ttl' => 60 * 60 * 24, // Time-to-live in seconds (24 hours)
// Decrease for more frequent updates
// Increase for better performance
],
'navigation' => [
'store' => null, // null: Fallback to default store
'key' => 'inspirecms.navigation', // Cache key for menu structures
'ttl' => 60 * 60 * 24, // 24 hour cache duration
// Clear with: php artisan cache:clear
// Critical for site performance under high traffic
],
'content_routes' => [
'store' => null, // null: Fallback to default store
'key' => 'inspirecms.content_routes', // Cache key for content URL routing data
'ttl' => 120 * 60 * 24, // 5-day cache duration (longer than other caches)
// Extended duration improves routing performance
// Clear after adding new content types
],
'key_value' => [
'store' => null, // null: Fallback to default store
'ttl' => 60 * 60 * 24, // Cache duration for system settings
// Affects all configuration values retrieved at runtime
// Consider shorter values during development
// Longer values (3-7 days) for production
'prefix' => 'inspire_key_value.',
],
// For production environments, consider enabling a persistent cache driver
// such as Redis or Memcached in your .env file:
// CACHE_DRIVER=redis
// Monitor cache usage with: php artisan inspirecms:cache-stats
],
```
### Admin Panel
Configure the admin panel:
```php
use SolutionForest\InspireCms\Filament\Clusters as FilamentClusters;
use SolutionForest\InspireCms\Filament\Pages as FilamentPages;
use SolutionForest\InspireCms\Filament\Resources as FilamentResources;
'admin' => [
'enable_cluster_navigation' => true, // Group navigation items by function
// Set to false for a flat navigation structure
'navigation_position' => 'top', // left, top
'panel_id' => 'cms', // Internal identifier for the panel
// Must be unique if using multiple panels
'path' => 'cms', // URL path segment for admin area
// Example: https://yoursite.com/cms
'allow_registration' => false, // Whether to allow user registration via the admin panel
'brand' => [ // More info https://filamentphp.com/docs/3.x/panels/themes#adding-a-logo
'name' => 'InspireCMS', // Display name shown in admin header
'logo' => fn () => view('inspirecms::logo'), // Logo component (can be replaced with custom view)
'logo_title' => 'InspireCMS',
'logo_show_text' => true,
'favicon' => fb () => asset('images/favicon.png'), // Browser tab icon
],
'database_notification' => [
'enabled' => true, // Real-time admin notifications
// Disable for improved performance
'polling_interval' => '30s', // How often to check for new notifications
// Lower for more responsiveness, higher for reduced server load
],
'background_image' => 'https://random.danielpetrica.com/api/random?format=regular',
// Login page background
// Replace with your own image path for branding
// Resource classes define admin CRUD interfaces
// Replace with custom classes to modify behavior
'resources' => [
'content' => FilamentResources\ContentResource::class,
'document_type' => FilamentResources\DocumentTypeResource::class,
// ... other resources
],
// Admin panel pages (replace to customize specific pages)
'pages' => [
'dashboard' => FilamentPages\Dashboard::class,
'export' => FilamentPages\Export::class,
'health' => FilamentPages\Health::class,
],
// Navigation clusters (groupings of admin features)
'clusters' => [
'content' => FilamentClusters\Content::class,
'media' => FilamentClusters\Media::class,
'settings' => FilamentClusters\Settings::class,
'users' => FilamentClusters\Users::class,
],
// Extra widgets to display on the dashboard
// Add custom widgets to enhance the admin experience
'extra_widgets' => [
// Example: App\Filament\Widgets\LatestOrders::class,
// Example: App\Filament\Widgets\VisitorStatistics::class,
// Each widget will appear on the dashboard page
// Implement custom widgets by extending Filament\Widgets\Widget
],
],
```
### Data Import/Export
Manage data migration and content portability:
```php
'import_export' => [
'imports' => [
// Storage configuration for imports
'disk' => 'local', // Storage disk for finished imports
// Options: 'local', 'public', 's3', etc.
// Use 'local' for security as imports may contain sensitive data
'directory' => 'imports', // Directory within the disk where imports are stored
// Keep distinct from other file types for organization
'temporary' => [
'disk' => 'local', // Storage for in-progress imports before processing
// Should be fast, local storage for performance
'directory' => 'temp/imports', // Temporary location during processing
// Automatically cleaned after successful import
],
'allowed_mime_types' => [ // Limit file formats for security
'application/zip',
'application/octet-stream',
'application/x-zip-compressed',
'multipart/x-zip',
],
'max_file_size' => 10 * 1024, // 10MB limit
// Increase for larger datasets
],
'exports' => [
'directory' => storage_path('app/exports'), // Where export files are saved
'include_media' => false, // Set to true to include media files in exports
// Warning: Can create very large exports
'include_users' => false, // Set to true to export user accounts
// Consider security implications
],
],
```
### Models and Database
Configure entity models and database settings:
```php
use SolutionForest\InspireCms\Models;
use SolutionForest\InspireCms\Policies;
use SolutionForest\InspireCms\Support\Models as SupportModels;
'models' => [
'table_name_prefix' => 'cms_', // Prefix for database tables
// Change requires database migration update
'morph_map_prefix' => 'cms_', // Prefix for polymorphic relationships
// Model class mappings - replace with your own to extend functionality
// Example: 'user' => App\Models\User::class
'fqcn' => [
'content' => Models\Content::class,
'content_path' => Models\ContentPath::class,
// ... other models
],
/**
* Policy mappings control authorization
*/
'policies' => [
'content' => Policies\ContentStatusPolicy::class,
// Add custom policies here
],
/**
* Auto-cleanup settings for database tables that can grow large
*/
'prunable' => [
'content_version' => [
'interval' => 30, // Delete content versions older than 30 days
],
'import' => [
'interval' => 5, // Delete import records older than 5 days
],
'export' => [
'interval' => 5, // Delete export records older than 5 days
],
],
],
```
### Custom Fields
Define and manage custom fields for content types:
```php
'custom_fields' => [
// Register field configuration classes
// Add your own custom field types by creating a class that extends
// \SolutionForest\InspireCms\Fields\Configs\FieldConfig
'extra_config' => [
// Complex field types
\SolutionForest\InspireCms\Fields\Configs\Repeater::class, // Repeatable field groups
\SolutionForest\InspireCms\Fields\Configs\Tags::class, // Tag selection field
// Rich content editors
\SolutionForest\InspireCms\Fields\Configs\RichEditor::class, // WYSIWYG editor
\SolutionForest\InspireCms\Fields\Configs\MarkdownEditor::class, // Markdown support
// Relationship fields
\SolutionForest\InspireCms\Fields\Configs\ContentPicker::class, // Select related content
\SolutionForest\InspireCms\Fields\Configs\MediaPicker::class, // Select media items
],
],
```
### Permissions
Set up role-based access control:
```php
use SolutionForest\InspireCms\Filament\Widgets as FilamentWidgets;
'permissions' => [
/**
* Whether to skip access right permission checks on resources
*/
'skip_access_right_permission_on_resource' => false,
/**
* Define actions that require specific permissions
*/
'guard_actions' => [
],
/**
* Dashboard widgets requiring permissions to view
*/
'guard_widgets' => [
FilamentWidgets\CmsInfoWidget::class,
FilamentWidgets\TemplateInfo::class,
FilamentWidgets\UserActivity::class,
],
],
```
### Template Management
Configure themes and templates:
```php
'template' => [
'component_prefix' => 'inspirecms', // Prefix for Blade layout components
// Example usage: Year: {{ $year }} $user_fav_color Year: {{ $event_date?->format('Y') }} {{ $item->getPropertyData('description')?->getValue() }} {{ implode(' | ', $event_categories ?? []) }} {{ $post->getPropertyValue('blog', 'excerpt') }} {{ $subtitle }} Custom hero content here{{ $field_group_name_field_name }}
@endif
```
This checks if the field has a value before rendering content.
### Accessing Arrays
```blade
@propertyArray('field_group_name', 'field_name')
@foreach($field_group_name_field_name as $item)
Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Rule**: Validation rules for the field.
> - **Length**: The exact length of the input.
> - **Max Length**: The maximum allowed length of the input.
> - **Min Length**: The minimum required length of the input.
> Template Usage
> ```blade
> @property('hero', 'title')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Rows**: The number of visible rows in the text area.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> ```blade
> @property('intro', 'text')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> ```blade
> @property('contact', 'email')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> ```blade
> @property('user', 'password')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Rule**: Validation rules for the field.
> - **Min Value**: The minimum allowed value.
> - **Max Value**: The maximum allowed value.
> Template Usage
>
> ```blade
> @property('event', 'max_ppl')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> ```blade
> @property('contact', 'facebook')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Options**: The predefined choices available in the dropdown.
> - **Multiple**: Whether multiple selections are allowed.
> - **Default Value**: The initial value of the field.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> Multiple is false:
>
> ```blade
> @property('event', 'type')
> ```
>
> Multiple is true:
>
> ```blade
> @propertyArray('event', 'types')
> {{ implode(', ', $event_types ?? []) }}
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> Template Usage
>
> ```blade
> @if ($content?->getPropertyGroup('event')?->getPropertyData('active')?->getValue() ?? false)
> @endif
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Options**: The predefined choices available for selection.
> - **Default Value**: The initial value of the field.
> Template Usage
>
> ```blade
> @property('user', 'gender')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Disk**: The storage disk where files are saved.
> - **Directory**: The directory path within the disk.
> - **Visibility**: The visibility of the uploaded files.
> - **Multiple**: Whether multiple files can be uploaded.
> - **Rule**: Validation rules for the field.
> - **Accepted File Types**: The allowed file types for upload.
> - **Min File**: The minimum number of files required.
> - **Max File**: The maximum number of files allowed.
> - **Min Size**: The minimum file size allowed.
> - **Max Size**: The maximum file size allowed.
> Template Usage
>
> ```blade
> @propertyArray('event', 'docs')
> @foreach ($event_docs ?? [] as $doc)
> Doc
> @endforeach
> ```
>
> Or
>
> ```blade
> @propertyArray('event', 'docs')
> @foreach ($event_docs ?? [] as $doc)
> Doc
> @endforeach
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Disk**: The storage disk where images are saved.
> - **Directory**: The directory path within the disk.
> - **Visibility**: The visibility of the uploaded images.
> - **Multiple**: Whether multiple images can be uploaded.
> - **Rule**: Validation rules for the field.
> - **Accepted File Types**: The allowed file types for upload.
> - **Min File**: The minimum number of images required.
> - **Max File**: The maximum number of images allowed.
> - **Min Size**: The minimum image size allowed.
> - **Max Size**: The maximum image size allowed.
> Template Usage
>
> ```blade
> @propertyArray('event', 'images')
> @foreach ($event_images ?? [] as $img)
>
> @endforeach
> ```
>
> Or
>
> ```blade
> @propertyArray('event', 'images')
> @foreach ($event_images ?? [] as $img)
>
> @endforeach
> ```
>
>
Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> Template Usage
>
> ```blade
> @propertyNotEmpty('user', 'fav_color')
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Default Value**: The initial value of the field.
> - **Placeholder**: Text displayed inside the field when empty.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Has Time**: Whether the field includes time selection.
> - **Has Date**: Whether the field includes date selection.
> - **Rule**: Validation rules for the field.
> - **Format**: The format of the date/time value.
> Template Usage
>
> ```blade
> @propertyNotEmpty('event', 'date')
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Types**: The types of media files allowed.
> - **Min**: The minimum number of items required.
> - **Max**: The maximum number of items allowed.
> Template Usage
>
> ```blade
> @propertyArray('hero', 'image_slider')
> @foreach ($hero_image_slider ?? [] as $item)
>
> @endforeach
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Types**: The types of media files allowed.
> - **Min**: The minimum number of items required.
> - **Max**: The maximum number of items allowed.
> Template Usage
>
> ```blade
> @propertyArray('hero', 'image_slider')
> @foreach ($hero_image_slider ?? [] as $item)
>
> @endforeach
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **ColumnsLayout**: Controls how many columns the icons are displayed in the selection interface.
> Template Usage
>
> ```blade
> @propertyNotEmpty('section', 'icon')
> @svg($section_icon, ['class'=>'h-5 w-5'])
> @endif
> ```
>
> Configuration Options
>
> - **Fields**: The sub-fields included in the repeater.
> - **Collapsible**: Whether the repeater sections can be collapsed.
> - **Cloneable**: Whether the repeater sections can be cloned.
> - **ColumnsLayout**: Controls how many columns the repeater items are displayed in.
> Template Usage
>
> ```blade
> @propertyArray('document_content', 'sections')
> @foreach ($document_content_sections ?? [] as $item)
> {{ $item->getPropertyData('title')?->getValue() }}
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Prefix Label**: Text displayed before the field.
> - **Suffix Label**: Text displayed after the field.
> - **Prefix**: Text added before each tag.
> - **Suffix**: Text added after each tag.
> - **Separator**: The character used to separate tags.
> - **Suggestions**: Predefined suggestions for tags.
> - **Reorderable**: Whether tags can be reordered.
> - **Color**: The color of the tags.
> - **Rule**: Validation rules for the field.
> Template Usage
>
> ```blade
> @propertyArray('event', 'categories')
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Toolbar** Buttons: The buttons available in the editor toolbar.
> - **Disk**: The storage disk where files are saved.
> - **Directory**: The directory path within the disk.
> - **Visibility**: The visibility of the uploaded files.
> Template Usage
>
> ```blade
> @property('event', 'content')
> ```
>
> Configuration Options
>
> - **Translatable**: Whether the field supports multiple languages.
> - **Toolbar** Buttons: The buttons available in the editor toolbar.
> - **Disk**: The storage disk where files are saved.
> - **Directory**: The directory path within the disk.
> - **Visibility**: The visibility of the uploaded files.
> Template Usage
>
> ```blade
> @property('document', 'content')
> ```
>
>
\n",
],
]);
// Add CommonMark extensions
$converter->setExtensions([
new AttributesExtension(),
new TableExtension(),
]);
});
```
For more information, see:
- [Available extensions](https://commonmark.thephpleague.com/2.6/extensions/overview/)
- [Configuration options](https://commonmark.thephpleague.com/2.6/configuration/)
---
## Macros
The Field Type system supports macros, allowing you to extend functionality without creating full custom field types. This approach is useful for adding small enhancements or modifications to existing field types.
You can use the mixin method to add multiple macros at once:
```php
use SolutionForest\FilamentFieldGroup\FieldTypes\Configs\FieldTypeBaseConfig;
// Add multiple methods via a mixin class
FieldTypeBaseConfig::mixin(new \Your\Mixins\FieldMixin);
```
Or add individual macros using the macro method:
```php
use SolutionForest\FilamentFieldGroup\FieldTypes\Configs\FieldTypeBaseConfig;
// Add a single macro
FieldTypeBaseConfig::macro('addHelpText', function ($text) {
$this->helperText($text);
return $this;
});
```
---
## Best Practices
- Keep field groups organized by logical function (e.g., "Banner", "Content")
- Use clear, descriptive names for fields and field groups
- Add helper text to guide content editors
- Use appropriate validation rules to ensure data quality
- Leverage translatable fields for multilingual content
- Consider the frontend display when designing field structures
## Customize the Admin Panel
---
title: Customize the Admin Panel
slug: customize-the-admin-panel
path: docs/v1/customize-the-admin-panel
uri: /docs/v1/customize-the-admin-panel
heading: Customize the Admin Panel
brief: This guide explains how to customize and extend the admin panel to meet your specific needs, including creating custom resources, pages, widgets, and modifying the appearance to match your brand. Whether you need to add new functionality or tailor the existing features, InspireCMS offers multiple extension points for developers.
quick_links: []
---
## Overview
The InspireCMS admin panel is built on [Filament](https://filamentphp.com/), a powerful admin panel framework for Laravel applications. This integration allows you to:
- Create custom admin pages
- Add new resources for managing database models
- Organize related functionality into clusters
- Define custom dashboard widgets
- Extend existing admin functionality
- Customize the look and feel of the admin panel
---
## Prerequisites
Before you begin extending the admin panel, ensure you have:
1. A working InspireCMS installation
2. Basic knowledge of **Laravel** and **Filament** concepts
3. Appropriate permissions to access the admin area
---
## Creating a Custom Panel Provider
The recommended approach for customizing InspireCMS is to create your own CMS Panel Provider by extending the base `CmsPanelProvider`:
1. Generate a new provider:
```bash
php artisan make:filament-panel my-cms
```
2. Extend the base CMS Panel Provider:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
[
// Other providers...
// Comment out or remove the default CmsPanelProvider
// SolutionForest\InspireCms\CmsPanelProvider::class,
// Add your custom provider
App\Providers\Filament\MyCmsPanelProvider::class,
],
```
### Customizing the Panel Appearance
Here's how to customize various aspects of the panel:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
brandName('My Custom CMS')
->brandLogo(fn() => view('admin.logo'))
->favicon(asset('images/favicon.png'))
// Custom colors
->colors([
'primary' => [
50 => '238, 242, 255',
100 => '224, 231, 255',
200 => '199, 210, 254',
300 => '165, 180, 252',
400 => '129, 140, 248',
500 => '99, 102, 241',
600 => '79, 70, 229',
700 => '67, 56, 202',
800 => '55, 48, 163',
900 => '49, 46, 129',
950 => '30, 27, 75',
],
'danger' => '#ff0000',
'success' => '#10b981',
'warning' => '#f59e0b',
])
// Fonts
->font('Poppins')
->fontSize('md')
// Dark mode
->darkMode(true) // Enable dark mode
// Render hooks
->renderHook(
'panels::body.start',
fn () => view('custom-scripts')
);
}
}
```
### Customizing Navigation
You can customize the navigation structure:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
navigationGroups([
NavigationGroup::make()
->label('Content')
->icon('heroicon-o-document-text'),
NavigationGroup::make()
->label('Shop')
->icon('heroicon-o-shopping-bag'),
NavigationGroup::make()
->label('Settings')
->icon('heroicon-o-cog'),
])
->navigationItems([
NavigationItem::make('Analytics')
->url('https://analytics.google.com')
->icon('heroicon-o-chart-bar')
->group('Reports'),
]);
}
}
```
### Adding Widgets and Resources
Configure default widgets and resources:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
widgets([
StatsOverview::class,
])
->resources([
ProductResource::class,
])
->pages([
Settings::class,
]);
}
}
```
### Advanced Configuration Options
For more advanced customization:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
middleware([
App\Http\Middleware\CustomMiddleware::class,
])
->authMiddleware([
App\Http\Middleware\CustomAuthMiddleware::class,
])
// Plugin registration
->plugin(new App\Filament\Plugins\CustomPlugin())
// Custom assets
->assets([
// CSS assets
\Filament\Support\Assets\Css::make('custom-stylesheet', 'path/to/stylesheet.css'),
// JavaScript assets
\Filament\Support\Assets\Js::make('custom-script', 'path/to/script.js'),
])
// Authentication
->login()
->registration()
->passwordReset()
->emailVerification();
}
}
```
---
## Adding Custom Clusters
### Creating Custom Cluster
1. Generate a new cluster class:
You can create a Filament cluster for the CMS panel or any other panel:
```bash
# Create a cluster for the CMS panel (auto-registered)
php artisan make:filament-cluster YourClusterName --panel=cms
# Create a cluster for another panel (requires manual registration)
php artisan make:filament-cluster YourClusterName --panel=admin
```
2. Register your cluster:
If you created the cluster under the CMS panel (`--panel=cms`), it will be automatically registered. However, if you created the cluster under a different panel or want to customize the registration, you can register your custom cluster in two ways:
**Option 1: Using configuration**
```php{title="app/Providers/AppServiceProvider.php"}
clusters([
YourClusterName::class,
// Add more clusters here
]);
}
}
```
### Example Cluster Class
```php{title="app/Filament/Cms/Clusters/Shops.php"}
[!IMPORTANT]
> Always ensure your Cluster implements the `SolutionForest\InspireCms\Filament\Contracts\ClusterSection` interface.
### Associating Resources and Pages with Clusters
To associate a resource or page with a cluster, specify the cluster class in the resource or page definition:
For resources:
```php{title="app/Filament/Cms/Resources/ProductResource.php"}
resources([
YourModelResource::class,
// Add more resources here
]);
}
}
```
### Example Resource Class
```php{title="app/Filament/Cms/Resources/ProductResource.php"}
schema([
Forms\Components\TextInput::make('name')
->required()
->maxLength(255),
Forms\Components\TextInput::make('price')
->required()
->numeric()
->prefix('$'),
Forms\Components\Textarea::make('description')
->maxLength(65535),
Forms\Components\Toggle::make('is_active')
->required(),
]);
}
public static function table(Table $table): Table
{
return $table
->columns([
Tables\Columns\TextColumn::make('name'),
Tables\Columns\TextColumn::make('price')
->money('USD'),
Tables\Columns\BooleanColumn::make('is_active'),
Tables\Columns\TextColumn::make('created_at')
->dateTime(),
])
->filters([
Tables\Filters\Filter::make('active')
->query(fn (Builder $query): Builder => $query->where('is_active', true)),
])
->actions([
Tables\Actions\EditAction::make(),
Tables\Actions\DeleteAction::make(),
])
->bulkActions([
Tables\Actions\DeleteBulkAction::make(),
]);
}
public static function getPages(): array
{
return [
'index' => Pages\ListProducts::route('/'),
'create' => Pages\CreateProduct::route('/create'),
'edit' => Pages\EditProduct::route('/{record}/edit'),
];
}
}
```
---
## Custom Pages
You can add standalone pages to the admin panel that aren't tied to a specific resource.
### Creating a Custom Page
1. Generate a new page class:
You can create a Filament page for the CMS panel or any other panel:
```bash
# Create a page for the CMS panel (auto-registered)
php artisan make:filament-page YourPage --panel=cms
# Create a page for another panel (requires manual registration)
php artisan make:filament-page YourPage --panel=admin
```
2. Register your page:
If you created the page under the CMS panel (`--panel=cms`), it will be automatically registered. However, if you created the page under a different panel or want to customize the registration, you can register your custom pages in two ways:
**Option 1: Using configuration**
```php{title="app/Providers/AppServiceProvider.php"}
pages([
YourPage::class,
// Add more pages here
]);
}
}
```
### Example Page Class
```php{title="app/Filament/Cms/Pages/ShopSettings.php"}
form->fill([
'site_name' => config('app.name'),
'site_description' => config('app.description'),
'maintenance_mode' => config('app.maintenance'),
]);
}
public function form(Form $form): Form
{
return $form
->schema([
Forms\Components\Section::make('General Settings')
->schema([
Forms\Components\TextInput::make('site_name')
->required()
->maxLength(255),
Forms\Components\Textarea::make('site_description')
->maxLength(1000),
Forms\Components\Toggle::make('maintenance_mode'),
]),
]);
}
public function save(): void
{
$data = $this->form->getState();
// Save settings logic here
// For example, update .env file or settings table
Notification::make()
->title('Settings saved successfully')
->success()
->send();
}
}
```
---
## Custom Widgets
You can add widgets to the admin dashboard to display important information, statistics, or shortcuts.
### Creating a Custom Widget
1. Generate a new widget class:
You can create a Filament widget for the CMS panel or any other panel:
```bash
# Create a widget for the CMS panel (auto-registered to CMS dashboard)
php artisan make:filament-widget StatsOverview --panel=cms
# Create a widget for another panel (requires manual registration)
php artisan make:filament-widget StatsOverview --panel=admin
```
2. Register your widget:
If you created the widget under the CMS panel (`--panel=cms`), you can optionally register it to the CMS dashboard. However, if you created the widget under a different panel, you need to manually register it to that panel's dashboard.
**For CMS Panel widgets - Optional registration to CMS Dashboard:**
You can register CMS widgets to the CMS Dashboard in two ways:
**Option 1: Using service provider**
```php{title="app/Providers/AppServiceProvider.php"}
[
// ...
'extra_widgets' => [
// Extra widgets to be added to the CMS Dashboard
\App\Filament\Cms\Widgets\StatsOverview::class,
],
//..
],
```
### Widgets for Other Filament Panels
If you created a widget for a different panel (e.g., `--panel=admin`), you need to register it manually:
```php{title="app/Providers/Filament/MyCmsPanelProvider.php"}
widgets([
StatsOverview::class,
// Add more widgets here
]);
}
}
```
### Example Widget Class
```php
description('Increased by 20%')
->descriptionIcon('heroicon-s-trending-up')
->color('success'),
Card::make('Total Orders', Order::count())
->description('3% increase from last month')
->descriptionIcon('heroicon-s-trending-up')
->color('success'),
Card::make('Average Order Value', '$' . number_format(Order::avg('total') ?? 0, 2))
->description('1.5% decrease from last month')
->descriptionIcon('heroicon-s-trending-down')
->color('danger'),
];
}
}
```
---
## Further Resources
- [Filament Documentation](https://filamentphp.com/docs)
- [Laravel Documentation](https://laravel.com/docs)
With these tools and techniques, you can extend and customize the InspireCMS admin panel to suit your specific requirements while maintaining a consistent and user-friendly interface.
## Directory Structure
---
title: Directory Structure
slug: directory-structure
path: docs/v1/directory-structure
uri: /docs/v1/directory-structure
heading: Directory Structure
brief: Understanding the InspireCMS directory structure helps you efficiently develop and customize your application. This guide explains the key directories and files in an InspireCMS installation.
quick_links: []
---
## Overview
InspireCMS follows Laravel's standard directory structure, with additional directories and files specific to CMS functionality.
```plaintext
project/
├── app/
│ └── Filament
│ └── Cms/ # Custom CMS extensions
│ ├── Clusters/ # Custom admin panel clusters
│ ├── Pages/ # Custom admin panel pages
│ ├── Resources/ # Custom admin panel resources
│ └── Widgets/ # Custom admin panel widgets
├── config/
│ └── inspirecms.php # Main CMS configuration file
└── resources/
└── views/
├── components/
│ └── inspirecms/ # CMS components and templates
│ └── {theme}/ # Theme-specific components
└── inspirecms/ # Exported CMS templates
└── templates/
```
---
## Key Directories Explained
### App Extensions
- **`app/Filament/Cms/`**: Directory for all your custom CMS extensions
- **`Clusters/`**: Custom admin panel sections, each containing related resources
- **`Pages/`**: Custom admin dashboard pages
- **`Resources/`**: Custom Filament resources for CRUD operations
- **`Widgets/`**: Custom dashboard widgets
### Configuration
- **`config/inspirecms.php`**: The main configuration file for InspireCMS, containing settings for:
- Authentication and users
- Media management
- Custom models
- Database connections
- Frontend themes
- Caching
- Permission settings
### Resources
- **`resources/views/components/inspirecms/{theme}/`**: Theme-specific components
- `page.blade.php`: Default page layout template
- `layout.blade.php`: Base layout used by templates
- Various component templates (header, footer, navigation, etc.)
- **`resources/views/inspirecms/templates/`**: Exported templates from the CMS
---
## Custom Theme Structure
When creating a new theme, follow this structure:
```plaintext
resources/views/components/inspirecms/{theme-name}/
├── page.blade.php # Default page layout template
├── header.blade.php # Header component
├── footer.blade.php # Footer component
└── navigation.blade.php # Navigation component
```
---
## Adding Custom Extensions
### Creating a Custom Cluster
```bash
php artisan make:filament-cluster YourClusterName --panel=cms
```
### Creating a Custom Resource
```bash
php artisan make:filament-resource YourModel --panel=cms
```
### Creating a Custom Page
```bash
php artisan make:filament-page YourPage --panel=cms
```
## Document type
---
title: Document type
slug: document-type
path: docs/v1/document-type
uri: /docs/v1/document-type
heading: Document Type
brief: Document Types in InspireCMS define the structure and behavior of your content. They determine what fields are available, how content is organized, and how it's presented to visitors.
quick_links: []
---
## Overview
A document type is essentially a **blueprint** for content, similar to a class in object-oriented programming. It defines:
- What fields are available for content entry
- How content is organized in the admin panel
- What templates can be used for rendering
---
## Creating Document Types
To create a document type:
1. Navigate to Admin Panel > **Settings** > **Document Types**

2. Click **Create Document Type**
3. Configure the following settings:
### Basic Settings
- **Name**: Human-readable name (e.g., "Blog Post")
- **Slug**: Machine-readable identifier (e.g., "blog-post")
- **Icon**: Visual identifier in the admin panel
- **Category**: For organizing document types (e.g., "web", "data")
- **web**
Pages with built-in routing and SEO settings
(e.g., Blog Post, Landing Page)
- **data**
Reusable data entities without their own URL
(e.g., Company Email, Site Settings)
### Advanced Settings
- **Show as Table**: Whether to display content under this content (children) in a table view
- **Show at Root**: Whether content can be created at the root level
- **Allowed document types**: Document types that can be children of this type
---
## Custom Fields
Associate custom fields with your document type to define what data can be entered:
1. In the **Structure** section, click **New field** or **Attach**
2. Select from available field groups or create new ones

3. Arrange field groups in the desired order
For detailed information about creating and configuring custom fields, see the [Custom Fields documentation](./custom-field){.doc-link}.
---
## Templates
Define which templates are available for rendering your content:
1. In the **Templates** section, click **Add Template** or **Attach**
2. Create a new template or select an existing one


3. Set a default template for new content

For detailed information about creating frontend layouts and templates, see the [Frontend Layouts documentation](./fe-layouts){.doc-link}.
---
## Content Hierarchy
InspireCMS allows you to create parent-child relationships between content:
### Setting Child Types
Define which document types can be children of the current type:
1. In the **Allowed document types** field, select appropriate document types
2. This determines what content types can be created underneath this content
3. Leave empty to prevent child content from being created

---
## Using Document Types
Once document types are configured, content editors can use them to create structured content:
1. Navigate to the **Content** section in the admin panel
2. Click **Create Content** and select your document type

3. Fill in the fields defined by your field groups
4. Save and publish your content
---
## Best Practices
- Create document types that align with your content strategy
- Use clear, descriptive names for document types
- Group related fields for better organization
- Define parent-child relationships carefully to create logical content hierarchies
## Event Listeners
---
title: Event Listeners
slug: event-listeners
path: docs/v1/event-listeners
uri: /docs/v1/event-listeners
heading: Event Listeners
brief:
quick_links: []
---
## Available Events in InspireCMS
InspireCMS fires events for various system activities. Here are the key events organized by category:
### Content Events
```php
// Content version events
SolutionForest\InspireCms\Events\Content\CreatingContentVersion::class // Before a content version is created
SolutionForest\InspireCms\Events\Content\CreatedContentVersion::class // After a content version is created
SolutionForest\InspireCms\Events\Content\CreatingPublishContentVersion::class // Before publishing a content version
SolutionForest\InspireCms\Events\Content\CreatedPublishContentVersion::class // After publishing a content version
SolutionForest\InspireCms\Events\Content\DispatchContentVersion::class // When a content version is dispatched
// Content status events
SolutionForest\InspireCms\Events\Content\ChangeStatus::class // When content status is changed
// Sitemap events
SolutionForest\InspireCms\Events\Content\GenerateSitemap::class // When sitemap generation is requested
SolutionForest\InspireCms\Events\Content\SitemapGenerated::class // After sitemap has been generated
```
### Template Events
```php
// Template events
SolutionForest\InspireCms\Events\Template\UpdateContent::class // When template content is updated
SolutionForest\InspireCms\Events\Template\CreateTheme::class // When a new theme is created
SolutionForest\InspireCms\Events\Template\ChangeTheme::class // When the active theme is changed
```
### Licensing Events
```php
// Licensing events
SolutionForest\InspireCms\Events\Licensing\LicensesRefreshed::class // When licenses are refreshed
```
---
## Creating Event Listeners
### Step 1: Generate a Listener Class
You can create an event listener using Laravel's artisan command:
```bash
php artisan make:listener YourListener --event=\\SolutionForest\\InspireCms\\Events\\Content\\CreatedPublishContentVersion
```
This creates a new listener in the `app/Listeners` directory.
### Step 2: Implement the Listener Logic
Edit the generated file to implement your listener logic:
```php
content;
$version = $event->version;
$status = $event->status;
Log::info('New content version created:', [
'content_id' => $content->id,
'version_id' => $version->id,
'status' => $status ? $status->name : 'none',
'is_publishing' => $event->isPublishing,
]);
// Your custom logic here
// E.g., send notifications, update external systems, etc.
}
}
```
Adding the `ShouldQueue` interface makes your listener run asynchronously for better performance. The `InteractsWithQueue` trait provides methods like `release()` and `delete()` for queue management.
### Step 3: Register the Listener
Register your listener in the `EventServiceProvider` class:
```php
[
YourListener::class,
],
];
}
```
---
## Practical Examples of Event Listeners
### 1. Track Content Status Changes
```php
content;
$oldStatus = $event->oldStatus ? $event->oldStatus->name : null;
$newStatus = $event->status ? $event->status->name : null;
// Record status change in history table
ContentStatusHistory::create([
'content_id' => $content->id,
'content_type' => get_class($content),
'old_status' => $oldStatus,
'new_status' => $newStatus,
'changed_by' => auth()->id(),
'changed_at' => now(),
]);
}
}
```
### 2. Generate Sitemap After Content Changes
```php
content;
// Only trigger sitemap generation for certain content types
$relevantTypes = ['page', 'post', 'product'];
if (in_array($content->document_type, $relevantTypes)) {
// Dispatch the generate sitemap event
Event::dispatch(new GenerateSitemap(
get_class($content),
$content->getKey(),
'content_published'
));
}
}
}
```
### 3. Track User Activity
```php
user;
$request = request();
$agent = new Agent();
$agent->setUserAgent($request->userAgent());
UserActivity::create([
'user_id' => $user->id,
'activity_type' => 'login',
'ip_address' => $request->ip(),
'user_agent' => $request->userAgent(),
'browser' => $agent->browser(),
'browser_version' => $agent->version($agent->browser()),
'device' => $agent->device(),
'platform' => $agent->platform(),
'platform_version' => $agent->version($agent->platform()),
]);
// Update user's last login time
$user->last_login_at = now();
$user->last_login_ip = $request->ip();
$user->save();
}
}
```
## Export
---
title: Export
slug: export
path: docs/v1/export
uri: /docs/v1/export
heading: Export
brief: InspireCMS provides powerful export capabilities for migrating content, creating backups, and transferring data between systems. This guide explains how to use the export features effectively.
quick_links: []
---
## Overview
The export system in InspireCMS allows you to:
- Export content and configuration in various formats
- Select specific elements to include in exports
- Schedule automatic exports
- Create data backups
- Prepare content for migration to other systems
---
## Export Interface
Access the export interface through: **Settings** > **Export**

### Export Types
InspireCMS supports several export types:
1. **Full Site Export**: All content, settings, and configuration
2. **Document Type Export**: Document types with field groups and templates
3. **Field Group Export**: Field groups and their field definitions
4. **Template Export**: Templates and associated configuration
### Export Formats
Available export formats include:
- **JSON**: Complete structured data (default)
---
## Creating an Export
### Basic Export
To create a basic content export:
1. Go to **Settings** > **Export**
2. Click "**Export**" to create new export
3. Configure additional options based on export type
4. Click "**Export**" to submit request
5. Wait for the export to complete or execute command `php artisan inspirecms:export`
6. Download the export file
### Export Configuration Options
Depending on the export type, additional options may include:
- **Content Selection**: Which content items to include
- **Include Dependencies**: Whether to include related records
---
## Custom Exporters
InspireCMS allows you to create custom exporters:
```php
namespace App\Exports;
use SolutionForest\InspireCms\Exports\Exporters\BaseExporter;
use SolutionForest\InspireCms\Models\Contracts\Export;
class CustomExporter extends BaseExporter
{
public function export(Export $record): ?string
{
// Implement your custom export logic
$data = $this->collectData();
// Generate export file
$path = storage_path('app/exports/' . uniqid('export_') . '.json');
file_put_contents($path, json_encode($data, JSON_PRETTY_PRINT));
return $path;
}
protected function collectData(): array
{
// Logic to collect data for export
return [
// Your export data structure
];
}
}
```
Register your custom exporter:
```php {title="config/inspirecms.php"}
'import_export' => [
'exports' => [
'exporters' => [
\SolutionForest\InspireCms\Exports\Exporters\ContentExporter::class,
\SolutionForest\InspireCms\Exports\Exporters\DocumentTypeExporter::class,
// Add your custom exporter
\App\Exports\CustomExporter::class,
],
],
],
```
---
## Export File Storage
Configure where export files are stored:
```php {title="config/inspirecms.php"}
'models' => [
'prunable' => [
'export' => [
'interval' => 5, // Automatically delete files after 5 days
],
],
],
'import_export' => [
'exports' => [
'disk' => 'local', // or 's3', 'sftp', etc.
'directory' => 'exports',
],
],
```
For cloud storage:
```php {title="config/filesystems.php"}
'disks' => [
// Local disk
'local' => [
'driver' => 'local',
'root' => storage_path('app'),
'throw' => false,
],
// S3 for export storage
'export_s3' => [
'driver' => 's3',
'key' => env('EXPORT_AWS_ACCESS_KEY_ID'),
'secret' => env('EXPORT_AWS_SECRET_ACCESS_KEY'),
'region' => env('EXPORT_AWS_DEFAULT_REGION'),
'bucket' => env('EXPORT_AWS_BUCKET'),
'url' => env('EXPORT_AWS_URL'),
],
],
```
## Assets
---
title: Assets
slug: fe-assets
path: docs/v1/fe-assets
uri: /docs/v1/fe-assets
heading: Assets
brief: Learn how to work with assets in your frontend templates.
quick_links: []
---
---
title: Content
slug: fe-content
path: docs/v1/fe-content
uri: /docs/1.x/fe-content
heading: Assets
brief: Learn how to work with assets in your frontend templates.
---
## Overview
For detailed media configuration options, please refer to the [configuration documentation](./configuration#media-management){.doc-link}.
---
## Asset Helper
Use the `inspirecms_asset()` helper to work with media assets:
```php
// Get asset by ID
$asset = inspirecms_asset()->findByKeys('550e8400-e29b-41d4-a716-446655440000')?->first();
// Get multiple assets
$assets = inspirecms_asset()->findByKeys('550e8400-e29b-41d4-a716-446655440000', '7f1b96c0-d4f0-11ed-afa1-0242ac120002');
```
---
## Accessing Asset Properties
Access basic asset information:
```php
// Get asset properties
$url = $asset->getUrl(); // Full URL to the asset
$filename = $asset->getFilename(); // Original filename
$extension = $asset->getExtension(); // File extension
$size = $asset->getSize(); // File size in bytes
$mimeType = $asset->getMimeType(); // MIME type
// Get asset metadata
$title = $asset->title; // Title
$caption = $asset->caption; // Caption
$description = $asset->description; // Description
```
---
### Image Transformations
Create responsive image variants:
Predefined variants (from config `media.media_library.responsive_images`):
- **small**: width 400 px
- **medium**: width 600 px
```php
// Get default URL
$url = $asset->getUrl();
// Get predefined responsive variants
$smallUrl = $asset->getUrl('small');
$mediumUrl = $asset->getUrl('medium');
```
---
## Working with Assets in Templates
### Accessing Media from Properties
Use property directives to access media assets linked to content:
```blade
@property('hero', 'image')
@if($hero_image)
@endif
@propertyArray('gallery', 'images')
@if($image->caption)
```
## Content
---
title: Content
slug: fe-content
path: docs/v1/fe-content
uri: /docs/v1/fe-content
heading: Content
brief: Learn how to work with content in your frontend templates.
quick_links: []
---
## Content Helper
The `inspirecms_content()` helper provides access to content items throughout your frontend templates:
```php
// Get content by ID
$modelContent = inspirecms_content()->findByIds(ids: '550e8400-e29b-41d4-a716-446655440000', limit: 1)->first();
// Get content by slug
$modelContent = inspirecms_content()->findByRealPath(path: 'about-us', limit: 1)->first();
// Get multiple content items
$modelContents = inspirecms_content()->findByIds(['550e8400-e29b-41d4-a716-446655440000', '7f1b96c0-d4f0-11ed-afa1-0242ac120002']);
// Get published content under 'home'
$modelContents = inspirecms_content()->getUnderRealPath(path: 'home', isPublished: true);
// Get paginated published content under 'home'
$modelContents = inspirecms_content()->getPaginatedUnderRealPath(path: 'home', isPublished: true, page: 1, perPage: 10);
// Get content by document type
$modelContents = inspirecms_content()->getByDocumentType(documentType: 'blog-post', isPublished: true);
// Get paginated content by document type
$modelContents = inspirecms_content()->getPaginatedByDocumentType(documentType: 'blog-post', isPublished: true, page: 1, perPage: 10);
```
> [!note]
>
> These functions return Content model instances. To access content properties and use them in templates, convert the model to a DTO using the `toDto()` method:
>
> ```php
> $contentDto = $moedlContent->toDto($locale ?? app()->getLocale());
>
> $title = $contentDto->getTitle();
> ```
---
## Accessing ContentDTO Properties
### Basic Properties
Access core content attributes:
```php
$title = $contentDto->getTitle(); // Get content title
$slug = $contentDto->slug; // Get content slug
$url = $contentDto->getUrl(); // Get content URL
$locale = $contentDto->getLocale(); // Get content locale
$publishedAt = $contentDto->publishAt; // Publication date
```
### Custom Fields
Use property directives in Blade templates to access custom fields:
```php
// Single property
@property('hero', 'title')
// With custom variable name
@property('hero', 'images', 'custom_images')
@foreach($custom_images ?? [] as $image)
@endforeach
// Value is from $blogDTO, variable available as $blog_category
@property('blog', 'category', null, $blogDTO)
// Array properties
@propertyArray('gallery', 'images')
@foreach($gallery_images ?? [] as $image)
@endforeach
// Conditional display
@propertyNotEmpty('hero', 'button_text')
{{ $hero_button_text }}
@endif
```
You can also access properties programmatically:
```php
// Check if property exists
if ($contentDto->hasProperty('hero', 'title')) {
// Get property value
$title = $contentDto->getPropertyValue('hero', 'title');
// Get property value with fallback
$subtitle = $contentDto->getPropertyValue('hero', 'subtitle') ?? 'Default subtitle';
// Get multilingual property with specific locale
$frenchTitle = $contentDto->getPropertyValue('hero', 'title', 'fr');
}
// Check if property group exists
if ($content->hasPropertyGroup('hero')) {
// Get entire property group
$heroGroup = $contentDto->getPropertyGroup('hero');
}
```
---
## Content Relationships
Access related content and structure:
```php
// Get parent contentDTO
$parent = $contentDto->getParent();
// Get all child contentDTO
$children = $contentDto->getChildren();
// Get paginated child contentDTO (After v1.1.x)
$paginator = $contentDto->getPaginatedChildren(page: 1, perPage: 15, pageName: 'page2', isWebPage: true, isPublished: true, sorting: ['__latest_version_publish_dt' => 'desc'])
// Get ancestors in hierarchical order
$ancestors = $contentDto->getAncestors();
```
---
## Content Filtering and Sorting
Filter and sort content collections:
```php
// Get recent blog posts
$modelContents = inspirecms_content()->getUnderRealPath(
path: 'blogs',
isPublished: true,
sorting: ['__latest_version_publish_dt' => 'desc'],
limit: 5,
);
// Get paginated recent blog posts
$modelContents = inspirecms_content()->getPaginatedUnderRealPath(
path: 'blogs',
page: 1,
perPage: 10,
isPublished: true,
sorting: ['__latest_version_publish_dt' => 'desc'],
);
// Filter by custom fields
$dtoContents = inspirecms_content()->getByDocumentType(
documentType: 'blog_post',
limit: 50,
)
->toDto($locale ?? app()->getLocale())
->filter(function($post) {
return $post->getPropertyValue('blog', 'is_featured') === true;
});
```
---
## Working with Multiple Languages
Access content in different languages:
```php
// Get content in specific language
$frenchContentDto = $modelContent->toDto('fr');
// Loop through all available translations
foreach (inspirecms()->getAllAvailableLanguages() as $locale => $langDto) {
$translatedTitle = $contentDto->getTitle($locale);
// Do something with the translation
}
```
---
## Pagination
Paginate content collections:
```php
// In your controller
$paginatedContentDto = inspirecms_content()->getPaginatedByDocumentType(documentType: 'post-page', perPage: 10)->toDto();
// In your Blade template
@foreach ($paginatedContentDto as $post)
{{ $post->getTitle() }}
{{ $title ?? 'Welcome' }}
@if(isset($subtitle))
$analyticsCode = "";
$content = str_replace('', $analyticsCode . '', $content);
$response->setContent($content);
}
return $response;
}
}
```
### 3. Language Selection
Middleware to set the site language based on user preference:
```php
segments();
$locale = '';
if (count($segments) > 0 && in_array($segments[0], ['en', 'fr', 'de', 'es'])) {
$locale = $segments[0];
Session::put('locale', $locale);
}
// If no locale in URL, check session or cookie
if (empty($locale)) {
$locale = Session::get('locale', config('app.locale'));
}
// Set the application locale
App::setLocale($locale);
return $next($request);
}
}
```
### 4. Content Security Policy
Add security headers to protect against XSS and other attacks:
```php
headers->set('Content-Security-Policy', "default-src 'self'; script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com; img-src 'self' data:;");
$response->headers->set('X-Frame-Options', 'SAMEORIGIN');
$response->headers->set('X-XSS-Protection', '1; mode=block');
$response->headers->set('X-Content-Type-Options', 'nosniff');
$response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
return $response;
}
}
```
### 5. Cache Control
Middleware to manage cache headers:
```php
is('cms/*') && $request->isMethod('GET')) {
$response->headers->set('Cache-Control', 'public, max-age=3600'); // 1 hour
} else {
// Don't cache admin pages or non-GET requests
$response->headers->set('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0');
$response->headers->set('Pragma', 'no-cache');
$response->headers->set('Expires', 'Sat, 01 Jan 2000 00:00:00 GMT');
}
return $response;
}
}
```
## Requirements
---
title: Requirements
slug: requirements
path: docs/v1/requirements
uri: /docs/v1/requirements
heading: Requirements
brief: Before installing InspireCMS, ensure your environment meets the following requirements
quick_links: []
---
## Server Requirements
- PHP 8.3 or higher
- Laravel 11.x or higher
- MySQL 5.7+ or PostgreSQL 10+
- Composer 2.0+
- Node.js 18+ and npm (for asset compilation)
---
## PHP Extensions
The following PHP extensions must be enabled:
- Fileinfo
- JSON
- Mbstring
- PDO
- Exif
- GD
- FFMPEG
---
## Development Environment
We recommend using one of the following for local development:
- [Laravel Herd](https://herd.laravel.com)
- [Laravel Sail](https://laravel.com/docs/11.x/sail)
- [Laravel Valet](https://laravel.com/docs/11.x/valet)
- [XAMPP](https://www.apachefriends.org/)
- [WAMP](https://www.wampserver.com/en/)
- [MAMP](https://www.mamp.info/en/)
## Search Implementation
---
title: Search Implementation
slug: search-implementation
path: docs/v1/search-implementation
uri: /docs/v1/search-implementation
heading:
brief:
quick_links: null
---
# Search Implementation
InspireCMS provides flexible search capabilities to help users find content quickly and efficiently. This guide covers how to implement, customize, and optimize search functionality in your InspireCMS application.
## Overview
The search system in InspireCMS allows you to:
- Search across all content types
- Filter results by document type, status, and other criteria
- Implement full-text search
- Customize search relevance and ranking
- Create advanced search interfaces
## Basic Search Implementation
### Using the Built-in Search
InspireCMS includes a basic search function that can be used out of the box:
```php
// Simple search across all content
$results = inspirecms_content()->search('keyword');
// Search with specific document type
$results = inspirecms_content()
->documentType('blog_post')
->search('keyword');
// Search with pagination
$results = inspirecms_content()
->search('keyword')
->paginate(10);
```
### Search Controller Example
Here's a simple search controller implementation:
```php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class SearchController extends Controller
{
public function index(Request $request)
{
$query = $request->input('q');
$documentType = $request->input('type');
$page = $request->input('page', 1);
if (empty($query)) {
return view('search.index', [
'query' => '',
'results' => null,
]);
}
$searchBuilder = inspirecms_content()
->isPublished(true);
if ($documentType) {
$searchBuilder->documentType($documentType);
}
$results = $searchBuilder
->search($query)
->paginate(12);
return view('search.index', [
'query' => $query,
'results' => $results,
]);
}
}
```
### Search Template Example
Create a search results template:
```blade {title="resources/views/search/index.blade.php"}
{{ $results->total() }} results found for "{{ $query }}" {{ Str::limit(strip_tags($item->getPropertyValue('content', 'summary')), 150) }} No results found. Please try different keywords.Search Results
@if($query)
{{ $item->getTitle() }}
@if($item->getPropertyValue('content', 'summary'))
@if (isset($seo) && $seo instanceof \Illuminate\Contracts\Support\Htmlable) {{ $seo }} @endif