This package is not installable via Composer 1.x, please make sure you upgrade to Composer 2+. Read more about our Composer 1.x deprecation policy.

A CMS for Laravel


A white-label CMS for Laravel

Latest Stable Version Latest Unstable Version Codacy Badge SensioLabsInsight


Use Composer to install:

composer require clumsy/cms

In the config/app.php file, add this to the providers key:


Optionally, you can set the following aliases:

'Clumsy' => Wizclumsy\CMS\Facades\Clumsy::class,
'Overseer' => Wizclumsy\CMS\Facades\Overseer::class,
'Shortcode' => Wizclumsy\CMS\Facades\Shortcode::class,

Publish Clumsy configuration:

php artisan vendor:publish --provider="Wizclumsy\CMS\CMSServiceProvider" --tag=config

Run migrations to get the admin area's authentication tables and media management tables:

php artisan migrate

Finally, publish all Clumsy public assets:

php artisan clumsy:publish


Clumsy will create an admin area where its users can manage resources. Before you start adding resources and routes, it could be a good idea to make sure you have access to it. Ideally, if you have many users, you would create a seeder in which you would register them all at once. If you just want to get up and running for development, you can user the following:

php artisan clumsy:user

You will be prompted for email, name, password and optionally a user level.

With a user of your own you can proceed to the admin area. By default this will be (you can configure this by editing the authentication-prefix in the config). After successful authentication, if you haven't yet defined a route which resolves the URL, you will see a simple message that reads: [Admin home] Clumsy is correctly set up.

Adding routes to that authenticated admin area is easy: whatever route that uses the clumsy middleware will automatically be managed by Clumsy.

Creating new resources

A resource that will be managed inside the admin area is basically an Eloquent model with some standard methods and properties. Most of the funcionalities which make up Clumsy are achieved by those model methods plus a standardized controller and a type of class which we call Panels. Because the Clumsy admin area can be customized entirely, all those classes inhabit your local app's folders and not the package's. Luckily there's an easy way to just create all those objects at once:

php artisan clumsy:resource post

The resource name (post in this example) defines what the classes will be called. The above command will create the following:

  • App\Post.php model
  • App\Http\Controllers\PostsController.php controller
  • Panels\Post\Table.php panel
  • database\migrations\(...)_create_posts_table.php migration
  • database\seeds\PostsSeeder.php seeder
  • some boilerplate code inside the database\factories\ModelFactory.php class
  • resources\views\admin\post folder

(The above paths are based on default configuration. All object namespaces can be overridden so that the resource generator puts them in the correct place inside your local application.)

The command output will also give you the resourceful route. By now your routes\web.php might look like this:


Route::group(['prefix' => 'admin', 'middleware' => ['web', 'clumsy']], function () {
    Route::resource('post', 'PostsController');

Which means that, after running the newly created migration, you can go to and see the index for the post resource and from there create, update and delete entries.

Panels: customizing data and features

By default the admin panels have all features disabled. The index assumes you want to show all items, and that a title column exists and is all that can be viewed and edited. Of course this are just unassuming defaults and are meant to be easily extended or overridden. In order to achieve this, Clumsy relies on a object which we call a Panel, which can be thought of as an objectual representation of the view you want to render. The index of a resource is generated by an Index panel, the editing form is generated by an Edit panel and so on. Custom panels are located inside your app/Panels/{Resource} folder (unless overridden by config), where {Resource} is the actual studly case name of the resource you want to customize (e.g. app/Panels/Post).

Customizing views

Clumsy will prioritize your local application's views whenever they're available at your views/admin folder and fallback to its default templates. Clumsy's templates are small bits of code in Blade syntax, intentionally small so you can override them in a very granular manner.

Say you want to override the editing form of your post resource. Instead of overriding the entire page, you can just create a resources\views\admin\post\fields.blade.php and place your HTML inputs inside it. Clumsy will use them for the create and edit forms. If you want your create forms to be different from your edit forms, you can create a resources\views\admin\post\create\fields.blade.php which will be used only during creation.

Cascading view priority

Clumsy's ViewResolver will cascade through a series of folders and check for overriding view files before assuming they don't exist and use the defaults. As a general rule, the cascade includes a domain and an action. The domain is the slug of the resource, while the action relates to the current panel in view (index, edit, create, reorder). You can also have local templates which are common to many resources inside your admin area. So, for a given template while viewing the list of a resource named post, this is the order files it will run through to see if the main index view should be overridden:

  • admin/post/index/index.blade.php (action-specific + domain-specific override)
  • admin/post/index.blade.php (domain-specific override)
  • admin/templates/index.blade.php (template override)

If none of those files are found, Clumsy will make the same cascade (domain + action > domain > template) inside it's own templates folder.

For clarity's sake, say you want to add a button after the page title when editing a post resource. There's a template called after-title that's included especially for that purpose, and it could be located in any of these folders for Clumsy to use it instead of the default:

  • admin/post/edit/after-title.blade.php (overrides only when editing)
  • admin/post/after-title.blade.php (overrides all after-title templates when viewing post pages)
  • admin/templates/after-title.blade.php (overridesall after-title templates in all resources)

Domain-agnostic templates

An admin area can easily be built using Clumsy's controllers and views. But you could also choose to have your own controllers and views and not extend any of Clumsy, which is fine. For consistency's sake, though, it assumes the navbar will display even on those "stand-alone" pages which do not use Clumsy code, meaning the navbar is a domain-agnostic set of templates: if you want to customize it, place the overrides in the root of your views/admin folder. Here's a full list of domain-agnostic templates:

  • navbar-wrapper.blade.php
  • navbar-home-link.blade.php
  • navbar.blade.php
  • navbar-buttons.blade.php

Available templates

Here's an exhastive list of the templates which Clumsy uses and which can be overridden:

  • master
    • head
      • alert
      • alert-errors (instead of alert)
      • navbar-wrapper
        • navbar-home-link
        • navbar
        • navbar-buttons
    • breadcrumb
    • page-header
      • title-prepend
      • title-append
      • after-title
    • [...]
    • footer

Where [...] are the templates of a given panel currently in view, which extend the master template (unless otherwise noted):

  • index

    • inner-index
      • filter
      • table
        • table-tr
        • table-empty (instead of table-r, when no resources exist)
      • gallery (instead of table)
        • gallery-item
          • gallery-caption
      • filter-toggles
      • pagination
  • edit

    • edit-form
      • fields
      • bottom-buttons
    • delete-button
  • edit-nested (when editing resources with children; extends edit)

    • edit-nested-tablist
    • edit-nested-tab-content
  • create (extends edit)

  • reorder

    • inner-reorder
      • table-empty (when no resources exist)
    • bottom-buttons

Note that the templates also use Blade sections, so you can override certain templates without resorting to replacing each individual files, but rather by using Blade's native syntax. A combination of the two techniques should give developers an almost limitless array of possibilities to customize Clumsy's templates.

Overriding views natively in Laravel

Of course you can also override all Clumsy's views by resorting to Laravel's native vendor publishing. When placed inside your views/vendor folder, Clumsy's fallback templates will be loaded from there, having priority over the package's views. This is especially useful for views that don't get the cascading priority treatment, such as authentication templates.

In order to publish Clumsy views:

php artisan vendor:publish --provider="Wizclumsy\CMS\CMSServiceProvider" --tag=views


  • For Laravel 5.3 support, use version 0.28.*
  • For Laravel 5.2 support, use version 0.27.*
  • For Laravel 5.1 support, use version 0.24.*
  • For Laravel 4.1 or 4.2 support, use 0.22.*

Upgrading from 0.22

  • Users, groups and password reset database structure now follows Laravel's default
  • Form macros have been removed with the exception of Form::location and Form::delete
  • Parent / Child relations now need to be explicitly declared as methods and return Laravel Relation objects in order to work
  • Resource view folders are now singular
  • External resources:
    • Route::externalResource no longer exists; instead, an external option should be passed when registering an ordinary resource route, e.g. Route::resource('resource', 'Controller', ['external' => true]);
    • ExternalResource is no longer a controller to be extended, but a Trait, and must be used to achieve the same effect
    • Importable is now a model Trait and must be used in order to have importing
  • Resource names are now supposed to be slug-like and valid URL components -- no more underscores
  • AdminController property resource_plural has been removed
  • AdminControllers no longer receive arbitrary data in their methods
  • Switched most BaseModel properties to Panels
  • All properties are now camel-cased
  • Config setting default-columns has been removed
  • The alert system has changed; it is now expected to call withAlert method on the redirect response and pass an associative array where the key is the alert status and the value is the alert message
  • There are no more active booleans, but rather editableInline inputs (to be defined on index-type Panels); also, the booleans method in the models is now deprecated in favour of Laravel's attribute casting
  • Removed has_slug property in the BaseModel in favour of a Trait which acts as if the property has been set
  • "Inner view" terminology was changed to "Panel Type" throughout;