October CMS 2.0 - Upgrade Guide

Release Note 13

The following is an instructional guide on how to upgrade your 1.x October CMS installation to the latest version 2.0

Even though this is a major upgrade to the October CMS platform, it mostly affects the configuration file structure and introduces a new editor system in the backend. Most, if not all, of your plugins and themes should still be fully compatible.

We will use an approach that keeps a backup of your old website files in case you need to rollback any changes. However, you should take a snapshot of your database for cases where this needs to be rolled back.

Before proceeding, make sure that you have a license key ready by visiting the Project Management page of the October CMS website.

Table of Contents

Backing Up The Database

Use this command to backup your MySQL database. For example, if the username is root and the database is called database_name. You will then be prompted to enter the password.

mysqldump -u root -p database_name > october_backup_20210317.sql

To restore the backup, you can use this command.

mysql -u root -p database_name < october_backup_20210317.sql

PHP 7.2.9 Required

The new minimum PHP version is now 7.2.9

Database Requirements

The new minimum supported version for MariaDB is 10.2 and MySQL is 5.7.7, however, older versions will still work. If you wish to continue to use lower versions, ensure the following is added to your database configuration under the key database.connections.mysql.

'varcharmax' => 191,

See the Laravel issue on why this is necessary.

Upgrading from 1.0 or 1.1 to 2.0

In summary we will do the following:

  1. Install October CMS 2.0 in a new directory
  2. Copy the config, storage, plugins and themes to the new directory
  3. Migrate the database and test the website
  4. Swap the old directory with the new directory

Convert to environment variables

October CMS now uses environment variables as standard for its configuration. If you do not have a .env file in your application directory, create one using the following command.

php artisan october:env

Install October CMS in new directory

We will need to prepare a new directory to place the updated version. For example, if your website is located in /var/www/mywebsite then we should place the new installation in /var/www/mywebsite-new by running these commands.

cd /var/www
composer create-project october/october mywebsite-new

To make the configuration process run smoothly, you can copy your old configuration to the new website. This step is optional.

cp mywebsite/.env mywebsite-new/

Copy or move storage

Depending on the size of your storage directory. You can either copy or move the storage directory to the new installation. To copy it across.

cp -R mywebsite/storage mywebsite-new/

If you decide to move it across, you will need to create the new resources folder first. When creating this folder, make sure it has read and write permissions for the web server.

cp -R mywebsite-new/storage/app/resources mywebsite/storage/app
cp mywebsite-new/storage/app/.gitignore mywebsite/storage/app

Then perform the move.

mv mywebsite-new/storage mywebsite-new/storage-old
mv mywebsite/storage mywebsite-new/

Delete the old storage directory.

rm -rf mywebsite-new/storage-old

Next clean up the framework cache files by deleting the following files.


Copy themes and plugins

Copy any desired themes from old website to new. In this example we are copying the mytheme theme directory. Repeat the command for any other themes you wish to move.

cp -R mywebsite/themes/mytheme mywebsite-new/themes/

If you have any non-vendor plugins that you have developed yourself, copy them across as well. This example will copy the entire sam author and plugins.

cp -R mywebsite/plugins/sam mywebsite-new/plugins/

Note: If your plugins use composer dependencies or are published to source control, skip this step and follow the instructions for private plugins below.

Perform installation

Change directory to the new website.

cd mywebsite-new

Proceed through the installation process steps by running the installation command.

php artisan october:install

Migrate the database with the migration command.

php artisan october:migrate

Test that October CMS is working properly by opening it in a browser.

php artisan serve

If the demo theme or your theme is displayed, then everything is good.

Sync project and private plugins (optional)

Now install your vendor plugins and themes by syncronising to your project.

php artisan project:sync

If you have developed your own plugins that use composer dependencies, called private plugins, first place them inside a directory anywhere outside of the project. For example, we could place them inside /home/sam/plugins.

Ensure that your private plugins include a composer.json file with these minimum specification. For example, we will use a plugin named Sam.Blog and it translates to a package name of sam/blog-plugin.

    "name": "sam/blog-plugin",
    "type": "october-plugin",
    "description": "A Great Blog Plugin",
    "require": {
        "composer/installers": "~1.0"

Use the plugin install command and direct to a local source. For example, a plugin named Sam.Blog is installed with the following.

php artisan plugin:install Sam.Blog --from=/home/sam/plugins/sam/blog

Alternatively, if your plugin is already published to a source control repository, you can reference this address instead.

php artisan plugin:install Sam.Blog --from=git@github.com:sam/blog-plugin.git

Repeat this process for each private plugin in your website. Then test that everything is working.

php artisan serve

Replace old with new

Finally, complete the website upgrade, replace the old website with the new website.

cd ..
mv mywebsite mywebsite-old
mv mywebsite-new mywebsite

If you are using a public folder in your application, don't forget to mirror to it.

cd mywebsite
php artisan october:mirror

Enjoy using the latest version of October CMS!


Configuration Changes

Previously all configuration was stored in the config/cms.php file. Configuration files have been changed so that each core module has its own configuration file. Please observe the following new configuration files.


The following configuration keys have been renamed or moved.

Old Value New Value
cms.backendSkin backend.skin
cms.backendUri backend.uri
cms.backendForceSecure backend.force_secure
cms.backendForceRemember backend.force_remember
cms.disablePlugins system.disable_plugins
cms.linkPolicy system.link_policy
cms.storage system.storage
cms.loadModules system.load_modules
cms.pluginsPath system.plugin_asset_url
cms.themesPath system.theme_asset_url
cms.enableCsrfProtection system.enable_csrf_protection
cms.convertLineEndings system.convert_line_endings
cms.defaultMask system.default_mask
cms.restrictBaseDir system.restrict_base_dir
cms.updateAuth system.update_gateway_auth
cms.activeTheme cms.active_theme
cms.enableRoutesCache cms.enable_route_cache
cms.urlCacheTtl cms.url_cache_ttl
cms.parsedPageCacheTTL cms.template_cache_ttl
cms.enableAssetCache cms.enable_asset_cache
cms.enableAssetMinify cms.enable_asset_minify
cms.enableAssetDeepHashing cms.enable_asset_deep_hashing
cms.databaseTemplates cms.database_templates
cms.enableSafeMode cms.safe_mode
cms.forceBytecodeInvalidation cms.force_bytecode_invalidation
cms.enableTwigStrictVariables cms.enable_twig_strict_variables
cms.enableBackendServiceWorkers backend.enable_service_workers
cms.twigNoCache cms.enable_twig_cache
cms.fileDefinitions.* system.file_definitions
cookie.unencryptedCookies system.unencrypt_cookies
brand.appName backend.brand.app_name
brand.tagline backend.brand.tagline
brand.secondaryColor backend.brand.secondary_color
brand.logoPath backend.brand.logo_path
cms.storage.media.ignore media.ignore_files
cms.storage.media.ignorePatterns media.ignore_patterns
cache.codeParserDataCacheKey cms.code_parser_cache_key
cache.disableRequestCache system.in_memory_cache (reversed)

Version Checking

A note about backwards compatbility, if you need to check the version of October CMS, you can look for the System class.

if (class_exists('System'))  {
    // Running October CMS 2.0
else {
    // Running October CMS 1.0

Project is No Longer Syncronised Automatically

Previously when performing a system update, the platform will check with the server for any new plugins or themes and install them. This forces the website to use all plugins and themes defined by the project. This functionality has changed to decouple this process and the plugins and themes are now defined by the composer.json file instead.

A new command has been introduced to install anything added to the project recently.

php artisan project:sync

This command will install all plugins and themes defined by the project and add them to your composer file.


Removed Middleware on Backend Controllers

Previously it was possible to register middleware on any secondary backend controller. This ability has been removed as it introduces significant complexity to the system. The following is no longer possible.

\MeAuthor\MyPlugins\Controllers\Posts::extend(function($controller) {

As an alternative, it is still possible to register middleware on the primary backend controller.

\Backend\Classes\BackendController::extend(function($controller) {

For other simpler alternatives, see the article on overriding responses in backend controllers.

Migrations No Longer Occur on Login

Previously the database would be migrated when a user successfully signed in to the backend. This functionality and associated config (cms.runMigrationsOnLogin) has been removed. Migrations are now performed as part of the standard update process.

Controller Methods Should Be Snake Case

Consistency with controller actions has been improved. Previously, when defining a controller action, a URL like /download-pdf would translate to an action method of downloadPdf. This logic has changed and segmented action names should use snake_case instead. For example, /download_pdf or /download-pdf will reference an action method of download_pdf.

jQuery Migrate Plugin Removed

The jQuery version in the backend area has been updated to v3 from v2 and the core accomodates all the necessary changes. As a result, the jQuery Migrate plugin is no longer included by default. We recommend following the Upgrade Guide for jQuery 3.0 to ensure your plugins remain compatible.


Database Behaviors are Deprecated

The following classes have been deprecated and will be no longer supplied by the system in a later update.

  • October\Rain\Database\Behaviors\Purgeable - link
  • October\Rain\Database\Behaviors\Sortable - link

If your plugins depend on these classes, we recommend taking a copy of these classes and including them locally in your plugin. This should give you greater control over the behavior and its functionality.

Note: The database traits of the same name still exist and should be used where possible.

Migrations No Longer Use Transactions by Default

As a result of PHP 8's implementation of the PDO library, when a commit action is called inside a transaction, an exception will be thrown. Previously when the code encountered a commit action, it would fail silently and commit the transaction, usually unknown to the developer.

As a result of this change, it is not longer possible to apply a general approach to database transactions and it is now up to the developer. We recommend wrapping migrations or seed scripts in a transaction, especially if they involve multiple changes.

Db::transaction(function() {
    // Place code in here

This approach is more explicit and gives more control over the database processes.

Removed Helper Paths

The uploads_path() and media_path() global functions have been removed. These functions were found to be unreliable for use as system methods since objects can be stored using external providers and won't always exist on disk.

If your code relies on these functions, you may use a replacement as following.

// media_path()
storage_path('app/'.config('system.storage.media.folder', 'media'));

// uploads_path()
storage_path('app/'.config('system.storage.uploads.folder', 'uploads'));

Unsafe eval reduced in AJAX Framework

The unsafe command eval() has been removed from the AJAX framework data attributes. Please check if your code is using these attributes and adapt the code accordingly.

  • data-request-before-update
  • data-request-success
  • data-request-error
  • data-request-complete

The primary argument available is this similar to the onclick JavaScript attribute. To create the $el argument, use $(this) instead. The data argument is also still available but we recommend passing to a function that uses the JavaScript API instead. This is because the feature will eventually be phased out.

Internal Caching Removed on Models

The internal cache used by Eloquent and Halcyon models has been removed to reduce the memory footprint of the application. As a result the following property has been removed from database models.

 * @var bool Indicates if duplicate queries from this model should be cached in memory.
public $duplicateCache = true;


Attachments and Deferred Records Only Support Integer Keys

This section is required for PostgreSQL databases and an optional patch for MySQL and other database engines. We recommend all platforms apply this patch as it has a signifant improvement to the platform performance.

The following tables now use integer keys:

Table Column
deferred_bindings slave_id
system_files attachment_id

Previously these tables allowed strings to be used as keys and this carried an 800% performance penalty that was noticably slow at scale. This approach was intended to support both UUID (string) and ID (integer) primary keys. The support for UUIDs has now been dropped and related tables should introduce integer keys in addition to their UUID counterparts.

A migration function has been introduced to safely switch to integer keys whilst retaining the string key values. We strongly recommend taking a database backup before running this command.

php artisan october:util patch 2.0

This will perform the following steps for both tables:

  1. Rename the string column to a str_column (eg: attachment_id becomes str_attachment_id) so the existing values are not lost
  2. Introduce the new integer column (attachment_id)
  3. Copy values from the string column to the integer column, where possible
  4. If a string is found that cannot cast to integer (i.e a UUID), a warning is displayed with a list of records that need to be attended to.

This optimization is not required for new installations.

comments powered by Disqus