0887 371 498 support@itservice-bg.net
От стара Joomla към нов сайт (част 2): миграция на данните
13.08.2026 · Самуил Арсов · Hosting

От стара 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“. Стандартният шаблон, разбъркана навигация, статии с картинки, които се чупят, дребен разнобоен шрифт. Третата, най-обемна част от поредицата е за тунинга: как от гол нов сайт направихме подреден, съвременен и лесен за четене портал, страница по страница.

📚 Поредица: от стара Joomla към нов общински сайт
← Част 1 — Анализ на стария сайт
Част 2 — Миграция: инсталация и пренос на данните (тази статия)
Част 3 — Тунинг: тема, навигация и съдържание →