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.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

Run these commands only after 0.12 is released. 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 publishers both page:publish and access:view, 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_LENGTHCMS_PROXY_MAXSIZE and CMS_PROXY_STREAM_TIMEOUTCMS_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