Three reusable, placeholder-based Claude Code skills distilled from the IVV Aachen TYPO3 v11→v14 project: - typo3-v11-to-v14-ddev-upgrade - typo3-t3bootstrap-live-design-parity (v1.1) - typo3-konsoleh-staging-deploy Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9.2 KiB
name, description, metadata
| name | description | metadata | ||||
|---|---|---|---|---|---|---|
| typo3-v11-to-v14-ddev-upgrade | Bring an existing TYPO3 v11 site up and booting on TYPO3 v14 LTS (v14.3) locally under DDEV, starting from a v11 SQL dump + the old sitepackage. Use when upgrading/migrating a TYPO3 v11 (or v12/13) project to v14 for local dev, when a v11 database dump must be made to boot on v14, or when a t3bootstrap-based v11 site needs its composer/config/schema/upgrade-wizards/site-sets brought to v14. Covers: composer.json rework to ^14 + private git repos & composer registry auth, config/system/settings.php, the v14 .htaccess, database:updateschema, backend admin, upgrade wizards (incl. confirmable + one-way ones), language packs, wiring t3bootstrap TypoScript via site sets, and the recurring v11->v14 traps. NOT for fresh installs and NOT for server deployment (see the konsoleH staging-deploy skill for that). |
|
TYPO3 v11 → v14 upgrade (local, DDEV)
Get an existing TYPO3 v11 site installable and booting on v14 LTS (14.3.x) under DDEV, from a v11 SQL dump + the old sitepackage. This is the "make it run" phase — a later phase matches the frontend design (see the t3bootstrap live-design parity skill) and another deploys to staging (see the konsoleH staging-deploy skill).
Work one step at a time and verify each before moving on. ddev snapshot before anything
destructive (especially upgrade wizards — several are one-way). Never let a live secret appear in a
command. Many errors here look like config bugs but are data/schema/host issues — always confirm the
actual error before "fixing".
Placeholders to resolve first
<PROJECT_DIR>— the DDEV project root (docrootpublic/).<SITE_ID>— the site identifier folder underconfig/sites/<SITE_ID>/.<SITE_BASE_HOST>— the site's base host fromconfig/sites/<SITE_ID>/config.yaml(e.g. the*.ddev.sitehost). The FE only answers on this host, NOTlocalhost.<REGISTRY_URL>— the private Composer registry for the theme/vendor packages, if any (e.g. a Gitea.../api/packages/<vendor>/composerURL).<GIT_REPOS>— anygitea@/GitHub SSH git repos incomposer.jsonrepositories.<TEMPLATE_PACKAGE>— the sitepackage's composername(⚠ often ≠ repo name — read the repo's owncomposer.json).<TEMPLATE_EXTKEY>— its extension key (keep it stable across the rename).
Step 0 — DDEV up + import the dump (read-only baseline)
ddev start; import the v11 dump into the db database (ddev import-db --file=dump-*.sql or
ddev mysql < dump.sql). Confirm PHP/DB versions match the target (v14.3 wants PHP 8.2–8.5). Snapshot:
ddev snapshot --name pre-upgrade.
Step 1 — Rework composer.json for v14
- Bump every
typo3/cms-*to^14. Bump third-party exts (news, address, t3bootstrap/*, …) to their ^14 releases. Drop anything with no v14 release (e.g. flux/vhs are gone in v14 t3bootstrap —t3bootstrap/flux-*do not exist; do not re-add them). - Custom-repo package name ≠ repo name. A git repo
…/<name>.gitmay publish itself as a different composer package name — read the repo'scomposer.jsonnameand require THAT. - Contradictory constraints fail:
"^14 dev-release/v14"(tag AND branch) → composer "cannot possibly match". Use plain"^14"for a tagged package, or"dev-<branch>"for an untagged one. - Repository order controls the source. If the same package name is served by both a git repo and
the registry, composer takes the first repo listed as canonical → list the project's git repo
before the composer registry in
repositoriesto make it win.
Step 2 — Composer auth
- SSH git repos:
ddev auth ssh(loads your keys into the DDEV agent; coversgitea@…/GitHub). - Private registry:
ddev composer config http-basic.<registry-host> <user> <token>(writes the projectauth.json). Get the token from the user — never invent/guess it.
Step 3 — Install
ddev composer update -W (resolve + install with dependencies). Fix constraint conflicts per Step 1.
Step 4 — Create config/system/settings.php
v14 does not auto-write settings.php; ConfigurationManager reads it if present, else falls
back to the old typo3conf/LocalConfiguration.php in place — so a v11→v14 jump with production DB
creds in the old file fails to boot first. Create settings.php from the old
LocalConfiguration.php, but with DDEV DB creds (host db, name db, user db, pass db, port
3306, utf8mb4). Preserve SYS/encryptionKey, install-tool password, sitename, systemMaintainers,
mail sender, and per-extension EXTENSIONS config. Drop obsolete v11 feature flags.
Step 5 — Replace public/.htaccess
Swap in the v14 template:
cp vendor/typo3/cms-install/Resources/Private/FolderStructureTemplateFiles/root-htaccess public/.htaccess.
Symptom of the stale v11 .htaccess: Apache 500 "Request exceeded the limit of 10 internal
redirects" (looks like a config error; it's the htaccess).
Step 6 — Update the DB schema
ddev exec vendor/bin/typo3 database:updateschema "*.add,*.change" — adds the ~20 tables v12–v14 need
(e.g. sys_csp_resolution). Non-destructive (add/change only). Symptom if skipped:
Table 'db.sys_csp_resolution' doesn't exist on any backend request.
Step 7 — Backend admin
ddev exec vendor/bin/typo3 backend:createadmin <user> <pass> (or backend:resetpassword if an admin
already exists in the dump). Do NOT create admin users the user didn't ask for on shared/live systems;
local DDEV is fine.
Step 8 — Upgrade wizards (⚠ snapshot first)
ddev snapshot --name pre-upgradewizards. Then vendor/bin/typo3 upgrade:list and run wizards:
upgrade:rungates on a "Database Up-to-Date" prerequisite → clear data blockers, re-rundatabase:updateschema, thenupgrade:run. Blockers commonly seen:tx_news_domain_model_news.related_linksNULL/non-int →UPDATE … SET related_links=0 WHERE related_links IS NULL OR NOT related_links REGEXP '^[0-9]+$'.sys_category_record_mmduplicate PK tuples (table has nouid) → add a temp AUTO_INCREMENT PK,DELETEvia self-join keeping the lowest, drop the temp column.
- Confirmable wizards (e.g.
convertHeadersize,rewriteIconPaths) error "You have to acknowledge this wizard" under--no-interaction. There is no--confirmflag (--confirm allthrows). Run interactively with piped input:printf 'yes\n' | ddev exec vendor/bin/typo3 upgrade:run <id>(omit--no-interaction). - One-way wizards (e.g. container migration, address→contacts) — the snapshot is your only undo.
- news 14.0.x vs
FlexFormTools::cleanFlexFormXML(): older news calls it with 3 args, v14.3 wants 4 → blockstxNewsPluginUpdater. Fix: update news to a patched 14.x, or one-time-patch the vendorPluginUpdater(the wizard marks itself done; the patch is then harmless if reverted).
Step 8b — Language packs
ddev exec vendor/bin/typo3 language:update. Composer mode ships no language packs → labels fall
back to English (e.g. news "more-link"). Run this whenever the site language isn't English.
Step 9 — Wire TypoScript via site sets
v14 t3bootstrap delivers TypoScript (incl. the PAGE object) through site sets, not sys_template.
The site config must declare them under dependencies: in config/sites/<SITE_ID>/config.yaml, or the
FE dies with "No page configured for type=0". Add the set identifiers (the name: in each ext's
Configuration/Sets/*/config.yaml — independent of package name/extkey), e.g. the theme set +
container-bs5-templates + news/form/address/blog/slider as used. See the design skill for details.
Step 10 — Flush + verify
ddev exec vendor/bin/typo3 cache:flush. Verify over HTTP with the correct host: /typo3/ → 200,
FE with curl -H "Host: <SITE_BASE_HOST>" … (or the real DDEV URL) → 200. "No site configuration
found" is usually a false alarm from curling localhost instead of <SITE_BASE_HOST>.
Other recurring traps
- Leftover custom content element with no v14 provider → FE fatal empty-
templateNameInvalidTemplateResourceException. Don't assume it's flux — check the old sitepackage; a plain custom FSC CType must be re-registered for v14 (see the design skill's iconmenu example). - Relocating a git-repo package's vendor path: change the
namein that repo's owncomposer.json(composer installs by declared name, not repo URL). Keep theextension-keyunchanged soEXT:<key>/…refs + set names keep working. Untagged repo → requiredev-<branch>. - v14 FlexForm relational fields:
FlexFormFieldValues::get()returns aLazyRecordCollection/RecordInterfacefor relation fields (NOT a CSV of uids), which breaksintExplode()/(int)casts in migrated/old ext code →TypeError. Normalize to(string)/(string)$record->getUid()before parsing. Reproduce/verify from CLI with a small bootstrap script (SystemEnvironmentBuilder::run + Bootstrap::init + the record API). - TYPO3 Console (
helhum/typo3-console^8.3) works with v14 —vendor/bin/typo3is the console binary.
Each step verified + a snapshot before wizards = a reversible, debuggable upgrade.