# Introduction

The dream of AdaptCMS is a content management system that is like a sandbox. To be able to build any type of site you want and if you're a developer, to be able to create additional functionality easily.

We do this by implementing a modular system that allows us, as well as developers to quickly be able to build plugins, fields, and other types of content. Our upcoming new version continues the tradition of using Laravel and VueJS, but what really makes a difference this time around is using TailwindCSS for the UI and InertiaJS for quickly building web pages.

At the time of this writing, a beta version is in the works and will be complimented with the documentation listed here so any developer may use the CMS.


# Terminology

While using the admin interface, or exploring the code base, here is a simple dictionary of common terminology we use in either/both places.

#### Packages

So packages can be a few different things! In general it refers to a "package" in the base folder `packages`. Within that may contain our own packages, or plugins. Plugins themselves will also reside in here, as well as Fields. It's the central point for all of those, but with different configuration that will be mentioned below to differentiate.

#### Modules

For those coming from Laravel Nova, a "module" is similar to a "resource" in that software. If I had a restaurant, I would create a location module. So it can be seen as a category of content items, or a content type that is defined. Upon creation of a module, a `/app/Modules/{moduleName}.php` is created with the option to customize various aspects of behavior in the admin.

#### Fields

Fields are, at their base, "Field Types". By default, a "Text" field exists, as well as "Textarea". A field you may create, or download could be "Google Places" with a google places address lookup input, for example.

#### InertiaJS

InertiaJS is one of the most powerful tools we are using. With it enabled, developers can create a route, a HTTP controller with action, and then they create a `page.vue` file with data being received by the aforementioned controller action, as well as a lot of helpful stuff such as flash message support, redirect support, validation, and more :)


# Setup a Cloud Server

Coming soon...


# Web Hosts

User contributed notes on various web host that play well or don't play with with Statamic. Send your pull requests, no affiliate links!

### PHP Versions by Host

[http://phpversions.info/shared-hosting](http://phpversions.info/shared-hosting/)

## Supported Hosts

Any linux based server with a fairly up to date version of it's distro, and CLI access shold work fine. Below is a more fine list of web hosts that *should* work fine:

* AWS - [https://aws.amazon.com](https://aws.amazon.com/\\)
* Digital Ocean - [https://www.digitalocean.com](https://www.digitalocean.com/\\)
* A Small Orange - [http://asmallorange.com](http://asmallorange.com\\)
* ArcusTech - [http://arcustech.com](http://arcustech.com\\)
* Azure - [https://azure.microsoft.com](https://azure.microsoft.com/\\)
* Digital Pacific - [http://www.digitalpacific.com.au/hosting](http://www.digitalpacific.com.au/hosting/\\) - Sydney, Australia
* Google Cloud Platform - [https://cloud.google.com](https://cloud.google.com/\\)
* HostGator - [http://www.hostgator.com](http://www.hostgator.com/\\)
* Laravel Forge - [https://forge.laravel.com](https://forge.laravel.com/\\)
* Linode - [http://linode.com](http://linode.com\\)
* Media Temple (dv) - [http://mediatemple.net](http://mediatemple.net\\)
* Media Temple (grid) [http://mediatemple.net](http://mediatemple.net\\)
* Metanet - [http://www.metanet.ch](http://www.metanet.ch\\) - Switzerland
* OVH - [https://www.ovh.com/fr/index.xml](https://www.ovh.com/fr/index.xml\\)
* Panthur - [http://www.panthur.com.au](http://www.panthur.com.au/\\) - Sydney, Australia
* ServInt - [https://www.servint.net](https://www.servint.net/\\)
* Site5 - [http://www.site5.com](http://www.site5.com/\\)
* WebFaction - [https://www.webfaction.com](https://www.webfaction.com/\\)

## Hosts Not Supported

You should probably avoid these. It doesn't mean it's not possible, but will likely require support tickets to enabled PHP modules like \`mcrypt\`, \`mbstring\`, and so on, as well as CLI support.

* Go Daddy - [http://godaddy.com](http://godaddy.com\\) - doesn't meet server requirements
* NameCheap - [http://namecheap.com](http://namecheap.com\\)
* Rackspace Cloud - [http://www.rackspace.com/cloud](http://www.rackspace.com/cloud/\\) - issues with out-of-sync file timestamps and permissions
* 1and1.com - [http://1and1.com](http://1and1.com\\) - please [see here](https://github.com/statamic/hosts/issues/12) for more details.


# Requirements

Below you will find the requirements necessary to install and run this software. A majority of the requiredments are what [**Laravel**](https://laravel.com/docs/5.4#server-requirements) requires, with a few exceptions:

* PHP >= 7.2.0
* OpenSSL PHP Extension
* XML PHP Extension
* PDO PHP Extension
* Tokenizer PHP Extension
* Mbstring PHP Extension
* GD/ImageMagick PHP extension
* Mcrypt PHP Extesion
* ZIP PHP Extension
* MySQL Server/Client
* Apache, NGINX
* URL Rewriting enabled (mod\_rewrite, try\_files, etc)

#### Lerna

To manage `npm` dependencies across different packages, we use Lerna. Please install this as well, before installation:

```
yarn global add lerna

or

npm install --global lerna
```


# Installation

## Setup

After ensuring your web server meets the requirements, you will also need NPM/Yarn installed, as well as composer:

```
composer require adaptcms/cms
```

After composer is finished, enter the `adaptcms` directory and modify your `.env` file with your database credentials, mail, anything that you see that you can enter credentials, or to choose drivers.

Next, run npm/yarn and composer to install the dependencies:

```
yarn OR npm install
composer install
```

When running composer you will be asked for a username and password. Login to the [AdaptCMS website](https://www.adaptcms.com) and go to your dashboard. Once a license has been purchased you will see two lines listed per license. The first line is the username, the long random string below is the password.

![Example Dashboard at AdaptCMS.com](https://794952664-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LCoHzGIZNj7Zx4z2EvE%2F-MUJsLATB-BUFM5P0mnT%2F-MUJssDzILgHWOSG86z_%2FMovavi%20ScreenShot%20007%20-%20AdaptCMS%20-%20new.adaptcms.com.jpg?alt=media\&token=4c6a0ded-0d7f-4729-9bf8-74b914ab0284)

After composer is completed, copy the `.env.example` file to `.env`. Open up this new file and enter in your configuration, such as database info. Next, run this command to trigger the initial install, as well as setting up your first admin account:

```
php artisan cms:install
```

If you're looking for a new web host, by the way, we highly recommend [**DigitalOcean**](https://m.do.co/c/083895eaa907)!

![](https://794952664-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LCoHzGIZNj7Zx4z2EvE%2F-LCoI2QMiXezwKicl57Z%2F-LCoI31H-YUxTza6XrCS%2Frsz_do_logo_horizontal_blue-3db19536.png?generation=1526664548824813\&alt=media)

## Permissions

We know setting permissions sucks, but one day we sat down and found a good set that worked for us very well. In the root folder, there is a `laravel_permissions.sh` file that you can run. Please note before running this command to ensure your apache/nginx username matches `www-data` in the file, and to either create or edit the group name `dev` that is in the file. We've found having a properly set up user with group permissions to be a big key to getting everything working right.

If you are unsure of how to handle group management in the command line, we have a tutorial setup on this. Note in the example the group name being used is `dev`, but that name can be quickly replaced in the permissions bash file:

{% embed url="<https://charliepage.gitbook.io/book/tutorials/setup-ubuntu-server-2020#non-root-user-setup>" %}

If you choose not to run this bash file, keep in mind that read/write/execute permissions will be needed for the below folders:

* app/ (only for upgrading through the CMS)
* bootstrap/cache/
* config/ (only for upgrading through the CMS)
* database/migrations/
* packages/
* storage/

To upgrade through the CMS, the following files will also need to have read/write permissions:

* composer.json
* package.json
* VERSION


# Upgrading

With the CMS installed and when in the admin, you will see a button on the navigation that will show if an upgrade is available. Along with upgrading through the CMS, you have one other option when proceeding.

**Git Pull**

If you pulled down the repository manually, you can simply run a `git pull` which will update the necessary files in the new version of the CMS.

**CMS Upgrade**

Otherwise, if you did a `composer require` to pull in the CMS, continue on after clicking on upgrade to proceed with the update. If anything failed, there should be a rollback that occurs. Otherwise, you may need to manually look at any files that changed. We highly recommend setting up the CMS in a git repo under your control, especially since running `git status` can quickly help you find any issues that popped up.

After the upgrade is complete, run `yarn run prod` to ensure the latest UI has been built for the admin and public side.


# Auth

The Auth package is exactly how it sounds! It manages logging in, registration, roles, users, and permissions. In this section we'll be covering the specifics of how these work, and include helpful resources for developers so they can take advantage of internally built in helpers, as well as libraries used within this package.

#### Users

Here are the columns:

* name
* email
* timezone

Here are the core relations:

* roles
* permissions

The database table is created out of the box, as well as the first user being created upon installation. Details on roles and permissions can be seen below.

Login and registration are handled by the base Laravel configuration out of the box, but may be modified per the [Laravel Docs](https://laravel.com/docs/authentication). The UI views may be modified below:

* /packages/Adaptcms/Auth/ui/pages/login.vue
* /packages/Adaptcms/Auth/ui/pages/register.vue

#### Permissions

For permissions and roles, we use a package from Spatie that features full documentation:

{% embed url="<https://docs.spatie.be/laravel-permission/v3/introduction>" %}

Permissions are in use in every aspect you will see, from the admin to the public side. Menu links are checked, buttons such as create or delete, search, and all routes are protected by permissions. The base permission for being able to access the admin area at all is named `base.admin.access`. A user that does not belong to a role with that permission will not be able to enter the admin area, regardless of any other permissions attached.

Package specific permissions, which are synced upon `composer update`, can be seen in the core class for that Package. For example with the Pages module, the list of permissions that must always exist can be seen in this file:

`/packages/Adaptcms/Pages/Pages.php`

The method `syncPermissions` will contain this list. If you create a package yourself, such as a plugin, be sure to include this so that there is no issues with missing permissions. Any route name defined with a reference to `admin` will, by default, be attached to all roles that have the aforementioned attached permission `base.admin.access`. Roles without that permission will not have access by default to those permissions, but will for any routes that have no reference to `admin` in it's name. Of course, any of this can be overridden within the admin UI.

All permissions can be managed in the admin UI, but we recommend not changing any core permission names as to avoid issues that will occur. Same with deletion of core permissions. Roles can be easily attached, or detached within this UI as well.

Lastly, if you manually modify permissions, or the permissions seem to be out of date - run this command:

```
php artisan permission:cache-reset
```

#### Roles

Roles are used as sort of a middle-man grouping of permissions for users. Rather than directly assigning permissions to users, although you are free to do that within PHP code, roles are assigned permissions - then users are assigned roles.

By default, a User role, Admin role, and Super Admin role are supplied upon installation. Admin and Super Admin are exactly the same, but are separated for those who would like to alter assigned permissions so only one or two people may have super admin access, and others may have admin access - an example being a restaurant admin where some users would only need access to manage locations, but not to have access to sensitive areas such as permissions, roles, etc.


# Base

The base package is used as a repository of neutral functionality that may be used by many other packages.

#### Back-end Helpers

One of the most important functions at this time for Base is the various CLI commands that will be of great use for developers:

```
php artisan cms:command:make {vendor} {package} {commandName}
php artisan cms:migration:make {vendor} {package} {migrationName}
php artisan cms:model:make {vendor} {package} {modelName}
php artisan cms:controller:make {vendor} {package} {controllerName}
```

Another useful utility is the ability to get a full list of installed packages, with fields excluded:

```
use Adaptcms\Base\Models\Package;

Package::getList();
```

#### UI Helpers

On the UI side of things, base contains a large amount of components and helpers that are in use in every core package. We won't be listing out every single component, you can see them all at - `/packages/Adaptcms/Base/ui/components` - but here are some that may slip past the radar.

```
this.modules

Returns list of custom modules created. Looping through this array will return an
array of data for the module.
```

Modifying the admin dashboard can be done in this page: `/packages/Adaptcms/Base/ui/pages/admin/dashboard.vue`&#x20;

Admin Utility Mixin: `/packages/Adaptcms/Base/ui/mixins/AdminUtilityMixin.js`

Admin Form Mixin: `/packages/Adaptcms/Base/ui/mixins/AdminFormMixin.js`

### Package Fields

A large piece of functionality is package fields. Currently this links a field to a specific page, or a field to a specific module. The package field then serves as the director of storing custom data into a pages table, or in the case of modules, a particular modules table (such as a column "overall\_rating" on a games table), as an example.

It also serves to be usable by plugins of any sort. To implement this functionality into a plugin you are creating, or better understand this feature, we will document how to do so and what configuration is available with a lot of flexibility. For example, the relation to pages is one where there is only one pages table with all custom columns on that one table. Whereas with modules, there is a table for each module with it's respective package fields contained on it's own table, yet both itself and Pages use Package Fields.

**Add new trait usage**

To start off with, you need the trait to implement some methods automatically for you:

```
<?php

use Adaptcms\Base\Traits\IsPackageFieldOwner;

class MyClassName extends Model
{
  use IsPackageFieldOwner;
}
```

**Required columns**

* id
* name
* slug (this will be filled automatically when using the above trait)

**toSearchableArray()**

Per the [Laravel Scout docs](https://laravel.com/docs/scout), please create this method.

**getPrimaryFieldAttribute()**

A primary field should be defined in your model of choice for implementation. If you have a column in your table that is set in stone, such as "name" for the pages table, simply return a stdClass with the `column_name` object property value returning this column name.

**shouldCreateColumnMigration(PackageField $packageField) (optional method)**

**shouldRenameColumnMigration(PackageField $packageField) (optional method)**

**shouldDropColumnMigration** **method(PackageField $packageField) (optional method)**

If you want to use conditions to determine if the migration for creating a column for the package field should be made, then implement any (or all) of these methods. Named respectively for creation of a column, renaming a column (on update of a package field name), or dropping a column (upon deletion of a package field).

**getModelFileContents()**

**putModelFileContents(string $contents)**

These two methods are necessary for fields such as `FieldFile` and `FieldImage` which require traits to be inserted into the model file. An example with Pages would be pointing to the Page model file as a fallback, but we avoid this for the package by applying the required implements and use call described in the [Spatie Media Library docs, which you may do as well](https://docs.spatie.be/laravel-medialibrary/v8/basic-usage/preparing-your-model/). For modules, we use the `Storage` helper to return and put contents into the path `/app/Modules/{moduleName}.php`. Simple as that!

**fillCustomData(array $data)**

This method is used to set data from package fields before saving the record in the database. The best way to utilize this method is looking at the code for this within the `Modules` and `Pages` packages. Here are those model paths:

```
/packages/Adaptcms/Pages/Model/Page.php
/packages/Adaptcms/Modules/Model/Module.php
```

**syncSearch()**

Upon creating a package field, renaming, or dropping - the search index will need to be updated. Here is an example below, from the `Pages` package:

```
/**
* Sync Search
*
* @return void
*/
public function syncSearch()
{
  // run scout import
  $items = $this->all();

  $items->searchable();
}
```

**Admin Link Show**

A package that implements the package fields functionality should be searchable. To that end, a standard that is in use for all searchable packages is in place. Here again we show below how the `Pages` package implements this:

```
use URL;

/**
* @var array
*/
protected $appends = [
  'admin_link_show'
];

/**
* Get Admin Link Show Attribute
*
* @return string
*/
public function getAdminLinkShowAttribute()
{
  return URL::route('pages.admin.show', [
    'page' => $this->id
  ]);
}
```

**Global Warnings**

Packages may take advantage of a global warning system that stores messages in a session and will return them within the admin UI.

Use cases will vary, but one example is an API key not being entered in for a new field type that requires it. You'll want to alert any admins so they can easily fix this issue. To get started, below is an example of creating a warning - note, a URL is optional:

```
use Adaptcms\Base\Models\GlobalWarning;

GlobalWarning::storeWarning(
  'enter-a-unique-warning-key-here',
  'This is a test warning that should be taken very seriously!',
  route('route.name.here')
);
```

Once a user has taken the required action to fix this issue, you will want to remove the warning. Simply do the below:

```
GlobalWarning::deleteWarning('enter-your-unique-warning-key-here');
```

That's it! Messages will appear on every admin page until the session has expired/been flushed, or until the warning has been removed with the code above - otherwise if the user deletes the warning. One other utility you may require is to check if the warning is active for your package - here's how to do that below:

```
GlobalWarning::hasWarning('enter-your-unique-warning-key-here');
```


# Fields

Fields are a sort of "field type" grouping which is used for Modules and Pages. A basic example is a "Text" field which is a simple text input and is used as a module field upon creation of a module.

### CLI Commands

#### Create Field

To create a new "field" that can become a GitHub package later on, simply run this:

```
php artisan cms:field:create {vendor} {package}
```

Upon creation, you will find a new folder path under `/packages` following the vendor/package naming you entered. Creating a field in the admin ends in the same result. Within this folder, there are several key files.

#### Sync UI components

When creating a field, if you make any changes within the default components inside of `/packages/{vendor/Field{package}/ui/field/` - you must run a CLI sync command for your changes to take effect within your website. Simply run this below with yarn/npm running, or build afterward:

```
php artisan cms:fields:sync
```

### Field Class File

First, under `/packages/{vendor}/Field{package}/src/Field/Field{package}.php` is the primary method for API usage where you may adjust default settings. `$storeRules` and `$updateRules` are default validation rules that will be passed in when the field is used, such as with a module or page. An example would be an email field that would pass in an attribute to assure a proper email address:

```
public $storeRules = [
  'email'
];
```

If your validation needs to be dynamic, then you can instead hook into the `getStoreRules` and the `getUpdateRules` methods, here's the method:

```
getStoreRules(PackageField $packageField)
```

The other important methods include a `getValue()` and `setValue($value)` methods. This will be the default getter/setter for any package fields created. If a developer modifies the module file this field is attached to, a mutator would override the getValue/setValue methods.

The `migrationCommand` method contains a string value of the migration command that will be run upon creation of a package field. The example should be pretty self-explanatory. Just keep in mind to go by the Laravel documentation on column modifiers, ensure `->nullable()` is attached unless the field is built for a specific website, and keep the same syntax standard seen in the default.

Using the `shouldNotSetData` attribute and having it return true is mostly used for relationship fields. That way a `hasMany` doesn't try to save data to a column that does not exist.

`formatColumnName` controls the value saved to the database for a package field, as does `formatName`. It should be noted that the column name is set first.

The methods `afterStore` and `afterUpdate` are called after a package field is stored with this field type. You may use this to update configuration, sync custom database structure, or whatever else you would like.

When a model is saved and has a package field linked to your field type, `afterModelStore` and `afterModelUpdate` methods are called, respectively. The same basic idea is used as with the above-after methods. For a relationship field, for example, we hook into this method to manually save data for a `HasMany` relationship.

Another relationship-related method is `withLoadedRelationships`, although it can be used for other purposes. Primarily it is used to dynamically define relationships, [as first introduced in Laravel 7](https://laravel.com/docs/7.x/eloquent-relationships#dynamic-relationships). Another important usage is loading relationships that will be returned to the VueJS layer. This second piece can be of great use for those building fields with specific purposes - such as a field for a particular website to achieve specific results. That way your code is still abstracted from the core CMS code, but can still load in the data you need.

The `withFormMeta` is yet another helper method, this one allowing a field to pass in data within the create/edit actions. An example is that you need to pass in possible select-able values from the database to a select field.

For validation on any options stored in a package field `meta` column, you can create the method `createFieldRules()` which should return an array of Laravel-supported validation rules. An example can be found below for the `FieldPasswordConfirmation` field:

```
/**
* Create Field Rules
*
* @return array
*/
public function createFieldRules()
{
  return [
    'meta.passwordField' => 'required'
  ];
}
```

If you need the same validation on editing a package field, use `updateFieldRules()` like the below:

```
/**
* Update Field Rules
*
* @return array
*/
public function updateFieldRules()
{
  return [
    'meta.passwordField' => 'required'
  ];
}
```

#### UI Customization

There are three UI components that will be used to control how the field value is shown in the admin create/edit pages, index/show pages, and public side views.

**/packages/{vendor}/Field{package}/ui/field/AdminField.vue**

This field returns the HTML input which will be used for create/edit pages within a created package.

**/packages/{vendor}/Field{package}/ui/field/AdminOptions.vue**

When creating a module field, for example, you may save `meta` info for use within these other views, or within the field PHP class file. An example of this is with `FieldNumber` which allows customization of minimum value, maximum value, and increment/step value. We store these values in the database and can then use this when rendering the field with the above `AdminField.vue` component.

**/packages/{vendor}/Field{package}/ui/field/AdminShow\.vue**

Used for the index & show pages within the admin panel for a created package.

**/packages/{vendor}/Field{package}/ui/field/PublicShow\.vue**

This is used anywhere a package module entry, which is related to this field, returns its value. An example might be returning a google maps image for a google places address picker field.

**Field Configuration**

A field, or field type, may require custom configuration that the user needs to use - such as providing an API key. While this could be hard-coded in, we provide an easy built-in way to accomplish this.

For the field `FieldPlace`, we need to do just that, have the user provide a Google API Key for use with Google Places. Here is our implementation as an example below:

```
class FieldPlace extends FieldType
{
  /**
  * @var array
  */
  public $defaultSettings = [
    'options' => [
      'is_sortable'        => false,
      'is_searchable'      => false,
      'is_required_create' => false,
      'is_required_edit'   => false
    ],
    'action_rules' => [
      'index'  => false,
      'create' => true,
      'edit'   => true,
      'show'   => true,
      'search' => false
    ],
    'config' => [
      'google_api_key' => null
    ]
  ];
```

The relevant part is the `config` array key. Simply pass in key and default values (or null), then a settings page will be viewable within the fields admin section - you'll see a pink button with a cog icon where the user can then put in their configuration.

You will also see above an `options` array - this can also be configured to set defaults when a package field is created from your field type. Being a location lookup field, we don't want to require the field by default, nor allow it to be sortable or searchable (the former could work though).

The other array key is `action_rules` which enable, or disable showing the field on the relevant page. With the place field, we don't want it showing on the index page nor the search, but should be shown on the create, edit, and show pages when browsing a module.

**Settings Integration**

Currently when creating a site type, there is configuration where a developer may use custom field types for the user to interact with basic configuration of the site type - such as entering in a site name, or uploading a logo. Unlike other use cases, this data is stored within the settings for the site type. This requires a new method which you can implement below. Included in the example is how to get meta data, the column name, how to get the current value and how to set a new value:

```
/**
  * Save To Settings
  *
  * @param Model   $model
  * @param Request $request
  * @param array   $field
  * @param string  $settingsKey
  *
  * @return void
  */
  public function saveToSettings($model, Request $request, array $field, $settingsKey)
  {
    $columnName = $field['column_name'];
    $metaData   = $field['meta'];
    
    $currentValue = $model->settings()->get($settingsKey);
    
    // set new value
    $newValue = 'test123';
    
    $model->settings()->set($settingsKey, $newValue);
  }
```

If your field type has meta information that needs to be passed in to the view where it is being displayed on a settings page, there is a separate method from `withFormMeta` called `withSettingsFormMeta`. Below is an example from `FieldImage` which returns full image meta for use. The model is whichever settings is used for - so for site types, it would be the site type model and have media attached to it to retrieve.

```
/**
* With Settings Form Meta
*
* @param Request $request
* @param object  $model
* @param string  $columnName
*
* @return array
*/
public function withSettingsFormMeta(Request $request, $model, string $columnName)
{
  $meta = [];

  // set media info to view
  if (!empty($model)) {
    $meta = $model->getMedia($columnName);
  }

  return $meta;
}
```


# Modules

Modules are at the very core of this software. Think of them as manageable "content types". A restaurant website may want a "Location" module. A video game website may have a "Console" module, and a "Game" module. They can also be seen as sort of a "category" management too.

Managing these modules can be entirely done in the admin, as well as the ability to customize individual modules, and use the command line to manage modules too.

#### CLI Commands

You can create, update, and delete modules with the below commands:

```
php artisan cms:module:create {name}
php artisan cms:module:update {oldName} {newName}
php artisan cms:module:delete {name}
```

#### Admin

When creating a module, a module file will also be created within this path - `/app/Modules/{module}.php`. A module file is simply a base model file with some extra options.

The `indexQueryFilter()` method can be used to modify the query for the index page of a module within the admin. You receive request data, as well as the Eloquent query object, which you also will return. Any filtering here may be done.

We also have, commented out, several examples of code for getter/setter attributes of package fields. Keep in mind these overwrite any default getter/setter on a specific Field file.

One other helpful method is an example of query filtering for a relation field. An example with a video game website - you have a relationship where a "console" hasMany "game" models. However, you want to filter what consoles are shown when an admin goes to create a game. Utilizing the `fieldQueryFilterConsole()` method would allow you to customize this for the create/edit pages in the admin.

**Public**

While it is mostly up to the developer to build the public side of their website, we want to make it as easy as possible to do so, while not losing out on the ability for customization. Whenever a module is created, two Vue components are created under the `Site` package to be modified at will.

```
/packages/Adaptcms/Site/ui/pages/modules/{moduleNamePlural}/index.vue
/packages/Adaptcms/Site/ui/pages/modules/{moduleNamePlural}/show.vue
```

The routes for these two methods are as follows, including a route for search:

```
/post/{moduleNamePlural}
/post/{moduleNamePlural}/{itemSlug}
/search/post/{moduleNamePlural}?query={searchInput}
```

An example could be /post/games, or /post/games/halo-2.


# Pages

Pages are essentially static parts of your public website, such as a home page or an about page. By default, a page has a title, a URL and status. The URL defines where the user will be able to access the page relative to the website domain.

To help non-tech users better be able to manage the content that appears on pages without doing any coding themselves, fields may be attached to a page creating a `PackageField`. Utilizing this feature a developer, for example, could define hero fields, content sections using the `FieldRichText` field, basically enabling the user to go into the admin and modify the content in these fields. The developer would then modify the page template to display these values in the appropriate places.

To customize the Vue component for a page, you will find it in this path:

```
/packages/Adaptcms/Site/ui/pages/pages/{name}.vue
```

Please note also that you can customize the data that is passed to the view by modifying the `PagesController` which is also in the `Site` package.


# Plugins

Like Fields, Plugins reside in the root `/packages` folder. Unlike fields, plugins are like mini-apps within your site. UI vue components, routes, controllers, models, commands - anything that Laravel supports is usable within a plugin. They could be used to add a feature, or to add a layer to the CMS fit for the specific website in mind.

When creating, or editing a plugin, there is an option to "Publish". As long as a valid GitHub URL is entered, we will update that GitHub repo with the files that reside in the Plugin path.

Another feature is the ability to search for a plugin from the AdaptCMS.com Marketplace. You may view the plugin on the marketplace, or even choose to install it directly to your website.


# Site Types

Site types are a way to quickly set up your own category of website. The first site type we have is `SiteTypePizza`, which allows someone who either owns their own pizza restaurant or is making a website for a pizza company, to have their very own pizza website running in moments. Developers can then customize the public website, and otherwise, content management is already setup.

{% hint style="info" %}
**Note:** Instances of `SiteTypePizza` are simply an example. Whatever you name as your site type will take the place of that reference in the below docs.
{% endhint %}

### Activating a Site Type

Coming soon...

### Creating a Site Type

**CLI Command**

To generate a site type locally through the command line, we have a simple way to do this:

```
php artisan cms:siteType:create VendorName SiteTypeName
```

For the Pizza site type, the formatting was `Adaptcms SiteTypePizza` - however, if you do not include the prefix `SiteType`, it will be prepended automatically anyways.

**Base Config**

This first page on the site type activation screen is used to store general info for your site type. That may be the site name, a logo image, or other things that can be used in building a layout, for example:

```
src/SiteType/SiteTypePizza.php

/**
* Base Config
*
* @return array
*/
public $config = [
  [
    'name'               => 'Site Name',
    'field'               => 'FieldText',
    'is_required_create' => true,
    'is_required_edit'   => true
  ]
];
```

Provide a valid `{vendor}/{package}` namespace for a field, define a name for the field, can require the field value to be provided, and can pass in meta-information as seen in an example below:

```
src/SiteType/SiteTypePizza.php

/**
* Base Config
*
* @return array
*/
public $config = [
  [
    'name'     => 'Site Logo',
    'field'     => 'FieldImage',
    'meta'     => [
      'mode' => 'single'
    ]
  ]
];
```

`FieldImage` has an option to support either a single or multiple images above, so providing a `meta` key with key/value of `mode => single` would create the field so a single image can be uploaded to the provided module, or in this case, configuration for the site type.

**Custom Modules**

Using the Pizza example, we want a `Location` module so the owner can enter in their different store locations to show on the website:

```
src/SiteType/SiteTypePizza.php

/**
* Custom Modules
*
* @return array
*/
public $modules = [
  [
    'name'  => 'Location',
    'fields' => [
      [
        'name'               => 'Title',
        'field'               => 'FieldText',
        'is_required_create' => true,
        'is_required_edit'   => true
      ],
      [
        'name'               => 'Address',
        'field'               => 'FieldPlace',
        'is_required_create' => true,
        'is_required_edit'   => true
      ],
      [
        'name' => 'Notes',
        'field' => 'FieldTextarea'
      ]
    ]
  ]
];
```

So we want a module called `Location`, with a title field (ex. Downtown Atlanta), address (of the store), and notes (ex. store hours or parking info).

**Custom Pages**

The other piece is static pages. For our example pizza restaurant, we may want an `About Us` page to talk about the history and mission of the pizza chain, a contact page with information on how to get in contact, a catering page with information on how to get pizza catered to you, and so on.

For this example, we'll just show a simple `About Us` page:

```
src/SiteType/SiteTypePizza.php

/**
* Custom Pages
*
* @return array
*/
public $pages = [
  [
    'name'  => 'About Us',
    'url'   => '/about',
    'fields' => [
      [
        'name'               => 'Body',
        'field'               => 'FieldRichText',
        'is_required_create' => true,
        'is_required_edit'   => true
      ]
    ]
  ]
];
```

**UI - Overwrite Layout**

When creating a Site Type, you can choose to overwrite the public layout in the `src/SiteType/SiteTypePizza.php` file:

```
class SiteTypePizza
{
  /**
  * @var bool
  */
  public $overwriteLayout = true;
}
```

This value is set to `false` by default, but switching to true will copy the layout in your site type path `ui/layouts/layout.vue` to the `Site` package folder where the public layout resides.

Using the power of package fields, you can easily build PHP arrays that contain the configuration used when activating the site type.

**UI - Activate Site Type**

When activating a site type, there is a basic warning near the top of the page explaining that current data may be overwritten by continuing and below that is where you may choose to show whatever you choose. You may want to simply thank the user for using your site type, show a preview of what it will look like, or other notes.

Simply edit, to your heart's content, the file at `ui/ActivateSiteType.vue` within your Site Type's folder.


# Creating Your Own Package

### Creating the Package

#### Commands

```
php artisan cms:command:make {vendor} {package} {commandName}
php artisan cms:migration:make {vendor} {package} {migrationName}
php artisan cms:model:make {vendor} {package} {modelName}
php artisan cms:module:create {name}
php artisan cms:module:update {oldName} {newName}
php artisan cms:module:delete {name}
```

#### Package Configuration File

```
/packages/{vendorName}/{packageName}/src/{packageName}.php
```

You will find your package file within the above path. Below are different configuration options.

**syncPermissions()**

Here is an example from the Notifications package. We recommend sticking to the prefix **{packageName}.admin.{controllerName}.{actionName}** syntax to be consistent. The name of your permission must also match the route name it corresponds to.

```
<?php

namespace Adaptcms\Notifications;

use Adaptcms\Auth\Models\Permission;

class Notifications
{
  /**
  * Sync Permissions
  *
  * @return void
  */
  public function syncPermissions()
  {
    $permissions = [
      // admin
      'notifications.admin.settings.edit',
  
      // frontend
      'notifications.front.settings.edit'
    ];
  
    Permission::syncPackagePermissions($permissions);
  }
```

**registerAdminSettingsPage()**

Another example is from the Notifications package. Simply pass the vendor name, package name, and permission/route name.

```
<?php

namespace Adaptcms\Notifications;

use Adaptcms\Base\Models\Setting;

class Notifications
{
  /**
  * Register Admin Settings Page
  *
  * @return void
  */
  public function registerAdminSettingsPage()
  {
    Setting::registerAdminSettingsPage('Adaptcms', 'Notifications', 'notifications.admin.settings.edit');
  }
```

**registerFrontSettingsPage()**

```
<?php

namespace Adaptcms\Notifications;

use Adaptcms\Base\Models\Setting;

class Notifications
{
  /**
  * Register Front Settings Page
  *
  * @return void
  */
  public function registerFrontSettingsPage()
  {
    Setting::registerFrontSettingsPage('Adaptcms', 'Notifications', 'notifications.front.settings.edit');
  }
```

**onInstall()**

This method is required to at least register the package with the CMS. You may put in whatever you want for code that is needed, such as calling an install command for your package, within the onInstall method.

```
<?php

namespace Adaptcms\Notifications;

use Adaptcms\Base\Models\Package;

class Notifications
{
  /**
  * On Install
  *
  * @return void
  */
  public function onInstall()
  {
    Package::syncPackageFolder(get_class());
  }
```

### Package Options

#### Vue Plugin File(s)

You may create a plugin or numerous plugins inside your package's UI folder. In the UI folder simply create a folder called `plugins` and any JS files in this folder will be autoloaded and globally usable. Please use Vue conventions to have this plugin able to be registered. Users may see an example in the Base package here:

```
/packages/Adaptcms/Base/ui/plugins/Base.js
```


# UI

### Override Core UI Views

With this feature, you could fully customize every single view rendered from the CMS. For more practical purposes, lets look at a realistic use-case of wanting to override the default login page with your own designed login page.

All it takes in this example is creating a file at `/packages/Adaptcms/Site/ui/pages/Adaptcms/Auth/login.vue`&#x20;

That path can be used with anything. In the example above the full path to the Auth login view is `/packages/Adaptcms/Auth/ui/pages/login.vue` - so as you can see we snip out the `ui/pages` part, essentially taking the vendor, the package name, and the path within the pages folder.

The only exception to overriding views are ones with a vendor/package explicitly set in the controller, although this method is strictly used at the moment to render `Site` views from a different package.


# Optimizing

### Compress JS/CSS

For production use, you may want to utilize gzip for your static CSS/JS assets. This is easy enough! Install `bread-compressor-cli` in a separate folder, such as a folder before your root path and use this package.json file:

```
{
  "name": "adaptcms",
  "scripts": {
    "dev": "npm run development",
    "local": "npm run dev",
    "prod": "npm run production",
    "compress": "bread-compressor -a gzip -s mysite/public/css/*.css mysite/public/js/*.js"
  },
  "private": true,
  "dependencies": {
    "bread-compressor-cli": "^1.1.0"
  }
}
```

Keep in mind, any time you run `npm/yarn run prod`, you will need to run the compressor since your browser should still be loading the gzip version of your asset files. Also, if you would like to build brotli files along with gzip, simply remove `-a gzip`.


# Contributing

Anyone can, and is welcome to, to contribute to AdaptCMS. You are free to go to our github page:

[**https://github.com/adaptcms/adaptcms**](https://github.com/adaptcms/adaptcms)

We have an issues page with bugs, features and just about anything else. Feel free to add new issues or feature ideas there, try and fix bugs you encounter or anything else you'd like. Make a pull request and we will review and respond as soon as possible.

To get the best cohesiveness we can, the easiest way is to get in contact with us, or more specifically, get involved in some part of the community.

AdaptCMS is an open source project and for the near future will not be a profitable organization. But our long-term plans are to have this project become a profitable business who has a paid staff. This year, we will be getting the necessary legal work done to make this an official business.

## Community

* [**Community Forums**](https://www.adaptcms.com/community)
* [**Slack**](https://www.adaptcms.com/slack)
* [**Discord**](https://discord.gg/2az3BzZ)

Along with GitHub, those are our communities currently where staff and the public alike can join and get involved. While it is by no means necessary, we can coordinate and discuss better so we don't have people fixing the same bug multiple times and have a direction in place.

## What can I do?

If you're not sure what you can do, please feel free to ask us at one of the above communities or any of these contact methods:

* [**Official Site**](https://www.adaptcms.com/pages/contact)
* [**Twitter**](https://twitter.com/adaptcms)
* [**Facebook**](https://www.facebook.com/AdaptCMS-104913829614704)

In general, here are the type of ways to contribute:

### PHP Developers

This is the biggest need right now. PHP developers who can help fix bugs, test and find other bugs, create core functionality, enhancements, work on plugins and more.

Ideally, if you are familiar with PHP frameworks and specifically, Laravel - we definitely could use your help!

While anyone can have whatever role they'd like, if you are familiar with Laravel, it would be of a great help to get involved and to be a part of some discussions and conversations of the direction and future of AdaptCMS.

To be a part of the first modern CMS to truly appeal to people from CMS newbies, to experienced veterans. Also the first CMS to not have it's focus on what engineers think people would like to have in a CMS, but to be a truly adaptable system that learns from it's users to improve.

### Front-end Developers

HTML work will be expansive and necessary. Styling by front-end, rather than PHP developers, would be a big step up. VueJS experience is very helpful, but not necessary.

Those with experience with mock-ups would also help, ideally we would like to have a thorough tested and discussed workflow of each part of the site at some point.

### Designers

While we predominantly use a front-end CSS framework to be the main design of the various looks of AdaptCMS, we would like to transition away from that somewhat. With coordinated design and front-end contributors, we have a great chance of blowing away the competition on launch.

### Miscellaneous

#### General Feedback

If you don't know anything at all about software like this, but are interested, you can get involved still! The more information we have, the more we understand different types of users - the better, and a more inclusive system we can build. Reach out to us any way you'd like and let us know what's confusing you, what you like about AdaptCMS, what you don't like about it.

Whether you're a PHP developers, or a small business owner trying to make a better site. We want to hear from you!

#### Writers / Editors

A big part of this project is going to be the code written, but also a lot of other things being written. Documentation, pages on the official site, language shown in the CMS itself, and more.

We need people that can either write these items (or revise things we've written) and also need editors to check writings for spelling, grammar, and assistance with simplifying, pointing out issues of coherence in documentation - so we can make the best available resources to the public.

Lastly, tutorials and guides will be written for launch of AdaptCMS.

#### Social Media

While not the top priority right now, we will be needing to do social media campaigns and keep an active social media overall.

To make in-roads with the community and also to assist with general requests.

#### Anything else?

Yes!

* General testing of the CMS and plugins/themes
* Local community outreach
* Advertising
* Server management
* Business manager / general advice

And more! Just reach out, let us know either what you'd like to do - that's most important. Or let us know what skills/experience you have and we can figure out, together, where you'd be able to get involved.

#### Hope to see you soon!

It's hard for an open-source project to have a small amount of contributors doing a whole lot. Everyone needs a job that brings in money, and open-source isn't usually the spot for that. It's for fun, to get experience, to help out. While we have long-term plans to turn this open-source CMS into a profitable company, to be able to have a paid staff, that's not right now.

When that does happen though, we will not be a greedy company. Paying for the necessities will come first - server costs, domain, staff, advertising and other business costs. Past that and the little extra's that come with it, that money will be used to grow the company and to help others in any way we can.

Thank you.

Charles Page

Founder of AdaptCMS


# Coding Guidelines

The two over-arching things to know about our coding philosophy:

1. We currently use the Laravel PHP framework
2. We try to use the latest stable technology we can

That said, there are some things we ask for people to watch out for and to try the best they can, to adhere to. Some are very basic things, and others are a personal preference.

## GitHub Workflow

We ask that you follow the traditional GitHub workflow. Pull down the repo and make changes to it based off of a current issue, or open a new issue and work on it. If we have people starting to do work on the CMS, without using the current structure, it will be very hard to keep things organized.

## Avoid the normal PHP annoyances

* Test out your code
* Name methods in a way that makes sense and isn't super long. Same with variables. No process() methods or $a variables.
* Don't over-abstract. If you're not sure, submit the pull request and we'll let you know.
* Use a standard editor so the code formatting isn't super different between everyone.
* Follow MVC standards as much as possible. If you need to dynamically query for data in a view file, and can't pass the data from the controller - create a service.

## Specific guidelines

* Be conscience of where your code goes. We try to keep the **Base** package for internal functionality and the rest goes to the appropriate module.
* Follow MVC standards as much as possible. With the power of InertiaJS, it has never been easier.
* Use Laravel code when needed. Please don't create a crazy custom super model class that isn't needed.
* When using filters/events, don't over-do it
* Talking about events, the reason is - speed. Along with testing out your code before you do a pull request, please ensure that the speed of your code isn't an issue.
* Use caching when appropriate
* For new features, think outside the box! If X CMS has a really useful feature - that's great. But try and think about how can it be better? More intuitive? User-friendly? What's not great about the implementation on X CMS?
* Working on this CMS is not a solo adventure. While you can have as much space as you want, for new features, please reach out so we can get a discussion going if it would be a feature for one of the core packages. If you're making a plugin, feel free to still reach out if you would like to brainstorm over it.


# PHP Developers

Welcome! If you're a PHP developer and wanting to get involved, we'll explain all that you need to do to get started. If you haven't reached out to the AdaptCMS team, we'd recommend that you follow this guide first and then reach out to us at any of the below sources:

* [**Community Forums**](https://www.adaptcms.com/community)
* [**Slack**](https://www.adaptcms.com/slack)
* [**Discord**](https://discord.gg/2az3BzZ)
* [**Twitter**](https://twitter.com/adaptcms)
* [**Facebook**](https://www.facebook.com/AdaptCMS-104913829614704)
* [**Email**](mail:charlie@adaptcms.com)
* [**Contact Form**](https://www.adaptcms.com/pages/contact)

##

If you don't already have an account on GitHub, please [**sign up here**](https://github.com/join?source=header-home). Once you sign up, or you already have an account there, head over to the AdaptCMS GitHub page:

[**https://github.com/adaptcms/AdaptCMS**](https://github.com/adaptcms/AdaptCMS)

Clone the site down to your local environment, make sure you're on the 4.0 branch and follow the [**installation**](/adaptcms/getting-started/installation) docs. Once the CMS is installed locally, you're ready for the next step.

## Take a look around

Spend a little time trying out the CMS and looking at the code. Get familiar with how the modules work, what the coding standards look like and see what you might want to work on.

## Slack

We use slack to talk about the CMS and generally as the best place to keep in contact. Go ahead and sign up here:

[**Slack**](https://www.adaptcms.com/slack)

After you sign up and login to Slack, check out there apps. They have one for the desktop (Windows, OSX and Linux!) and for Android/IO phone/tablet devices.

## Reach Out

At this point, go ahead and slack @charliepage that you'd like to help out and provide us with the following information:

* GitHub username
* If you want an email forwarder at the @adaptcms.com email domain, provide the desired username and what email it should go to
* Your name

Once we have that, we can add the email forwarder, if you want it. We can get you onto our project management software so you can start coding and we can get you added onto github as a contributor.

## Nostromo

We currently use a project management website called Nostromo. In the future we may move to somewhere else, but with it's custom workflow and easy to use software, it's home currently to project management of AdaptCMS.

In the above message to us via slack, you should of received an email invite to this site. Follow it and sign up with your @adaptcms.com email address or whichever one you'd like to use.

### Workflow

We follow a fairly particular workflow. In the "Plan" area, this is where we put ideas for the CMS and flesh them out to get them planned out and ready to work on. If you think of any feature ideas or have feedback for existing ideas, feel free to comment/add an idea card.

Once a plan is fleshed out and ready to be worked on, click on the 3 dots in the top right corner of the card and click on "Switch Board", which will move it over to the "Work" area and start it as a "TODO". When adding a card under "Plan", make sure to enter in a legible title, a description that describes the overview of the feature, tag it by version and "area" it effects (such as CMS, Plugin, Docs, etc.). If it's more than a one-step feature, add a checklist with the steps needed to accomplish this feature.

When a card is under "Work", we have this workflow:

* TODO
* Doing (actively working on feature)
* Ready for Review (add "Charlie Page" as a member of the card when it's ready for review)
* Reviewing (item is being actively reviewed)
* Done (feature has been worked on, reviewed and has been approved and pushed up)

To move a card from step-to-step, click on the 3 dots in the top right corner of the card and click on "Move". Then simply select the "Column" it should move to and click the big "Move" button and then you're done.


# Composer

So what is "Composer" to begin with? It's a PHP library that allows developers to easily include other PHP software in a project. With AdaptCMS, we use composer to pull in a framework and third-party libraries for many parts of the website. It auto-loads in these libraries and allows us to easily use those libraries quickly.

## How do I install it?

If your web server is running a newer version of Ubuntu, you should be able to install composer like this:

```
sudo apt-get install composer
```

If that doesn't do the trick, check out this guide:

[**https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-14-04**](https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-14-04)

## Now what?

Okay, so if you type in "composer" into your terminal for your web server, you should see something like this:

![](https://794952664-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LCoHzGIZNj7Zx4z2EvE%2F-LCoI2QMiXezwKicl57Z%2F-LCoI4643euxUhVKPLZL%2FScreen%20Shot%202017-08-22%20at%2012.13.02%20PM.png?generation=1526664549659047\&alt=media)

If not, it may not be installed, see the above guide. If it is installed, navigate to the root of your site folder and run this command:

```
composer update --lock
```

That should be it!


