# Bridge35: Joomla 3 to Joomla 5 content migrator Bridge35 copies the core content of a Joomla 3 site into a fresh Joomla 5 site. It keeps the original article, category and tag ids and aliases. Internal links that use ids (`index.php?option=com_content&view=article&id=12`) keep working, and when you rebuild your menus with the same aliases your SEF URLs come back too. ![Preflight](docs/screenshots/02-preflight.png) ## What it moves | Moved | Notes | |---|---| | User groups | Core groups are matched by name. A Joomla 3 "Guest" group with id 13 maps to the Joomla 5 "Guest" group with id 9. Custom groups keep their id when it is free. | | Access levels | Matched by name. Custom levels are added and their group lists are remapped. | | Users | Ids are kept where free. Password hashes are copied unchanged, so users with bcrypt hashes (every Joomla 3.2+ login) log in with their old passwords; this is tested with a real login. If a Joomla 3 user has the **same email** as an existing Joomla 5 user, they are treated as the same person: not copied, and their articles are credited to the Joomla 5 account. If only the **username** is taken by someone else, the user is not copied and their articles show no author. If only the **id** is taken, the user gets a new id and their articles follow. | | User group membership, user profiles | Remapped to the matched groups. | | Content categories | Ids, tree and paths are kept. The tree is rebuilt for Joomla 5. | | Articles | Ids, aliases, dates, hits, featured flags and ratings are kept. Each article joins the default workflow stage, so it shows in Content > Articles. | | Permissions | Category and article permission rules are copied, with group ids remapped. | | Tags | Ids, the tag tree and article/category tag links. | | Custom fields | Article, category and user fields, field groups, category assignments, values and field permissions. User field values are only copied for users that are copied. "Repeatable" fields (removed in Joomla 4) are skipped with a note. | | Global permissions | Joomla 3 Global Configuration and core component rules (including denials) are applied in Joomla 5. Joomla 5 keeps its defaults only for actions that Joomla 3 did not set. Access levels that differ take the Joomla 3 group list. | **Not moved in v1:** menus, modules, templates, banners, contacts, newsfeeds, language associations and third-party extensions such as K2, VirtueMart or Community Builder. Use the Joomla 5 versions of those extensions and their own import tools. **The check screen warns you about:** - Old pre-bcrypt password hashes. Those users should use "Forgot your password?". - Two-factor logins. Joomla 5 has a new multi-factor system, so those users set it up again. - Non-`*` content languages. Install the same languages in Joomla 5. - Very large sites. Use the CLI for those. ## Requirements - A **fresh** Joomla 5 site with no articles yet. Bridge35 refuses to run otherwise, so it can never mix two sites. - PHP 8.1 or later. Tested on Joomla 5.4.10 with PHP 8.3 and MariaDB 11.4. - Read access from the Joomla 5 server to the Joomla 3 database. A read-only database user is enough. ## Install Use System > Install > Extensions to upload `pkg_bridge35-1.0.0.zip`. Or run: ``` php cli/joomla.php extension:install --path=/path/to/pkg_bridge35-1.0.0.zip ``` The package installs the component (Components > Bridge35 Migrator) and the console plugin "Console - Bridge35 Migrator", which is enabled automatically. ## Use: admin screen 1. **Back up the Joomla 5 site** (files and database). 2. Open Components > Bridge35 Migrator. 3. Enter the Joomla 3 database host, name, user, password and table prefix. They are all in the Joomla 3 `configuration.php`. 4. Click **Check (no changes)**. Fix anything shown in red. Yellow notes are information only. 5. Click **Migrate**. The password is used for this one request and is never saved. ## Use: command line (large sites) ``` export BRIDGE35_SOURCE_PASSWORD='...' php cli/joomla.php bridge35:migrate --host=localhost --database=j3db --user=j3user --prefix=jos_ --dry-run php cli/joomla.php bridge35:migrate --host=localhost --database=j3db --user=j3user --prefix=jos_ ``` If `BRIDGE35_SOURCE_PASSWORD` is not set, the command asks for the password. ## After migrating - Copy the Joomla 3 `images/` folder to the Joomla 5 site. Article image paths are unchanged. - Recreate menus and modules. Category and article ids are the same, so menu items can point at the same ids. - Check System > Global Check-in. ## Rollback The whole migration runs in one database transaction. If any step fails, Bridge35 rolls back and the Joomla 5 database is left unchanged. To undo a migration that **succeeded**, restore the backup you made in step 1. ## Safety - The Joomla 3 database is only read. - Only Super Users can run a migration from the admin screen. The form is CSRF-protected. - The run refuses to start if the target already has articles, tags or custom fields. ## Development ``` composer install vendor/bin/phpunit # unit tests sh build.sh # dist/pkg_bridge35-.zip sh tests/integration/run.sh # real install test; see the header of the script for the Docker mounts SHOTS=1 sh tests/integration/run.sh # same, but migrates through the admin UI and saves docs/screenshots ``` The install test builds a Joomla 3.10.12 database from the official schema, the "Learn Joomla" sample data (copied up to 2,077 articles, so chunked reads are exercised) and `tests/integration/fixture_j3.sql`. It then installs a fresh Joomla 5.4.10 site, installs the package with the Joomla CLI, migrates, and checks 41 things: - row counts, ids, titles and article bodies (checksums) - nested sets and paths - assets and permissions - workflow - tags - fields, including the privacy of user field values - emoji (utf8mb4) - authorship mapping - refusal of a second run - front-end rendering - a real front-end login with a migrated password ## License GNU General Public License version 2 or later.