Grafite has archived this project and no longer supports or develops this code. We recommend using only as a source of ideas for your own code.
CMS - Add a CMS to any Laravel app to gain control of: pages, blogs, galleries, events, custom modules, images and more.
Grafite CMS is a full fledged CMS that can be added to any Laravel application. It provides you with full control of things like: pages, menus, links, widgets, blogs, events, faqs etc.
Grafite CMS comes with a module builder for all your custom CMS needs, as well as a module publishing tools. So if you decide to reuse some modules on future projects you can easily publish thier assets seamlessly. If you wish to make your Grafite CMS module into a PHP package, then you will need to have it publish its assets to the cms/modules
directory.
Simple setup uses Grafite Builder as the backbone of an app for you using Laravel, once the setup command has been run you will have a full CMS as an app. Complex setup is specifically for developers who want to add a CMS to their existing app.
- Matt Lantz (@mattylantz, mattlantz at gmail dot com)
- PHP 7.1.3+
- MySQL 5.7+
- OpenSSL
Laravel Version | Package Tag | Supported |
---|---|---|
5.8.x | 3.3.x | no |
5.7.x | 3.x.x | no |
5.6.x | 3.0.x | no |
5.5.x | 2.4.x | no |
5.4.x | 2.3.x | no |
Create a new Laravel application, and make a database somewhere and update the .env file.
- Run the following command:
composer require grafite/cms
- Then run the vendor publish:
php artisan vendor:publish --provider="Grafite\Cms\GrafiteCmsProvider"
!!! Tip "If you wish to use the publish datetime picker - set your app's timezone config to correspond with your location"
!!! warning "The simple setup requires a fresh Laravel application."
If you're looking to do a simple website with a powerful CMS, and the only people logging on to the app are the CMS managers. Then you can run the setup command, it will install everything it needs, run its migrations and give you a login to start with. Take control of your website in seconds.
php artisan grafite:cms-setup
Now you're done setup. Login, and start building your amazing new website!
You can login as an admin with the following credentials:
U: admin@example.com
P: admin
!!! warning "Complex setup is needed for applications that have already have existing code including the login/logout set up."
If you just want to add Grafite CMS to your existing application and already have your own application running then follow the instructions below:
- Add the following to your routes provider:
require base_path('routes/cms.php');
- Add the following to your app.scss file, you will want to modify depending on your theme of choice.
@import "resources/themes/default/assets/sass/_theme.scss";
- Then migrate:
php artisan migrate
- Then add to the Kernel Route Middleware:
'cms' => \App\Http\Middleware\GrafiteCms::class,
'cms-api' => \App\Http\Middleware\GrafiteCmsApi::class,
'cms-language' => \App\Http\Middleware\GrafiteCmsLanguage::class,
'cms-analytics' => \Grafite\Cms\Middleware\GrafiteCmsAnalytics::class,
In order to have modules load as well please edit the autoload psr-4 portion to your composer file:
"autoload": {
...
"psr-4": {
"App\\": "app/",
...
"Cms\\": "cms/"
}
}
Route to the administration dashboard is "/cms/dashboard".
Grafite CMS requires Grafite Builder to run (only for the FormMaker), but Grafite CMS does not require you to use the Grafite Builder version of roles. But you will still need to ensure some degree of control for Grafite CMS's access. This is done in the Grafite CMS Middleware, using the gate and the Grafite CMS Policy. If you opt in to the roles system provided by Grafite Builder, then you can replace 'cms' with admin to handle the Grafite CMS authorization, if not, you will need to set your own security policy for access to Grafite CMS. To do this simply add the Grafite CMS policy to your app/Providers/AuthServiceProvider.php
file, and ensure that any rules you wish it to use are in within the policy method. We suggest a policy similar to below.
Possible CMS Access Policy:
Gate::define('cms', function ($user) {
return (bool) $user;
});
Gate::define('cms-api', function ($user) {
return true;
});
Or Using Grafite Builder:
Gate::define('cms', function ($user) {
return ($user->roles->first()->name === 'admin');
});
If you're looking for clean URL pages without having to have the URL preceed with page
or p
then you can
add this to your routes.
Make sure you put it at the bottom of the routes or it may conflict with others.
Route::get('{url}', function ($url) {
return app(App\Http\Controllers\Cms\PagesController::class)->show($url);
})->where('url', '([A-z\d-\/_.]+)?');
With the roles middleware you can specify which roles are applicable separating them with pipes: ['middleware' => ['roles:admin|moderator|member']]
.
The Grafite CMS middleware utilizes the roles to ensure that a user is an 'admin'. But you can elaborate on this substantially, you can create multiple roles, and then set their access in your app, using the roles middleware. But, what happens when you want to allow multiple roles to access the CMS but only allow Admins to access your custom modules? You can use permissions for this. Similar to the roles middleware you can set the permissions ['middleware' => ['permissions:admin|cms']]
. You can set custom permissions in config/permissions.php
. This means you can set different role permissions for parts of your CMS, giving you even more control.
Grafite CMS comes with a collection of handy API endpoints if you wish to use them. You can define your own policies for access and customize the middleware as you see fit.
The basic Grafite CMS API endpoints must carry the Grafite CMS apiToken
defined in the config for the app. This can be provided by adding the following to any request:
?token={your token}
** All published and public facing data will be available via the API by default.
/cms/api/blog
/cms/api/blog/{id}
/cms/api/events
/cms/api/events/{id}
/cms/api/faqs
/cms/api/faqs/{id}
/cms/api/files
/cms/api/files/{id}
/cms/api/images
/cms/api/images/{id}
/cms/api/pages
/cms/api/pages/{id}
/cms/api/widgets
/cms/api/widgets/{id}
Images are resized on upload for a better quality response time. They follow the guidelines specified in the config
under cms.max-image-size
.
Regarding S3 bucket usage. You will need to set the permissions accordingly to allow images to be saved to your buckets. Then you need to set your buckets to allow public viewing access. This is an example of such a policy.
{
"Version":"2008-10-17",
"Statement":[{
"Sid":"AllowPublicRead",
"Effect":"Allow",
"Principal": {
"AWS": "*"
},
"Action":["s3:GetObject"],
"Resource":["arn:aws:s3:::MY_BUCKET/public/images/*"]
}]
}
Replace MY_BUCKET
with your bucket name.
If using S3 you will need to add the following line to your filesystem config: 'visibility' => 'public',
The Grafite CMS package also provides the following packages:
- DevFactory/Minify
- Grafte/Builder
Grafite CMS has a rather elaborate config with many options available. You can expand the core modules, enable / disable features, and configure so much more.
Key | Description |
---|---|
analytics | Choose an analytics engine for the dashboard (internal or google) |
pixabay | Your pixabay API code |
db-prefix | Add a prefix to the Grafite CMS content tables |
live-preview | Preview your site in the editor view |
frontend-namespace | Sets the default namespace for the frontend code |
frontend-theme | The theme for the frontend |
load-modules | Do you want to load the external modules |
module-directory | Directory for custom Grafite CMS modules |
active-core-modules | Which core Grafite CMS modules are active |
rss | A set of attributes which can be set for the RSS feed |
site-mapped-modules | The module urls and their repositories that build the site map XML |
auto-translate | Automatically translate your content to other languages with Google Translate |
default-language | Your website's default language |
languages | Languages available in your website (enables their tabs in the editor) |
storage-location | Storage for files/ images (s3 or local) |
max-file-upload-size | The maximum file size for upload (Must also be set in php.ini) |
preview-image-size | When uploading images we cache clones at a smaller size (default: 800) |
cloudfront | Set a cloudfront URL to swap for the S3 bucket link |
backend-title | A title for the CMS (default: cms) |
backend-route-prefix | The route prefix for the backend of the CMS (default: cms) |
backend-theme | Theme for the backend (standard |
registration-available | Enable or disable registration |
pagination | Results per pack in backend |
api-key | Api Key for the Redactor photo and file injection |
api-token | Api Token for the Redactor photo and file injection, and the general external API calls |
forms | Forms config for core modules |
Grafite's CMS API is very simple, and it has a VERY simple auth system using a single token which can be defined with in your env. You can easily use this to manage integration with various platforms etc. The general base route for all API requests is:
/cms/api/{resource-url}?token={CMS_API_TOKEN}
URL | Resource |
---|---|
blog | Blog |
events | Events |
endorsements | Endorsements |
faqs | FAQs |
files | Files |
images | Images |
pages | Pages |
widgets | Widgets |
Each of these routes can be called or, you can also get a specific resource instance with the ID:
Example:
/cms/api/blog/1?token=9a78sd6f9as6df9
All too often we need translations in our sites and even our apps. Grafite CMS has got a very simple way of handling multiple languages. Translations is set up so that in the config if you add any languages to the languages
array you will be able to define custom entries for those languages.
auto-translate: false
In order to enable the auto-translate ensure that it is set to true in your config.
Simply add the translatable trait to your module's model and then update your modules to follow a similar pattern to the Grafite CMS pages structure see the following files for reference:
Grafite\Cms\Controllers\PagesController
Grafite\Cms\Repositories\PageRepository
Grafite\Cms\Models\Page
You will need to extend CmsModel
rather than the default Model. It will also need to use the Translatable
Trait.
use Grafite\Cms\Models\CmsModel;
use Grafite\Cms\Traits\Translatable;
class Books extends CmsModel
{
use Translatable;
}
You will also need to set bindings similar to this in your module event provider.
'eloquent.saved: Grafite\Cms\Models\Page' => [
'Grafite\Cms\Models\Page@afterSaved',
],
'eloquent.created: Grafite\Cms\Models\Page' => [
'Grafite\Cms\Models\Page@afterCreate',
],
'eloquent.deleting: Grafite\Cms\Models\Page' => [
'Grafite\Cms\Models\Page@beingDeleted',
],
These bindings ensure that when you save you create an archive of the previous entry, and on deleting of a item the system clears out any translations and archives it left behind. The created binding allows for the auto-translate so you can utilize the power of Google Translate.
Grafite CMS comes with a blade directive which generates links for your supported languages and provides a simple way to swap between the languages of a single page or blog entry while remaining on the same URL.
By default we support the use of cookies to handle languages and swapping them. Since each page/blog/event etc can have a specific url relative to its language with this current build there isn't much point to the prefixes for languages. But, that being said, sometimes its handy so here is an easy way to add support for it.
Just add this code to the map()
method in the RouteServiceProvider.php
:
$segments = request()->segments();
$supportedLanguages = array_keys(config('cms.languages'));
if (isset($segments[0]) && in_array($segments[0], $supportedLanguages)) {
$language = $segments[0];
unset($segments[0]);
return redirect(implode('/', $segments))->withCookie('language', encrypt($language))->send();
}
Much like the term implies promotions are like advertisements. They are intended to be treated like widgets, the main difference is that they have time scopes. This means you can put together promotional materials and content and set their publish date and time, as well as a finished at date and time to have the promotion disappear. This makes it very easy to schedule launches of campaigns etc.
@promotion('slug')
You can set these on any theme files. We recommend you leave them in the theme files and simply change the content and dates when you need to.
Grafite CMS has a full scope theming tool built right in. You can easily generate basic themes that can be built on and kept clear of your views. All the listed templates with a star are optional - otherwise everything else is required, for the basic support.
- assets
- js
- theme.js
- sass
- _basic.scss
- _theme.scss
- js
- blog
- all.blade.php
- featured-template.blade.php
- show.blade.php
- events
- all.blade.php
- date.blade.php
- calendar.blade.php
- featured-template.blade.php
- show.blade.php
- faqs
- all.blade.php
- gallery
- all.blade.php
- show.blade.php
- layout
- master.blade.php
- pages
- all.blade.php
- featured-template.blade.php
- home.blade.php
- show.blade.php
- partials
- navigation.blade.php
- public
- img
You have the ability to include other theme views into your view using the @theme('path')
directive with Blade. Otherwise its basically anything and everything Blade can do including any directives you wish to expand it with.
Grafite CMS has some custom directives added to Blade which allows you to include files from your theme easily, as well as other parts.
You can always add the cms-frontend::
namespace to the @include('path')
or instead use @theme('path')
.
Create unique and elegant designs with block directives in your templates for pages and blogs.
!!! Warning
With the block blade directive you do not specify the module it needs to load, it determines that from the first string in the request URL.
It will default to page if no matching module name matches the URL. In the case of something like events
, it expects the variable in the template
to be $event
. It is wrapped in the optional
method to protect the view from breaking the app.
Easily add menus to your views with the menu blade directive.
Generate links to modules automatically (Bootstrap 4 by default).
Add widgets to your views with the menu blade directive, just specify the SLUG.
Provides an image URL with an html tag and extra for adding a class
Provides an image URL
Images will be provided as an array, and if you skip the tag then the method will return all images, otherwise it follows the tagging.
There is also the Grafite CMS Service which can be run inside your blade views. Its as simple as {{ Cms::method() }}
Convert your markdown blog or page entries into HTML.
Generate links for each supported lanugage in your website
- menu('slug', 'optional-view-path')
- images('tag')
- widget('slug')
- editBtn('module', 'id')
There are some special features for pages which are not available for other parts of the site.
Pages are special and can often require complex designs. If your application needs some of the more abstract designs you can still use Grafite CMS for page management by using the block system.
{!! $page->block('main') !!}
or
{{ block('main') }}
By placing code like this in your template Grafite CMS will generate the main
block if it does not exist yet. If it does and has content it will render the content. It's really that simple.
php artisan theme:publish {name}
The Grafite CMS theme publisher will publish the public directory only. If you want to integrate assets you need to do so using your webpack
or gulp
file, pending on which setup you use.
Laravel Verison | Asset builder |
---|---|
5.4+ | webpack.mix.js |
5.3 | gulpfile.js |
- assets
- blog
- events
- faqs
- gallery
- layout
- pages
- partials
- public
- img
php artisan theme:link {name}
The Grafite CMS theme link tool will create a symlink between your public folder and a folder in your public directory called theme
.
This can make it easier to manage assets within a theme.
Laravel Verison | Asset builder |
---|---|
5.4+ | webpack.mix.js |
5.3 | gulpfile.js |
- assets
- blog
- events
- faqs
- gallery
- layout
- pages
- partials
- public ->
{app_directory}/public/theme
- img
Grafite CMS comes with a handful of modules for handling a basic application/website including: Images, Files, Blog, Pages, Faqs, etc.
Below you will find a full listing of the modules that come pre-packaged with Grafite CMS.
In order to create your own Modules and ensure that they are loaded you MUST add "Cms\\": "cms/"
to the PSR-4 group in your composer.json
file.
- Blog
- Pages
- Menus
- Widgets
- Faqs
- Images
- Files
- Events
You have the freedom to make any modules you want. You can use the artisan module:make
or the artisan module:crud
to generate them and then artisan module:publish
to publish their contents.
Grafite CMS modules have an Assets
directory which is intended to contain all your JS and SASS or CSS. In order to load the Assets in your Module, you can use the Cms
facade.
Grafite CMS comes with a Minify package so you can easily load your modules assets with calls like below. You don't have to set the content-type. But pending on what you're loading you may want to override what the Cms service determines is the content-type.
So if you want to load your css file in your Sample module's Assets you could do the following:
Assets/css/styles.css
is the file we're grabbing.
<link rel="stylesheet" type="text/css" href="{{ Cms::moduleAsset('sample', 'css/styles.css', 'text/css') }}">
Or we can load some JavaScript, and yes jQuery is already inside Grafite CMS.
Assets/js/module.js
is the file we're grabbing.
<script type="text/javascript" src="{{ Cms::moduleAsset('sample', 'js/module.js', 'application/javascript') }}"></script>
So now you've made a CMS module and it's serving your application well, but now you've decided that it would make more sense for it to be a composer package, that you can run inside any app for easier maintenance. This also gives you far more freedom to decide how you wish to integrate the module into your app.
module:composer {name} {namespace}
This will generate a composer file, as well set the namespace of your module to a new package namespace.
The configs are autoloaded and are added to the cms config.
config('cms.modules.sample') // would retrieve the sample modules internal config.php contents
If you want to access a config that is customizable for your module you can publish one:
php artisan vendor:publish
Grafite CMS can generate custom CRUD modules for your application giving it all the power you want as fast as possble. Simply run the command: php artisan module:crud
and discover the many hidden powers inside the Grafite CMS.
The CRUD generator will produce a module with basic unit tests started. You would then need to setup your migrations etc, and then publish the module to your app. Check out the publishing for more details.
You can use the Form Maker tool which is provided by Grafite Builder
You can utilize redactor (the WYSIWYG) in your CRUD by adding .redactor
to any textarea class.
Inside the redactor instance you can easily add images and files which you have uploaded to Grafite CMS. Its as easy as clicking them to have them added to the entry.
When you generate a module the system will also generate a front-end or theme component which is kept in the Publishes
directory. The is the portion of code that your visitors will see. You will need to publish this code using the php artisan module:publish {name}
command.
Provided you leave the module inside the cms/modules
directory. However, you can also make your module into a composer package.
Grafite CMS is always concerned with security of what you provide, the potential open doors in your website/ app. As such, the Files which are uploaded to the CMS are locked outside of the public access points.
What does this mean?
This means that when you're website is providing these to visitors they are actually getting them through an API access point. This is done to ensure that the files do not reveal thier location. This means that no webscrappers can crawl your directories and take off files they shouldn't be, including files that have yet to be released.
In the config you can set the storage location for your file uploads. This can be either S3 or local. To get S3 to work correctly you need to configure Laravel as you would with S3. Grafite CMS will take it from there. So simply add your details to the config and it should work. The CMS loads all the third-party packages you will need.
Grafite CMS has a powerful CRUD builder. But lets say you want to have a custom module that integrates with another service or doesn't involve a CRUD at all.
Then the php artisan module:make
command will be your best tool. It will create a minimum viable module with a very basic admin layer and client layer which you can customize as you see fit.
You can utilize redactor in your module by adding .redactor
to any textarea class.
Inside the redactor instance you can easily add images and files which you have uploaded to the CMS. Its as easy as clicking them to have them added to the entry.
When you generate a module the system will also generate a front-end or theme component which is kept in the Publishes
directory. The is the portion of code that your visitors will see. You will need to publish this code using the php artisan module:publish {name}
command.
All custom modules will need to have their Publishes
folder published in order to have their code added to you app. We've wrapped this into one simple command:
php artisan module:publish
Running this will place the files in the matching folders in your app. So if you want to have files put in migrations make sure your Publishes
folder has a migration file in a directory like this:
Publishes/database/migrations/migration_file.php
If you switch themes in Grafite CMS you will need to republish your module. The views are added directly into the themes.
Grafite CMS is open-sourced software licensed under the MIT license
Grafite has an OEM licence for the use of Redactor in the Grafite CMS package. You are fully welcome to use Grafite CMS package and incorporate it into any apps you build, you are permitted to offer those apps as SaaS or other products. However, you are not entitle to strip out parts of Redactor and resell them, please see this license for more information
Please add as many details as possible regarding submission of issues and feature requests
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.