# K2Bridge: K2 to Joomla 5 migrator Move legacy K2 items into native Joomla articles, category trees, custom fields and tags. Tested with the included fixture on Joomla 5.4.10, PHP 8.3 and MariaDB. Use a fresh, disposable target first, and back up both sites before migration. ## Scope and limits - Items become articles, including text, publication state, dates, aliases, hits and featured flags. Article IDs are kept. Categories and tags receive new IDs, and their article references are mapped. Existing K2 routes and SEF URLs are not redirected or guaranteed; rebuild menus and redirects separately. - Extra field groups, definitions, choice options and item values become core custom fields. Test field display and any unusual K2 field types on staging. - Categories and tags are reconstructed in the target. - Images become references to K2 cached image paths. Copy the corresponding `media/k2/items/cache` files yourself; this tool does not transfer files. - Attachments become download links appended to article text. Copy `media/k2/attachments` yourself. No attachment binaries are transferred. - Comments are only counted and logged. Their text is **not copied or archived**. Keep the legacy database or export comments separately. - Galleries, video plugins, menus, modules, templates, permissions and other extension data are not migrated. Embedded plugin markup may need manual work. - Users and passwords are not copied. Authors match existing target users by email, with unmatched authors assigned to the first target user by ID. - Requires a target with no articles. Use a fresh target without custom fields, categories or tags of your own; migration is not an incremental sync or a repeatable upsert. Reserved Joomla root category/tag IDs require remapping. - Source K2 tables and the Joomla users table must be available. A database account with SELECT access is sufficient; the source is never modified. ## Build and install Install PHP dependencies for development using `composer install`, then run `sh build.sh` (or `pwsh build.ps1` on Windows). Upload `dist/pkg_k2bridge-1.0.1.zip` through **System > Install > Extensions**, or run: ```sh php cli/joomla.php extension:install --path=/path/to/pkg_k2bridge-1.0.1.zip -n ``` The package installs the administrator component and enables its console plugin. The administrator screen is under Components > K2Bridge Migrator. CLI is preferred for large sources, avoiding web request timeouts: ```sh export K2BRIDGE_SOURCE_PASSWORD='your-source-database-password' php cli/joomla.php k2bridge:migrate --host=127.0.0.1 --database=legacy --user=reader --prefix=jos_ --dry-run -n php cli/joomla.php k2bridge:migrate --host=127.0.0.1 --database=legacy --user=reader --prefix=jos_ -n ``` Review the dry run and staging front end before running on your intended target. Use `--no-attachments` to omit download links and `--no-comments` to omit counting comments. No comments are archived by either mode. ## Rollback Migration writes run in one target transaction. Exceptions roll it back; dry run executes the pipeline and rolls it back deliberately. Use transactional InnoDB tables. After a successful commit, restore your target database backup to undo the migration. Uninstalling the extension does not undo migrated content. Restore or remove manually copied media separately; preserve the source until verified. ## Real validation The unit suite uses Composer PSR-4 to load the shipped PHP under `com_k2bridge/admin/src`; there is no Python substitute. On Windows the base image's Composer wrapper invokes another PHP version; use `php /usr/bin/composer.phar install --no-interaction` inside this image. ```text docker run --rm -v :/app -w /app bridge35-test:base php vendor/bin/phpunit docker run --rm -v :/app -w /app bridge35-test:base sh build.sh docker run --rm -v :/app -v C:\Users\sammy\brain-runner\work\dl-joomla5\j5.zip:/j5.zip:ro bridge35-test:base sh /app/tests/integration/run.sh ``` Quote Windows mount arguments in PowerShell. The integration harness builds the current checkout in the container, starts an isolated database, installs Joomla, installs the actual package, runs dry and live migration, checks database results and requests a migrated article through Joomla's HTTP front end. Its databases exist only inside the disposable container. No host database is touched. ## Screenshot reproduction Run the same install test in the existing screenshot image (Node and Chromium): ```text docker run --rm -e K2BRIDGE_SCREENSHOTS=1 -v :/app -v C:\Users\sammy\brain-runner\work\dl-joomla5\j5.zip:/j5.zip:ro bridge35-test:shots sh /app/tests/integration/run.sh ``` This installs pinned Playwright Core into the disposable container, logs into the fresh Joomla administrator, checks the source, migrates through the real UI, captures five pages, then runs the same database and front-end assertions. The normal base-image command tests CLI migration. Only fixture credentials are used. Screenshots are unedited full-page browser captures; hashes and URLs are recorded in `build/screenshots/provenance.json`. Verification writes to ignored `build/screenshots/` so repeated runs leave the checkout clean. To refresh the listing assets, add `-e K2BRIDGE_SCREENSHOT_DIR=/app/docs/screenshots` to the Docker command, then review and commit the images and provenance together. The committed listing captures are in `docs/screenshots/`. No image generator is used. The fixture contains media references but no image or attachment binaries. The front-end capture deliberately shows that limitation, including the broken image; a download link alone does not mean its file was transferred. Validation in this task: PHPUnit exited 0 (18 tests, 86 assertions). The normal base-image install command above and the screenshot-image command both exited 0 and printed `RESULT: 24 passed, 0 failed`. Independent reviewer confirmation that screenshots are real and claims supported is pending; this is not self-certified.