Aimeos GrapesJS CMS is a page editor that inherits Aimeos's catch-all route
GrapesJS CMS integration into Aimeos
At a glance
- What is it?
- ai-cms-grapesjs gives an Aimeos shop a what-you-see-is-what-you-get page editor built on GrapesJS, and the interesting part is not the editor but the routing: content pages are served by a catch-all route that must be the last line in routes/web.php. That single constraint shapes everything you do afterwards.
- Who is it for?
- Adopt ai-cms-grapesjs if you run an Aimeos shop and need content pages that product data alone cannot express, since the extension gives you a component-based page editor and a decorator chain, and install it only if you are already inside the Aimeos ecosystem because the package is an extension rather than a standalone CMS.
- Can I use it commercially?
- Yes, with conditions. LGPL-2.1 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly PHP, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
It is an Aimeos extension, not a CMS you can adopt on its own
The readme opens with the sentence that settles the scope: the extension provides a page editor for creating content pages based on extensible components, as every Aimeos extension, installed through composer. Read the repository layout to see how tightly it is bound. There is a composer.json and a manifest.php, which is the Aimeos extension manifest, a config directory, a setup directory, templates, themes, i18n, src, tests, and a phing.xml build file. There is also a manifest.jsb2, which belongs to the GrapesJS build rather than to Aimeos, so you are looking at two ecosystems meeting in one tree. The practical consequence is that the useful questions are all about the host application. What does the page editor write to, which tables hold the content, which controller renders it. The answer is that content pages are stored in new tables created by a migration step, and that they are rendered through a dedicated controller from the Aimeos shop package. A team that wants a visual page builder but has no Aimeos shop gets nothing here, and a team with an Aimeos shop gets a page editor that reuses the shop's own component system rather than inventing a parallel one, which is the single strongest argument in its favour.
Install is a composer require, and then a migration you cannot skip
Installation follows the Aimeos convention, so the package name is the whole command. If composer is not present, the readme gives the standard one-liner to fetch it:
php -r "readfile('https://getcomposer.org/installer');" | php -- --filename=composerThen the extension itself:
composer req "aimeos/ai-cms-grapesjs"The readme states plainly that these commands install the extension into the extension directory and that it becomes available after you execute the database migration. That ordering is the thing to get right. Because content pages live in their own tables, a deployment that installs the package without running the migration produces an extension the admin interface can see and the front end cannot render, and the failure will look like missing content rather than a missing schema. The circular build configuration tells you the project installs through a Phing build file rather than only through composer, which matters if you are automating a deployment: the composer step gets the code, and something else has to apply the setup step. The repository also carries a translation directory and a tests directory, so the extension follows the Aimeos conventions that a core maintainer would expect, even though the release history is not published as GitHub releases.
Enabling pages is a config edit, not a plugin toggle
After the migration, pages become visible only if you wire them into the component list of your shop configuration. The readme says to uncomment the page section in config/shop.php and to add cms/page to the list of components where you want CMS content displayed, and it gives a concrete example: a catalog-home page whose component list gains cms/page alongside the locale selector, mini basket, catalog tree, search and home components. Two things follow from that example. The first is that pages are assembled from the same component vocabulary as the rest of the shop, so a CMS page is not a foreign document dropped into a shop, it is another set of components in a list, and ordering within that list is layout. The second is that enabling it is a per-page decision, which means the blast radius of a mistake is one template rather than the whole storefront, and which also means a page where someone forgot the entry is simply a shop page with no CMS content. The setup command for creating the new tables is documented as run in the root directory of your Laravel application:
php artisan aimeos:setupThat command is Laravel-specific, and it is the clearest signal in the readme about which integration is actually supported. Everything from this point onward is framed as Laravel work, and no other framework gets documented treatment.
The catch-all route: one line, placed last, and it breaks your later routes
This is the section to read twice. To serve CMS page URLs, the readme says to add a route match at the end of routes/web.php:
Route::match(['GET', 'POST'], '{path?}', '\Aimeos\Shop\Controller\PageController@indexAction')
->name('aimeos_page')->where( 'path', '.*' );The optional path segment with a regex constraint matching anything is a catch-all, and the readme's warning is unambiguous: it will catch every URL not matched before it, so do not put routes after that line because they will not be used. That is a genuine architectural cost, not a documentation warning. A single catch-all in a shared routes file means the file is now ordered rather than arbitrary, that route order becomes load-bearing for every future feature, and that any developer adding a route at the natural place at the bottom of the file will ship a 404 with no error message anywhere. Three variants exist for real deployments. A multi-language setup moves the locale into the route pattern. A multi-vendor setup wraps the same catch-all in a route group, once with a path prefix such as yourdomain.com/vendor1, once as a subdomain such as vendor1.yourdomain.com, and once as a custom domain, each with a where constraint restricting the site segment to lowercase alphanumerics and the vendor1.com variant also allowing dots. The subdomain and custom-domain variants are where this gets sharp: a per-vendor catch-all with a domain constraint is the mechanism by which a multi-vendor storefront serves each merchant's own CMS pages, and the regex is what stops one vendor's path from resolving under another's domain.
Form protection is a decorator in the config, not a setting in the editor
Spam protection on CMS forms is handled by Google reCAPTCHA v3, described as an invisible CAPTCHA, configured entirely in config/shop.php. The configuration is nested through four levels: a resource block holding a recaptcha entry with secretkey and sitekey, then a client block, then an html block, then a cms block, then a page block, and finally a decorators block with a local entry mapping the string Recaptcha to the string Recaptcha. Read the nesting as a decorator chain being assembled in configuration, which tells you two useful things. The editor does not decide whether a form is protected; a shop operator does, in a config file, which is the right place for something with keys in it. And the decorator model means other wrappers can be added at the same point, so a form is composable rather than hard-wired to one anti-spam vendor. The keys come from a Google account, and the readme flags the operational step most people skip: add all your domains to the list of allowed domains. Miss that and reCAPTCHA fails in production while working fine locally, because the domain allow list is enforced by Google rather than by your application. The readme also says to use it for all forms in CMS pages, so the intent is a site-wide default rather than a per-form choice.
The 419 error is a design leak, and it is worth understanding
The readme's potential problems section contains one entry, and it is unusually specific: a contact form page expiring. The stated cause is a security precaution, because being logged into the admin backend while using the contact form produces a 419 page expired error, so you must be logged out before sending a contact request. 419 is the CSRF token mismatch code in Laravel, so what is happening is that an authenticated session and a public form are colliding over token handling, and the extension has chosen to fail closed. Failing closed is the right call for a public form, because the alternative is a form that behaves differently depending on who submits it, which is exactly the sort of inconsistency attackers probe for. The cost lands on the workflow. An editor writing a contact page cannot test it from a browser where they are signed in, and the failure mode is a bare error code rather than a message explaining the cause, so a content team will hit this and file it as a bug. If you deploy this, the mitigation is procedural: test public forms in a private window or as a different user, and put the requirement in the page-editor instructions your content team reads. Nothing in the readme offers a config switch to relax it, which is itself the information you need.
No releases, an LGPL licence, and a recent push
The maintenance picture is thin on paper and healthy in practice. The repository publishes no GitHub releases, so there is no tag to pin and no changelog to read, which for a composer package is mostly a documentation gap rather than a supply-chain one, since composer resolves against the version metadata the package declares. The last push to the master branch was on 2026-09-09, which is recent, and the presence of a CircleCI configuration, a coveralls coverage badge and a Scrutinizer quality badge in the readme says the project runs continuous integration, coverage and static analysis rather than relying on a maintainer to run tests by hand. Those three badges together are a better maintenance signal than a release history would be for an extension of this size. The licence is LGPL-2.1, which for a PHP extension loaded into a shop means the linking question is the one to consider rather than a pure permissive grant, and the packagist badge links to the package page where the declared licence is the thing to check against what you rely on. If you are extending this yourself, the extension directory structure and the Aimeos extension manifest are the contracts you have to honour, not just the page editor.
Editorial conclusion
Adopt ai-cms-grapesjs if you run an Aimeos shop and need content pages that product data alone cannot express, since the extension gives you a component-based page editor and a decorator chain, and install it only if you are already inside the Aimeos ecosystem because the package is an extension rather than a standalone CMS. Do not reach for it as a general page builder: there is no releases published, no homepage beyond the Aimeos site, and the readme covers Laravel integration only, so a non-Laravel or non-Aimeos project is out of scope. Four things to verify before you commit. First, the route ordering, since the documented catch-all must be the final line of routes/web.php and every route you add after it is dead, which is a change to a shared file that other developers on the team will trip over. Second, the admin session constraint, because the readme warns that a contact form submitted while logged into the admin backend returns a 419 page expired error, so any workflow that lets an editor test a form as themselves will break. Third, the ReCAPTCHA v3 keys, which are yours to generate in a Google account and whose allowed domain list has to be edited every time you add a host. Fourth, the licence, which is LGPL-2.1, and the last push to the master branch was on 2026-09-09.
Frequently asked questions
How do I install the Aimeos GrapesJS CMS extension?
Install it as a composer package with composer req "aimeos/ai-cms-grapesjs". The readme states the extension becomes available only after you execute the database migration, since content pages use newly created tables.
How do I display CMS content on a shop page?
Uncomment the page section in config/shop.php and add cms/page to the list of components for each page that should show CMS content. The readme's example adds it to a catalog-home page alongside components such as locale/select, basket/mini, catalog/tree, catalog/search and catalog/home.
Where should the CMS page route go in routes/web.php?
At the end of the file, and nothing should follow it. The readme warns that the catch-all match on an optional path segment will handle every URL not already matched, so routes placed after it will never be used.
How does ai-cms-grapesjs handle spam on contact forms?
Through Google reCAPTCHA v3, configured in config/shop.php with a secretkey and sitekey under resource, and enabled by adding a Recaptcha decorator to the cms/page decorator chain. The keys are generated in a Google account and all your domains must be added to the allowed list.
Why does a CMS contact form return a 419 page expired error?
The readme states this happens when you are logged into the admin backend while submitting the contact form, as a security precaution, and that you must log out of the admin backend first. The extension fails closed rather than behaving differently for authenticated users.
What licence is the Aimeos GrapesJS CMS released under?
LGPL-2.1. The repository publishes no GitHub releases, though the last push to the master branch was on 2026-09-09, and the readme carries build, coverage and code quality badges.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/aimeos-ai-cms-grapesjs)