Upgrade PagibleAI CMS

PagibleAI CMS adheres to MAJOR.MINOR.PATCH semantic versioning (SemVer) for clear, predictable updates. MAJOR releases introduce breaking changes, MINOR releases add backward-compatible features (e.g., from 1.1.x to 1.2.x), and PATCH releases provide backward-compatible bug and security fixes. Each minor release is actively supported until the next minor release is published.

Users are strongly encouraged to keep their installations updated with the latest patch releases for security and critical fixes. For detailed changes, refer to the release notes.

Upgrade Guide

To upgrade your PagibleAI CMS installation between major/minor versions, follow these general steps:

  1. Run composer update in your project's root directory.
  2. Run php artisan migrate to apply any database schema changes.
  3. Carefully check your configuration files for any newly added lines or changes. It is recommended to compare your config/cms.php file with the original provided in the new release.
  4. If you have customized any vendor templates in ./resources/views/vendor/cms/, compare your overwritten templates to the original ones to ensure compatibility and merge any necessary updates.
  5. Similarly, compare the CSS and JavaScript files located in ./public/vendor/cms/theme/ to the original files from the new release and merge any changes as required.
  6. Check the release notes for breaking changes.

Important Changes

0.12.x → 0.13.x

PagibleAI 0.13 is a feature release without storage changes. It adds one database index, a larger preview size, dynamic robots.txt and security.txt routes, a news sitemap, a new admin color palette and optional webhook and CDN packages. Existing content keeps working; the steps below keep previews, robots rules, permissions, queue workers, GraphQL clients and customized configuration aligned.

Run the upgrade

php artisan down

composer require aimeos/pagible:~0.13 --with-all-dependencies
php artisan cms:install

php artisan vendor:publish --force \
  --tag=cms-admin --tag=cms-graphql

php artisan optimize:clear
php artisan queue:restart

php artisan up

cms:install also runs the database migrations, so a separate php artisan migrate isn't needed. Do not pass --seed on an existing installation. The only new migration adds an index on cms_pages (tenant_id, type, deleted_at, created_at) for the new news sitemap; it doesn't change existing records. If you use Pagible Cashier, require its 0.13 provider package in the same Composer update.

Create the new preview size

0.13 adds a fourth preview size with a width of 720px to cms.image.preview-sizes. If you published config/cms.php, add ['width' => 720, 'height' => 405] to your preview sizes. Then create the missing previews for existing images:

php artisan cms:previews

The command creates missing sizes and removes previews of sizes that are no longer configured. Use php artisan cms:previews --force to replace all previews, e.g. after changing CMS_IMAGE_QUALITY or the image driver. Limit the run with --tenant=ID or --id=ID; if it is stopped, run it again to update the remaining files.

Move robots.txt and security.txt into the CMS

/robots.txt is now served dynamically from the robots.txt configuration element of the root page, together with the generated sitemap and news sitemap (/sitemap-news.xml) URLs. The new /security.txt route is generated from the security configuration element of the root page in the same way. Web servers deliver static files in public/ before Laravel receives the request, so:

  1. Copy any custom rules from public/robots.txt and the contacts from public/security.txt into the matching configuration elements of the root page and publish the page.
  2. Remove the static files:
rm -f public/robots.txt public/security.txt

Alternatively, configure the web server to pass /robots.txt and /security.txt to Laravel even when the static files exist. See robots.txt, security.txt and Sitemaps for details.

Update configuration and environment variables

Setting
Default
Action
CMS_IMAGE_QUALITY
75
Optional: quality (1-100) of the WebP or JPEG previews; run cms:previews --force after changing it
CMS_QUEUE_CONNECTION / CMS_QUEUE
Default queue connection and name
Optional: dedicated queue for CMS background jobs; the sync driver is supported
CMS_AI_MAXSTEPS
25
Optional: maximum number of tool-calling steps of an AI request
CMS_ADMIN_LOGIN
Empty
Optional: login URL for single sign-on, e.g. https://example.com/login?redirect=_url_; the admin opens it when the session expires and replaces _url_ with the admin URL
CMS_CSP_FRAME_SRC
hCaptcha hosts and https://www.openstreetmap.org
If you override it, add https://www.openstreetmap.org when you use the new map element
Admin colors in config/cms/admin.php
New palette
If you customized the colors, merge the new keys surface-light, emphasis, on-emphasis, nav-accent, on-primary, on-secondary, on-error, on-info, on-success, on-warning and variables.selected-opacity for the light and dark themes

Assign new permissions

  • element:chat and file:chat (AI package) allow the new AI chat in the shared element and file lists, in addition to the existing page:chat.
  • config:webhook (webhooks package) allows managing webhooks.
  • cache:clear is now part of the built-in publisher role and therefore also of editor, so both can use Clear cache in the page list. With the CDN package installed, this also purges the pages from the CDN. Add !cache:clear to a role or user who shouldn't clear caches.

The built-in publisher and editor roles receive the chat permissions through their element:* and file:* wildcards, and admin has all permissions. Add the new actions to custom roles where editors should use these features. If you redefined the roles in a published config/cms.php, merge the new cache:clear entry yourself.

Run a queue worker

Publishing or deleting a shared element or file now invalidates the cached pages that use it in queued InvalidatePages jobs, so publishing content shared by many pages doesn't slow down the request. Run a worker for the CMS queue (CMS_QUEUE_CONNECTION, CMS_QUEUE), otherwise these pages keep their cached version until the cache lifetime expires. With the sync queue driver, the jobs run immediately.

Update GraphQL clients

The clearCache mutation now accepts a list of page IDs instead of a single ID: clearCache(ids: [ID!]!): Int!. It clears the cache of the selected pages and their descendants, accepts up to 1000 IDs and returns the number of cleared pages. Replace clearCache(id: "...") with clearCache(ids: ["..."]) in your clients. See GraphQL Pages.

Other changes

  • php artisan cms:restore --force now also accepts backups created by another installation with a different APP_KEY; all checksums are still verified.
  • The new optional packages aimeos/pagible-webhooks (signed outbound notifications when content changes) and aimeos/pagible-cdn (purging CDN and proxy caches) need a running queue worker. They require no action unless you install them.
  • If you customized published views or theme assets, compare them with the 0.13 packages and merge the changes.

0.11.x → 0.12.x

PagibleAI 0.12 changes managed file storage, custom-theme integration, CMS API contracts and the optional Cashier integration. Plan this as a maintenance upgrade, even if your site uses only public content.

Before you upgrade

Prepare
Why it matters
Back up the database and every CMS storage disk at the same point in time
The file-path migration changes database records and stored objects together
Run the upgrade on a staging copy with representative file histories
Remote disks may need several requests for every original, preview and historical version
Stop page/file writes, scheduled publishing, queue workers and payment webhooks
0.11 workers must not write while 0.12 migrations are moving files
Record local overrides
Review config/cms.php, published CMS config, resources/views/vendor/cms, theme assets, API clients and Echo clients
Confirm free storage and write access
The migration copies and verifies new objects before deleting legacy paths

Run the upgrade

php artisan down

composer require aimeos/pagible:~0.12 --with-all-dependencies
php artisan cms:install
php artisan optimize:clear
php artisan queue:restart

php artisan up

Do not pass --seed on an existing installation. If Pagible Cashier is installed, choose and require its 0.12 provider package before you run cms:install; the Cashier section below shows the additional work.

cms:install republishes package files, updates safely recognizable CMS configuration entries and runs the database migrations. In production, confirm the migration prompt. If the installer cannot safely replace a customized top-level cms.disk entry, it stops and tells you to update that configuration manually.

Do not bring traffic or workers back until the file migration and every other migration have completed.

Prepare the file-storage migration

0.12 adds the cms_files.disk column and changes managed paths from a shared tenant directory to a directory owned by the File UUID. The migration reads current and historical versions, copies every existing object to its new path, verifies the copy, updates the database and only then removes the legacy object. Remote hot-linked URLs are left unchanged.

Make sure the disk used by 0.11 is configured as cms.disks.public.name before the migration starts. The CMS_DISK environment variable keeps its name. The new private disk must be a different, non-public Laravel disk.

This storage migration is intentionally irreversible. A rollback requires the matching database and storage backups; changing the Composer version alone is not enough.

CMS_DISK=public
CMS_PRIVATE_DISK=local
CMS_PRIVATE_TTL=300

CMS_UPLOAD_FILESIZE=50
CMS_UPLOAD_MAXPIXELS=16777216
CMS_UPLOAD_MIMETYPES="application/gzip,application/pdf,application/vnd.,application/zip,audio/,image/,text/,video/"

Update configuration and environment variables

0.11 setting
0.12 setting
Action
cms.disk
cms.disks.public.name
Let the installer convert the top-level entry or update a customized structure manually; CMS_DISK remains valid
No private CMS disk
cms.disks.private.name and .ttl
Set CMS_PRIVATE_DISK only to a disk that is not publicly reachable and is different from the public disk
CMS_GRAPHQL_FILESIZE
CMS_UPLOAD_FILESIZE
Move any override; one upload policy now covers every CMS interface
CMS_GRAPHQL_MIMETYPES
CMS_UPLOAD_MIMETYPES
Move any override and verify the permitted MIME prefixes
No decoded-image limit
CMS_UPLOAD_MAXPIXELS
Raise the default only when your trusted image workflow needs larger rasters
Internal URL fetching allowed by default
CMS_ALLOW_INTERNAL=false
Keep the secure default; enable internal hosts only for controlled URLs
Shared cms-admin throttles on CMS routes
Separate cms-graphql, cms-mcp, cms-ai and cms-broadcast throttles
Rerun the package installers and update custom route middleware or limiter definitions
Custom tenant middleware on ordinary web routes
Package-specific route middleware plus outer page-route initialization
Initialize tenancy before page-cache, AI, broadcast and API middleware

Merge custom themes and published assets

If you use only the packaged themes, republish the admin and GraphQL bundles and let the theme publisher add missing files. If you own published views or theme assets, merge the 0.12 changes instead of overwriting your work.

  • blog.css and blog.js become list.css and list.js; the frontend selectors change from .blog-* to .list-*.
  • Layouts receive a Navigation object as $nav. Replace direct $page->nav() and ancestor filtering with $nav->items() and $nav->ancestors().
  • Include cms::layouts.foot so CSRF handling, lazy assets, page CSS/JavaScript and optional editor assets stay aligned.
  • Generate File URLs with cmsasset($page, $file). Direct cmsurl($file->path) calls bypass private delivery.
  • Hero media changes from one file value to a files list. The migration updates stored hero content; update custom schemas, importers and Blade templates too.
  • Remove %%CMS_CSRF%% and %%CMS_NONCE%% placeholders from copied layouts. 0.12 uses authenticated CSRF markup and CSP hashes for page-defined CSS and JavaScript.
php artisan vendor:publish --force \
  --tag=cms-admin --tag=cms-graphql

php artisan vendor:publish --tag=cms-theme

Back up local overrides first. Publishing cms-theme without --force adds new files but does not merge changed copies. Compare your published tree with the 0.12 package and port the required changes. Use --force for the theme only when that published tree contains no local edits.

Update API and real-time clients

Contract
0.12 change
What you need to change
MCP saves
save-page, save-element and save-file require latest_id
Read the item first and pass the version returned by get-*, add-* or the previous save
Page meta/config
Entries are keyed by type and each contains type, data and files
Update GraphQL, MCP, import and custom PHP payloads; migrations normalize stored 0.11 data
GraphQL Page.has
Returns an Int count instead of a Boolean
Regenerate typed clients and compare the value with zero
GraphQL Query.me
Returns CmsUser
Regenerate the schema types used by your client
GraphQL authorization
Sensitive relations and mutations also require the matching view action
Add page:view, element:view or file:view to narrowly defined custom roles where required
File versions
Description and transcription move from Version.data to Version.aux; File responses expose disk
Update direct version readers and generated client types
Model extension constants
Element::SELECT_COLS and File::SELECT_COLS become SELECT_COLUMNS
Update custom queries, packages and model extensions
Broadcasting
One tenant-aware channel per content type replaces per-item channels
Subscribe to cms.{tenant}.{type} and .{type}.{action} events; omit the tenant segment for the default tenant and resync after reconnect
{
  "meta": {
    "meta-tags": {
      "type": "meta-tags",
      "data": {
        "description": "A page description"
      },
      "files": []
    }
  }
}

Decide whether to enable frontend access

The new cms_page_access table does not restrict existing pages: a page with no rule rows remains public.

If you enable restrictions, configure one Access catalog or supported permission adapter, give the responsible users the page:access permission (included in the publisher role) and change rules through PageAccess::set(). CMS roles and visitor access remain separate.

A restricted page does not protect files already stored on the public disk. Relocate sensitive files to the private disk and render their URLs with cmsasset(). See Authorization and Permissions for the complete boundary.

Migrate Pagible Cashier only if you use it

0.12 splits payment support into one provider package per application. Require exactly one of aimeos/pagible-cashier-stripe, aimeos/pagible-cashier-paddle or aimeos/pagible-cashier-mollie; the provider package brings the shared integration and compatible upstream Cashier package. Stripe now uses Laravel Cashier 16.

If you already use Cashier, include the chosen 0.12 provider in the same Composer update as aimeos/pagible. Do this before cms:install, otherwise the shared Cashier installer correctly stops because no provider is registered.

Remove CMS_CASHIER_PROVIDER, add Pagible's CashierAccess trait beside the provider's Billable trait, and check for an application-owned users.access column before migration. Pagible Cashier reserves that column and refuses to overwrite it.

After installing the provider, run php artisan cms:install:cashier and php artisan cms:cashier:check. Deployment pipelines can publish with --no-migrate and run their normal php artisan migrate --force step. Recheck credentials, webhook signatures, sandbox checkout, cancellation and refund behavior before accepting payments.

Pagible packages change from LGPL-3.0-only to the MIT license in 0.12. Update your software bill of materials and license inventory. The new Pulse integration and additional theme packages are optional; they need no action unless you install them.

Verify before reopening the site

  • Confirm every migration is complete and no file-migration error was reported.
  • Rebuild the CMS search index after content and access normalization.
  • Open the admin, save and publish one draft, then verify another editor receives the update.
  • Check a public page as a guest and an authenticated user.
  • Upload an image, inspect its previews and restore an older File version.
  • If you enabled access rules, test guest, same-tenant, different-tenant and named-access users against both the page and a private file.
  • Exercise every GraphQL or MCP client that writes content.
  • Restart queue, Horizon, Octane and Reverb processes that keep application code in memory.
  • Run cms:cashier:check and a sandbox payment cycle when Cashier is installed.
php artisan migrate:status
php artisan cms:index
php artisan optimize:clear
php artisan queue:restart

If verification fails after the storage migration, keep the site in maintenance mode. Restore the database and all CMS disks from the same backup point before reinstalling 0.11. Do not run a partial package downgrade against the migrated storage layout.

0.10.x -> 0.11.x

  • AI engine: The AI integration has been migrated from prism-php/prism to the aimeos/prisma library, and aimeos/pagible-mcp is now a required dependency (it was previously only suggested). Run composer update to pull in the new packages
  • GraphQL CSRF protection: The GraphQL API endpoint is now protected against cross-site request forgery. Re-run php artisan cms:install after updating to add the ValidateCsrfToken middleware to your config/lighthouse.php — the installer is idempotent and only inserts the middleware when it is missing
  • AI default models removed: The hard-coded default models (e.g. gemini-2.5-flash, whisper-1) have been removed from config/cms/ai.php. The CMS now uses each provider's own default model unless you set the corresponding CMS_AI_*_MODEL environment variable
  • Refine provider default: The refine operation now defaults to the OpenAI provider instead of Gemini. Set CMS_AI_REFINE=gemini in your .env file to keep the previous behavior
  • Schema configuration removed: The config/cms/schemas.php file has been removed. Content element schemas are now loaded from schema.json files. If you customized config/cms/schemas.php, migrate your changes to the corresponding schema.json files
  • Template slots renamed: The Blade asset stacks have been renamed to match their semantics: css is now head and js is now foot. Update any custom themes or templates using @push('css')/@stack('css') and @push('js')/@stack('js') to @push('head')/@stack('head') and @push('foot')/@stack('foot')
  • Themes moved to separate packages: The default theme is now a new, clean theme shipped in aimeos/pagible-theme. The previous design is available as a separate package aimeos/pagible-themes-pagible, alongside aimeos/pagible-themes-glass, aimeos/pagible-themes-paper and aimeos/pagible-themes-premium. Require the theme package you want to use
  • Theme CSS split: Below-the-fold styles have been moved to a new cms-lazy.css file. If you customized the theme CSS in ./public/vendor/cms/theme/, re-publish the assets and merge your changes into both cms.css and cms-lazy.css
  • Removed page section config: The cms.config block defining theme page types and sections has been removed from config/cms.php. Page section configuration is now provided by the theme packages

0.9.x -> 0.10.x

  • Permissions: The cmseditor boolean column has been replaced by a cmsperms JSON column supporting named roles (admin, editor, publisher, viewer). Run php artisan migrate to apply the migration which automatically converts existing permissions
  • Configuration renamed: cms.menu_maxdepth has been renamed to cms.navdepth and the environment variable changed from CMS_MENU_MAXDEPTH to CMS_NAVDEPTH. Also, cms.config.locales has been moved to cms.locales and is now driven by the CMS_LOCALES environment variable
  • Configuration split: The schemas section has been moved from config/cms.php into a separate config/cms/schemas.php file. If you have customized schemas, move them to the new file
  • Admin proxy configuration: The proxy config keys in config/cms/admin.php have been renamed: max-length is now maxsize and stream_timeout is now timeout. Update your .env file accordingly: CMS_PROXY_MAX_LENGTH → CMS_PROXY_MAXSIZE and CMS_PROXY_STREAM_TIMEOUT → CMS_PROXY_TIMEOUT
  • Vendor publish tag: The publish tags have changed to cms-admin, cms-config, cms-graphql and cms-theme. Use php artisan vendor:publish --tag=cms-admin tag=cms-config tag=cms-graphql tag=cms-theme to republish the admin configuration
  • Search parameter: The frontend search query parameter has been renamed from search to q. Update any custom search forms or links accordingly

0.8.x -> 0.9.x

  • UUID: The pages now use UUID values as IDs and you have to execute php artisan migrate to change the database schema and update the records
  • Configuration: The AI provider configuration has changed including the names for the keys in the .env file. Please update your ./config/cms.php file