От стара Joomla към нов сайт (част 2): миграция на данните
В първата част обяснихме защо старият общински сайт (тук под измисленото име novsaitobshtina.bg) трябваше да бъде изграден наново, вместо да се обновява. В тази част е техниката: как инсталирахме нова Joomla в същата база данни, без да пипаме старите таблици, как пренесохме над 2100 статии с чист SQL и кои два капана крият половината съдържание, ако не знаеш за тях.
Стъпка 0: пълен бекъп
Преди първата команда — пълен, проверен бекъп на текущото състояние. База данни и файлове, всеки архив тестван за цялост:
# База данни mysqldump --single-transaction c4example | gzip > db_pre_migrate.sql.gz gzip -t db_pre_migrate.sql.gz # проверка на архива # Файлове (изображения и документи са ~12 GB) tar czf web_files.tar.gz web/ tar tzf web_files.tar.gz > /dev/null # проверка
Бекъпът е валиден само ако е тестван. Архив, който не можеш да разархивираш, не е бекъп — той е фалшиво спокойствие. Затова винаги
gzip -t/tar tzfведнага след създаването.
Стъпка 1: нова Joomla в същата база, но с нов префикс
Ключовото решение, което направи миграцията безопасна: инсталирахме Joomla 6 в същата база данни като стария сайт, но с различен префикс на таблиците. Старите таблици на Joomla 3 останаха недокоснати като резерва и източник на данни, а новият сайт получи чисти свои таблици.
| Таблици | Префикс | Роля |
|---|---|---|
| Стар сайт (Joomla 3) | old_ |
Замразени, източник за миграцията |
| Нов сайт (Joomla 6) | j6_ |
Работният сайт |
Предимствата на този подход:
- Двата сайта виждат едни и същи данни — миграцията е SQL между таблици в една база, без експорт/импорт през мрежата.
- Старите таблици са жива резервна точка — ако нещо в преноса се обърка, оригиналът е на един
SELECTразстояние. - Нулев риск за стария сайт, докато новият се изгражда.
Стъпка 2: пренос на статии и категории с чист SQL
Добрата новина: между Joomla 3 и Joomla 6 структурата на таблиците за съдържание (#__content, #__categories) е почти идентична. Разликите са малко — например премахната колона xreference — така че преносът е директен SQL с внимателен подбор на колоните. Пренесохме над 2100 публикувани статии и 45 категории, запазвайки оригиналните идентификатори и alias-и (важно за URL адресите).
Категориите в Joomla се пазят като nested set (вложено множество с ляв/десен указател за дървовидната структура). При пряк SQL пренос тези указатели трябва да се преизградят, иначе дървото на категориите е счупено. Направихме го с обхождане в предварителен ред (preorder) през кратък PHP скрипт.
Капан №1: статиите се крият заради „нулева“ дата
Първият голям капан ни струва време. След преноса всички статии бяха в базата, публикувани, но сайтът показваше нула. Причината е коварна: в стария сайт статиите имаха publish_down = '0000-00-00 00:00:00' — стар начин да се каже „без крайна дата на публикуване“.
Новата Joomla интерпретира тази нулева дата като дата в миналото — тоест смята статиите за „изтекли“ и ги скрива. Решението:
UPDATE j6_content SET publish_down = NULL WHERE publish_down = '0000-00-00 00:00:00';
Запомнете това при всяка миграция Joomla 3 → 4/5/6: „без край“ вече се пише
NULL, не0000-00-00. Ако след пренос статиите ги „няма“, първо проверетеpublish_down.
Капан №2: часовата зона праща статиите в бъдещето
Вторият капан се появи по-късно, при добавяне на нови статии директно през SQL. Joomla сравнява датата на публикуване publish_up с текущото време в UTC. Ако вмъкнеш нова статия с NOW(), а сървърът е в лятно българско време (UTC+3), новата статия получава дата три часа в бъдещето — Joomla я смята за „още непубликувана“ и я скрива (посетителят вижда 404).
Решението е да задаваш publish_up явно в миналото, не с NOW():
-- НЕ така (дава EEST → бъдеще → скрита статия): INSERT INTO j6_content (..., publish_up) VALUES (..., NOW()); -- А така (явно в миналото, гарантирано видима): INSERT INTO j6_content (..., publish_up) VALUES (..., '2026-08-01 08:00:00');
Стъпка 3: обновяване на PHP
Старият сайт вървеше на PHP 7.4 — версия, която също е извън поддръжка. Joomla 6 изисква съвременен PHP, затова вдигнахме vhost-а на PHP 8.3 през контролния панел (ISPConfig): създаване на нов FPM pool за 8.3 и превключване на сайта към него. Това дава не само съвместимост, но и осезаемо по-бърз сайт.
Стъпка 4: пускане на живо без загуба на изображения
Най-деликатната част — превключването на живо. Изображенията и документите бяха над 8 GB и копирането им би отнело време и рискувало разминаване. Тъй като новият и старият сайт са на една и съща файлова система, използвахме моментално преместване вместо копиране:
- Ядрото на новата Joomla се разположи в docroot-а на сайта.
- Директориите с изображения и качени файлове (
images/,uploaded/) се преместиха (mv) в новата структура — на една файлова система това е мигновено, независимо от обема, защото не копира данни, а само пренасочва указателите.
Затова 8 GB изображения се „преместиха“ за части от секундата.
mvв рамките на един дял не мести байтове — само преименува. Ако беше между два диска, щеше да е копиране и щеше да отнеме минути.
Резултатът от миграцията
| Мигрирано | Количество |
|---|---|
| Статии (публикувани) | над 2100 |
| Категории | 45 |
| Изображения и документи | над 8 GB |
| Пренесени разширения | 0 (умишлено) |
В този момент имахме работещ нов сайт с цялото съдържание — но той изглеждаше като „hello world“. Стандартният шаблон, разбъркана навигация, статии с картинки, които се чупят, дребен разнобоен шрифт. Третата, най-обемна част от поредицата е за тунинга: как от гол нов сайт направихме подреден, съвременен и лесен за четене портал, страница по страница.
Част 2 — Миграция: инсталация и пренос на данните (тази статия)
Част 3 — Тунинг: тема, навигация и съдържание →