PHPackages                             roland-solutions/vilt-cms - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. roland-solutions/vilt-cms

ActiveLibrary

roland-solutions/vilt-cms
=========================

A page builder CMS for Laravel projects using Vue, Inertia, Laravel, and Tailwind (VILT stack) — with Filament admin, media library, and navigation management.

v1.0.0(yesterday)113↑1053.8%MITPHPPHP ^8.3

Since Apr 5Pushed yesterdayCompare

[ Source](https://github.com/simon-roland/vilt-cms)[ Packagist](https://packagist.org/packages/roland-solutions/vilt-cms)[ Docs](https://github.com/simon-roland/vilt-cms)[ RSS](/packages/roland-solutions-vilt-cms/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (10)Versions (3)Used By (0)

VILT-CMS
========

[](#vilt-cms)

[![Latest Version on Packagist](https://camo.githubusercontent.com/21a3e61350d70744048675b8a1ee6a700992e11db554969e7aa06063553bff2c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f726f6c616e642d736f6c7574696f6e732f76696c742d636d732e737667)](https://packagist.org/packages/roland-solutions/vilt-cms)[![License: MIT](https://camo.githubusercontent.com/08cef40a9105b6526ca22088bc514fbfdbc9aac1ddbf8d4e6c750e3a88a44dca/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d4d49542d626c75652e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/c8d8dad6beb757a2b8acba331d16140813699543b88a37af0a81f20bd35f61de/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e332532422d626c7565)](https://www.php.net)[![Laravel](https://camo.githubusercontent.com/00fdc1cbd598ffba4c764b1584ca1600dbf559574bdd5d338909d39cb067fdee/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d31332d726564)](https://laravel.com)

A CMS package for the **VILT stack** — Vue · Inertia · Laravel · Tailwind. It provides the CMS infrastructure while each project supplies its own design, blocks, and layouts.

What's included
---------------

[](#whats-included)

- **Page builder** — pages with a layout slot + N content blocks, draft/published status, frontpage flag, and SEO meta
- **Media library** — uploads, folder organisation, grid/list browser, responsive WebP conversions, bulk operations
- **Navigation** — header and footer nav builder with links and dropdowns
- **Site settings** — singleton key/value store with a Filament admin page; fields auto-discovered from your app; shared on every Inertia request
- **User management** — admin user CRUD
- **Filament 5 admin** — all resources wired up and ready via `CmsPlugin`
- **Inertia middleware base** — shared props (title, ziggy, navigation) with overridable hooks
- **Vue plugin + components** — `createCms()`, `Wrapper`, `Head`, `Navigation`, `LinkItem`, `Blocks`, `Accordion`
- **Block / layout / field generators** — `cms:make-block`, `cms:make-layout`, and `cms:make-field`

Requirements
------------

[](#requirements)

DependencyVersionPHP^8.3Laravel^13.0Filament^5.0Inertia Laravel^3.0Vue3Tailwind CSS4Ziggy^2.3---

Installation
------------

[](#installation)

### 1. Require the package

[](#1-require-the-package)

```
composer require roland-solutions/vilt-cms
```

### 2. Run the installer

[](#2-run-the-installer)

```
php artisan cms:install
```

On a **fresh** Laravel project, the installer handles everything automatically:

- Publishes and runs migrations
- Publishes `config/cms.php` and `resources/views/app.blade.php`
- Creates `app/Http/Middleware/HandleInertiaRequests.php` and registers it
- Creates a Filament panel and registers `CmsPlugin`
- Adds `FilamentUser` to your `User` model
- Publishes `resources/js/app.ts` and `resources/css/app.css`
- Replaces `vite.config.js` with a Vue + Tailwind + `@cms` alias config
- Publishes starter blocks, layouts, and Vue components to your app
- Installs npm packages and builds assets
- Seeds an example page and navigation via `CmsShowcaseSeeder`
- Prompts you to create a Filament admin user

On an **existing** project, it prints manual steps for anything it cannot safely automate.

> **Security note:** The installer adds `canAccessPanel(): bool { return true; }` to your `User` model so you can reach the admin panel immediately. Before deploying to production, replace this with a real check (e.g. an `is_admin` column or a role).

---

Adding blocks
-------------

[](#adding-blocks)

Scaffold a new block:

```
php artisan cms:make-block Hero
```

This creates:

- `app/Cms/Blocks/HeroBlock.php` — Filament form schema
- `resources/js/cms/blocks/HeroBlock.vue` — Vue front-end component

Both files are **discovered automatically** — no registration needed. The PHP class is picked up by the CMS service provider at boot, and the Vue component is loaded via a glob import in `app.ts`.

Edit the generated files to define your block's fields and template.

---

Adding layouts
--------------

[](#adding-layouts)

```
php artisan cms:make-layout TwoColumn
```

Creates:

- `app/Cms/Layouts/TwoColumnLayout.php`
- `resources/js/cms/layouts/TwoColumnLayout.vue`

Same as blocks — both are discovered automatically.

---

Adding fields
-------------

[](#adding-fields)

Fields are **reusable PHP form components** — they wrap one or more Filament inputs into a single class so you can share the same field configuration across multiple blocks, layouts, or the site settings schema.

Scaffold a new field:

```
php artisan cms:make-field Actions
```

This creates a single PHP file:

- `app/Cms/Fields/ActionsField.php` — extends `BaseField`, returns any Filament `Component`

No Vue component is needed — fields are PHP-only.

### When to use a field

[](#when-to-use-a-field)

Use a field when the same configuration appears in more than one block. For example, an `ActionsField` that wraps a `Repeater` of labeled buttons with link targets can be reused in a Hero block, a Banner block, and a Card block without duplicating the schema.

### The starter `ActionsField`

[](#the-starter-actionsfield)

`cms:install` publishes `app/Cms/Fields/ActionsField.php` as a working example. It returns a `Repeater` where each item has a label and a link (internal page or external URL). It is immediately used in the `HeroBlock` starter.

### Using a field in a block

[](#using-a-field-in-a-block)

```
use App\Cms\Fields\ActionsField;

Block::make('hero')
    ->schema([
        ID::make(),
        TextInput::make('headline')->label('Headline'),
        ActionsField::make(),
    ]);
```

Pass an options array to override the field name or label:

```
ActionsField::make(['name' => 'cta', 'label' => 'Call to actions'])
```

### Returning a non-Field component

[](#returning-a-non-field-component)

Because `BaseField::setup()` returns `Filament\Forms\Components\Component`, your field can return anything — a `Repeater`, `Group`, `Fieldset`, or a plain `Field`. The generated stub starts with a `TextInput` as a simple baseline.

---

Updating frontend files after a package upgrade
-----------------------------------------------

[](#updating-frontend-files-after-a-package-upgrade)

Use `cms:publish` to selectively re-publish stub files:

```
# Publish everything
php artisan cms:publish

# Publish only specific groups
php artisan cms:publish --only=vue --only=ts

# Overwrite without confirmation
php artisan cms:publish --force
```

Available groups:

GroupWhat it publishes`ts``resources/js/app.ts``vue`Vue components and pages`css``resources/css/app.css``config``config/cms.php``php`Starter PHP block, layout, and field classes`settings-schema``app/Cms/SiteSettingsSchema.php` (see below)---

Site settings
-------------

[](#site-settings)

The CMS ships with a **Settings** admin page for storing global values that should be available on every frontend page — things like a site logo, favicon, social media links, and a default Open Graph image.

Settings are saved in a single database row and shared automatically on every Inertia request as `$page.props.settings`.

### Default fields

[](#default-fields)

SectionFieldTypeGeneral`logo`MediaPickerGeneral`favicon`MediaPickerSocial Media`facebook_url`URL inputSocial Media`instagram_url`URL inputSocial Media`linkedin_url`URL inputSocial Media`x_url`URL inputSocial Media`youtube_url`URL inputSEO`og_image`MediaPicker### Customising settings fields

[](#customising-settings-fields)

Publish the schema stub to define your own fields (replaces the defaults entirely):

```
php artisan cms:publish --only=settings-schema
```

This creates `app/Cms/SiteSettingsSchema.php`:

```
class SiteSettingsSchema
{
    public static function fields(): array
    {
        return [
            \RolandSolutions\ViltCms\Filament\Fields\MediaPicker::make('logo')->label('Logo'),
            \Filament\Forms\Components\TextInput::make('phone')->label('Phone'),
            // ... any Filament field or schema component
        ];
    }
}
```

The file is auto-discovered at boot — no registration needed.

### Using settings in Vue

[](#using-settings-in-vue)

```
import { usePage } from "@inertiajs/vue3";

const { settings } = usePage().props;

// settings.logo_media?.[0]?.src  — resolved media URL
// settings.facebook_url          — plain string
```

Media fields (any field whose value is a UUID from the media library) are resolved server-side. A field `logo` stored as a UUID gets an additional `logo_media` key containing the full media object array — the same shape as block media fields.

The `SiteSettings` TypeScript interface is exported from the CMS types and already applied to `PageProps.settings`.

---

Configuration
-------------

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --tag=cms-config
```

**`config/cms.php`**

```
return [
    // Eloquent model used for authentication and the admin user resource.
    // Must implement \Filament\Models\Contracts\FilamentUser.
    'user_model' => env('CMS_USER_MODEL', \App\Models\User::class),

    // Filesystem disk for uploaded media. Defaults to "public".
    'media_disk' => env('CMS_MEDIA_DISK', 'public'),

    // Options shown in the Button block's style selector.
    // [ value => label ]
    'buttons' => [
        'primary'   => 'Primary',
        'secondary' => 'Secondary',
    ],

    // Vertical padding options shown in the Video block's spacing selector.
    // [ value => label ]
    'padding' => [
        'sm' => 'Small',
        'md' => 'Medium',
        'lg' => 'Large',
    ],
];
```

`buttons` and `padding` default to empty arrays — the corresponding selectors are hidden if the array is empty.

---

Translations
------------

[](#translations)

The package ships English labels by default. To use Danish or override any string:

```
php artisan vendor:publish --tag=cms-lang
```

Published to `lang/vendor/cms/`. Activate Danish with `APP_LOCALE=da` in your `.env`.

---

Customising shared Inertia props
--------------------------------

[](#customising-shared-inertia-props)

Override `extraProps()` in your `HandleInertiaRequests` middleware to add or override shared props:

```
protected function extraProps(Request $request): array
{
    return [
        'user' => $request->user()?->only('id', 'name'),
    ];
}
```

---

Customising navigation loading
------------------------------

[](#customising-navigation-loading)

Override `loadNavigation()` to change how (or whether) header/footer nav is loaded:

```
protected function loadNavigation(string $type): array
{
    if ($type === 'footer') {
        return []; // disable footer nav
    }

    return parent::loadNavigation($type);
}
```

---

Block resource resolution
-------------------------

[](#block-resource-resolution)

If a block field stores a PHP class name in a `_resource` key, the package will instantiate it on every page render and inject the result back into the block data. This is useful for blocks that need to load dynamic data (e.g. a list of products).

Any class used as a block resource **must implement `RolandSolutions\ViltCms\Contracts\BlockResource`**:

```
use RolandSolutions\ViltCms\Contracts\BlockResource;

class LatestPosts implements BlockResource
{
    public function __construct(array $data)
    {
        $this->posts = Post::latest()->take($data['count'] ?? 3)->get();
    }
}
```

---

License
-------

[](#license)

MIT — see [LICENSE](LICENSE).
© 2025–2026 [Roland Solutions](https://simonroland.dk)

###  Health Score

44

—

FairBetter than 91% of packages

Maintenance100

Actively maintained with recent releases

Popularity10

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity49

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

2

Last Release

1d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/ba51711e1058b6f098745ea8fa52507250647e41c39d00be5544cde4e89c946d?d=identicon)[simon-roland](/maintainers/simon-roland)

---

Top Contributors

[![simon-roland](https://avatars.githubusercontent.com/u/40601765?v=4)](https://github.com/simon-roland "simon-roland (15 commits)")

---

Tags

laravelcmstailwindinertiamedia libraryfilamentvuepage buildervilt

### Embed Badge

![Health badge](/badges/roland-solutions-vilt-cms/health.svg)

```
[![Health](https://phpackages.com/badges/roland-solutions-vilt-cms/health.svg)](https://phpackages.com/packages/roland-solutions-vilt-cms)
```

###  Alternatives

[titasgailius/laravel-moonlight

An elegant Laravel scaffolding for your next single-page application.

1446.6k](/packages/titasgailius-laravel-moonlight)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
