@dmi3yy dmi3yy released this Dec 23, 2018

MODX Evolution is dead! Long live Evolution CMS 2.0 using Laravel components

EVO 2.0

What is Evolution CMS 2.0?

Evolution CMS 2.0 is the latest release of the popular content management system. While it works like before, underneath it's a major overhaul of a CMS that began life in 2004. The code has been modernised using components from Laravel. Gone is the infamous DocumentParser class, a collection of disparate functions. In its place are structured components for cache, events, logging, file system, cofig, console, migrations, seeders, Blade templating, models Eloquent, Observers, ServiceProvider and more.

evo1 evo2

evo3 evo4

A bit of history

  • Developers Raymond Irving and Ryan Thrash unveiled the first release of MODX CMS in 2004.
  • After MODX Revolution was released in 2012, the original MODX CMS (now called MODX Evolution) received minimal updates from the MODX LLC development team. A group of keen users from the MODX community stepped up to continue development.
  • In March 2013, MODX Evolution 1.0.9 was released (, created exclusively by the community, under the leadership of Dmytro Lukianenko and Evgeny Borisov (who continue to work on Evo to this day). Releases were made under the auspices of MODX LCC (via
  • In April 2017, MODX LCC cut its involvement with MODX Evolution ( Since then, our team has chosen its own development course.
  • In July 2017, we made the first release of the newly-renamed Evolution CMS. Evolution CMS 1.3.0 had a completely redesigned interface and a number of new features that embodied the wishes of the community.
  • In November 2017, at the MODXpo conference, Lukianenko Dmytro successfully gave a report on progress with Evolution CMS (
  • January 2018 saw the second major release of Evolution CMS 1.4.0 (, which radically changed a number of approaches in development.
  • In June 2018 it was decided to rewrite the Evolution CMS using Laravel components, with the prerequisite of maintaining full backward compatibility.
  • Now in December 2018 we are proud to present the first release of Evolution CMS 2.0.

A very important requirement was preserving backward compatibility with old versions of Evolution CMS and MODX Evolution, and we did it! You can safely upgrade your website from version 0.9.6 released in 2005 to 2.0. Only any code written without using the MODX Evolution API must be changed. All standard add-ons are updated and work with the new version.

Why did we choose Laravel?

There are many PHP frameworks but Laravel stood out because of its:

  • Extensive documentation
  • Active support
  • A lot of ready-made packages that can be used on Evolution 2.0

Initially, we saw only two ways: to continue working with obsolete Evolution code, while the community scattered and developers left the project, or to start writing a new CMS while keeping the old development paradigm people liked (the resource tree, chunks, snippets, TV parameters etc).

But we found the third option in which we gradually refactored the outdated code whilst maintaining backward compatibility.

Why Evolution CMS 2.0?

Evolution CMS is simple. You can understand how to work with it in a couple of evenings, and if you want to write code for it, the knowledge is the same as working with any Laravel project. Now you don't need to learn something that's only useful when working with Evolution CMS. This gives us universal appeal, as it's easy to switch between systems.

Will my existing Evolution CMS website continue to work?

Yes! Sites built the traditional way will continue to work, but the new flexibility and innovation won't be visible.

Great! How can I start migrating my site to the new features?

The small transition in Evolution CMS 2.0 from the $modx->config array to using the $modx->getConfig() method already allows you to manipulate the system settings of the engine, which are taken from the database. You can prepare for this change in your snippets right now, because the getConfig() method has been available since version 1.4.

Plugins for events can be created as before via the admin area or (new in Evolution CMS 2.0) through files. All this improves team development, simplifies project management through git. Developers will appreciate the convenience of storing the website configuration in Git.

Why should I learn something new and not stay with 1.4?

On version 1.4 you cannot install a site with one click. 1.4 doesn't have a good story for dev and production versions. Neither can you easily store templates in Git, or use database migrations etc. In version 2.0, this is all there.

Can you use ready-made Laravel components with Evolution CMS?


Here is a package for generating Entity Relation diagrams from the database ( Installing it requires you to run composer:

composer require beyondcode/laravel-er-diagram-generator --dev

and create a provider file (core/custom/config/app/providers/Diagram_Generator. php) containing 1 line:.

return BeyondCode\ErdGenerator\ErdGeneratorServiceProvider::class;


Let's start:

New settings and advantages

  • The entire core/config folder and core/custom/config is already working with Laravel-style configs. To use the .env file, you must install the package vlucas/phpdotenv through the composer

  • Working with Composer: adding dependencies to core/custom/composer.json and executing composer upd from the core folder

  • For convenience, we will enable debugging tools: Debug and debugbar Tracy

    • Debug: create file core/custom/config/app/debug.php with code:
     	return true;
    • function dump shows information in a beautiful way:
    • Folder with logs core/storege/logs

    • Tracy: create file core/custom/config/tracy/active.php with code:

     	return 'manager';


Working with Templates and Chunks using the BLADE template engine from files without using the admin panel

Linking templates to the document without EVO admin panel

To work, we need to create a folder views in the root of the site, in which we will have templates. Actually and everything, no additional actions in the form of installing anything is required.

Plugin searches for templates in such order:

  • tpl-3_doc-5.blade.php - use this if resource id=5 and resource template=3;
  • doc-5.blade.php - use this if resource id=5;
  • tpl-3.blade.php - use this if resource template=3.

Working with standard elements using the BLADE template engine

Before you start working with BLADE, we strongly recommend that you read the BLADE documentation:

//Display plaсeholder [*pagetitle*]:
{{ $documentObject['pagetitle'] }}
{{ $modx->documentObject['pagetitle'] }}

//Display TV plaсeholder
{{ $documentObject['image'] }}
{{ $modx->documentObject['image']['1'] }}

//Display URL [~2~]
{{ urlProcessor::makeUrl('2') }}
{{ $modx->makeUrl('2') }}

//Use system settings [(site_name)]
{{ $modx->getConfig('site_name') }}

//Use chunk from db: {{chunkFromDb}}
{{ $modx->getChunk('chunkFromDb') }} 

//Use chunk from file: (/views/partials/chunk.blade.php)
@include('partials.chunk', ['some' => 'data'])

//Use snippet: [[DocInfo? &docid=`2`]] 
{{ $modx->runSnippet('DocInfo',['docid' => '2']) }}

//Display the output of snippet without escaping html tags
{!! $modx->runSnippet('DocInfo',['docid' => '2']) !!}

//Standart MODX Parser
@evoParser('[*pagetitle*] [(site_name)] [[DocInfo]] {{chunkOld}}')

//Use of comments
{{-- This comment will not be in the final HTML --}}

//IF (All of the documentation for BLADE):
@for ($i = 1; $i <= 10; $i++)
  {{ $i }}
  @if ($i != 10)

//Work with php inside template (not recomended)
  dump($modx); //beautiful var_dump
  $chunk = '{{ $data["param1"] }}';
  $chunk .= '{!! $data["param1"] !!}';
  dump($modx); //beautiful var_dump
  $chunk = '{{ $data["param1"] }}';
  $chunk .= '{!! $data["param1"] !!}';

{{ $modx->tpl->parseChunk('@B_CODE:'.$chunk, ['param1' => 'value with "quote"']) }}
{{ time() }}

//Doclister with inline BLADE template
{!! $modx->runSnippet('DocLister',['parents' => '0', 'tpl' => '@B_CODE:{{ $data["pagetitle"] }}<br />']) !!}

//DocLister with BLADE template from file (/views/partials/doc-tpl.blade.php)
{!! $modx->runSnippet('DocLister',[
  'parents' => '2', 
	'tpl' => '@B_FILE:partials/doc-tpl',

An example of a finished template using BLADE can be found here:

Working with snippets and plugins from files without using the admin panel, as well as using Laravel events

In Evolution 2.0 we introduce a new entity package. This is a package of add-ons that may include snippets, plug-ins, chunks, modules. Modules now require you to register yourself through the admin area, but in the future we will redo them so that they automatically pull up, as well as all other elements.

1. Create our package(example):

Create file: core/custom/packages/example/src/ExampleServiceProvider.php

<?php namespace EvolutionCMS\Custom;

use EvolutionCMS\ServiceProvider;
use Event;

class ExampleServiceProvider extends ServiceProvider
     * If you specify an empty line, then snippets and chunks will have our usual naming convention.
     * Suppose a test file creates a chunk / snippet named test
     * If the namespace is specified, the test file will create a chunk / snippet named example#test
     * It also supports files in subfolders. Those. the test file from the subdir folder will create an item called subdir/test

    protected $namespace = 'example';    
     * Register the service provider.
     * @return void
    public function register()
            dirname(__DIR__). '/snippets/',

            dirname(__DIR__) . '/chunks/',
	//Work with EVO and Laravel events:
        Event::listen('evolution.OnWebPageComplete', function($params) {
            echo '<p>Hello Evo events.</p>';

And so we added our package in which we specified the namespace for the snippet, which allows us to use the same snippet from different packages, without worrying about the fact that they will conflict. Immediately register the wiretapping of events (plugins) and specify the folder for the chunks.

2. Update composer for packages:

Create file: core/custom/composer.json

  "name": "evolutioncms/custom",
  "require": {
    "barryvdh/laravel-ide-helper": "~2.4",
    "vlucas/phpdotenv": "~2.2"
  "autoload": {
    "psr-4": {
      "EvolutionCMS\\Custom\\": "packages/example/src/",

run command: composer upd from folder core

3. Register our package in EVO:

Create file: core/custom/config/app/providers/Package_Example.php

	return EvolutionCMS\Custom\ExampleServiceProvider::class;

4. Add chunk:

Create file: core/custom/packages/example/chunks/subdir/test.html

	Sample [+time+], [+content+]

The contents of this file is processed by the MODX parser, so you can use the usual MODX placeholders in it (an example with support for BLADE chunks will be later).

5. Add snippet:

Create file: core/custom/packages/example/snippet/subdir/test.php

return $modx->parseChunk('example2#subdir\test', [
    'time' => time(),
    'content' => 'zxc'
], '[+', '+]');

Call the snippet in the current example like this:

Parser MODX: [[example2#subdir\test]] 
Parser Blade: {{ $modx->runSnippet('example2#subdir\test') }}

But if you do not specify the namespace for the package and do not put the snippet in a subfolder, then we get all the usual option


Thus, we see that now you can fully work with Evo add-ons without having to store the code in the Database. At the same time leaving full backward compatibility with previous versions.

Work with DB, MODELS

All according to Laravel documentation, Models in the core/src/Models with namespace EvolutionCMS\Models. Example:

$out = EvolutionCMS\Models\SiteContent::where('parent', '=', 0)
    ->orderBy('pagetitle', 'DESC')
foreach ($out as $item) {
    echo "\t [ DOCUMENT #ID " . $item->id . ' ] ' . $item->pagetitle .PHP_EOL;

Coming soon:

  • Finish work on refactoring admin templates with full transfer to BLADE
  • More convenience for working with DEV PROD: migrations, sides, work through the console (artisan), solving the problem that DEV and PROD have different document IDs.
  • Separating the core from the add-ons and transferring the selection of what to install by default at the time of installation (all that are chosen will be loaded and installed, and the rest will not be loaded).
  • Refining the widgets for out-of-date extras and upgrades, with multiple levels of priorities.
  • Better documentation and examples.

How you can help with testing

Send your wishes and bug reports to us on github:
Be sure to provide:

  • Evolution CMS version
  • PHP version
  • MySQL version
  • The URL with the error
  • A screenshot of the error
  • Error messages from the log files
  • Step by step instructions to reproduce the bug

By sending us a great bug report, you will help us spend more time fixing the code, and not on figuring out what is not working.


Assets 2