Эта запись написана мною в 2014 году. В те времена деревья были высокими, а доллар стоил меньше 40 рублей. С тех пор прошло много времени и многое изменилось. Учитывайте это, читая.
На днях я закончил перенос своего блога с uCoz на WordPress, и теперь напишу небольшую инструкцию по тому, как это сделать. Надеюсь, она вам поможет.
Самое главное и сложное при переносе — перенести базу данных. Настроить старый шаблон на WordPress намного проще, и будет достаточно статьи о создании подобного шаблона для WP, которую я уже написал. Но самое главное — база данных.
Достать данные с сайта uCoz можно с помощью резервного копирования данных, оно доступно по ссылке вашсайт.ру/panel/?a=backup , резервное копирование можно сделать только ночью (дабы не давать лишней нагрузки на сервера в «час пик»), и не чаще раза в неделю. Нас сейчас интересует только дампы баз данных, там можно получить и все загруженные файлы, но с ними вы сможете при необходимости и разобраться сами.
Если у вас нет времени или возможностей заняться переносом своего сайта самостоятельно, то можете обратиться ко мне. Мои контакты тут
После создания и загрузки к себе резервной копии вы получите архив с названием, подобным _bk_idTbDPkVXK.zip, внутри будет ряд txt файлов от разных модулей вашего сайта. Я переносил /blog, /dir, /comments, /gb, но остальные, по примеру этих, перенести будет не проблема.
Рассмотрим файл blog.txt, из названия видно что это данные из модуля блог.
Во всём бекапе 1 строка = 1 запись, поля каждой записи разделены символом |. Вероятно если этот символ встречается в полях, он как-то экранируется, но я не проверял. Встретите такую проблему — вот и проверите. Соответственно нам нужно построчно обрабатывать каждый файл, добавляя записи в WP.
Последовательное значение полей в blog.txt:
id catID year month day pending ontop com_may addtime num_com author title brief message attach files reads rating rate_num rate_sum rate_ip other1 other2 other3 other4 other5 uid sbscr lastmod
Для остальных файлов названия полей можно найти на официальном форуме uCoz в соответствующей теме. Сейчас нам понадобятся далеко не все поля, а только следующие:
- catId — id категории
- years, month, day — для формирование даты, чтобы сохранить последовательность постов (по желанию можно ещё добавить addtime)
- title — заголовок
- message — текст (в зависимости от ваших настроек, ещё может пригодиться brief)
- reads — кол-во просмотров
- othre1, other2 — у меня эти поля означали keywords и description. Вам могут и не понадобиться.
Нам нужно написать примерно такую функцию:
function getBlog() { $data = file_get_contents('ПУТЬ К ФАЙЛУ blog.txt'); $data = preg_split('/[^\\\]\n/m',$data); $n = 0; foreach ($data as $post) { if (!isset($post[1])) break; $n++; $post = explode('|',$post); switch ($post[1]) { case 1: $cat_id = 9; break; case 2: $cat_id = 4; break; default: $cat_id = 2; // задаём категорию по-умолчанию } if (strlen($post[3]) == 1) $post[3] = '0'.$post[3]; if (strlen($post[4]) == 1) $post[4] = '0'.$post[4]; $source = array( 'post_title' => $post[11], // заголовок материала. 'post_content' => $post[13], // message 'post_status' => 'publish', // статус (опубликовано) 'post_author' => 1, // id автора 'post_category' => array($cat_id), // массив id категорий, у нас категория только одна 'post_date' => $post[2].'-'.$post[3].'-'.$post[4], // дата публикации 'post_type' => 'blog', // post type, у меня создан отдельный blog, у вас же скорее всего это значение будет post ); $post_id = wp_insert_post($source); // функция добавления записи update_post_meta( $post_id, 'post_views_count', $post[16] ); // обновляем мета информацию о записях, вам это может быть не нужно update_post_meta( $post_id, '_aioseop_keywords', $post[21] ); update_post_meta( $post_id, '_aioseop_description', $post[22] ); } echo $n; }
Обратите внимание на блок switch ($post[1])
, id категорий у вас не будут совпадать с wordpress, поэтому вам придётся прописать соответствие старых и новых id категорий (естественно предварительно их нужно будет создать на WP). Возможен и другой подход, которым я пользуюсь сейчас: категории модулей содержатся в отдельных файлах (к примеру ld_ld.txt для каталога файлов), их предварительно можно перенести специальным скриптом, который даст нам такое соответствие между ucoz id и id категории в WP.
Следующий блок:
if (strlen($post[3]) == 1) $post[3] = '0'.$post[3]; if (strlen($post[4]) == 1) $post[4] = '0'.$post[4];
Преобразует значение месяцев и дней к нужному WP формату.
update_post_meta
у меня переносит количество записей, keywords и description, у вас могут быть другие значения в этих функциях, или они могут не требоваться вовсе. Остальное должно быть более-менее понятно из комментариев.
Функцию нужно подключить к вашему wp сайту и один раз запустить на любой из страниц.
Будьте внимательны! Перед окончательным запуском протестируйте функцию на 1-2х записях, можно просто в конце цикла foreach ($data as $post) поставить return, после чего проверьте верно ли всё добавилось.
Перенос других контент-модулей аналогичен, и если у вас получилось с блогом, то не составит труда сделать и с любым другим. Поэтому отдельно остановлюсь только на комментариях. Их резервная копия имеет следующую структуру:
commentID moduleID (1=>'blog',2=>'news',3=>'publ',4=>'photo',5=>'load',6=>'dir',7=>'board') materialID pending addTime user name email www ip message answer userID parentID rate rateUserIDs
Нам понадобятся только moduleID, materialID, user, name, email, message, parentID, addTime. Так же нам понадобится один или несколько файлов от контент-модулей, комментарии к которым мы сохраняем, для определения к какой записи нам прикреплять комментарий. Я переносил комментарии только для модуля blog, но реализовать для нескольких модулей не многим сложнее.
Алгоритм примерно такой: разбираем blog.txt для соотношения id записи и его заголовка, затем разбираем comments.txt, перед каждым добавление определяем по id название из blog.txt, а по этому названию находим id записи в WordPress. После добавления комментария записываем его id в специальный массив, чтобы можно было далее правильно обработать ответы на этот комментарий.
Код, который получился у меня:
function getComments() { $dataBlog = file_get_contents('ПУТЬ К blog.txt'); $dataBlog = preg_split('/[^\\\]\n/m',$dataBlog); $blog = array(array()); // разбираем blog.txt foreach ($dataBlog as $postBlog) { $postBlog = explode('|',$postBlog); if (!isset($postBlog[1])) break; $blog[$postBlog[0]] = $postBlog[11]; // по id в массиве у нас становится доступно название записи } $data = file_get_contents('ПУТ К comments.txt'); $data = preg_split('/[^\\\]\n/m',$data); $n = 0; $comments = array(); foreach ($data as $post) { if (!isset($post[1])) break; $post = explode('|',$post); if ($post[1] == 1) { $commentOldId = $post[0]; // с помощью этой функции мы получаем id записи в WP по её названию $page = get_page_by_title( $blog[$post[2]], 'ARRAY_A', 'blog' ); $commentId = $page['ID']; $commentDate = date('Y-m-d G:i:s', $post[4]); // в зависимости от того, был ли авторизован автор комментария, или нет, его имя хранится в разных полях (user или name) if ($post[6] != '') { $commentAuthor = $post[6]; } if ($post[5] != '') { $commentAuthor = $post[5]; } // поле email может быть пусто, поэтому ставим для таких случаев адрес по-умолчанию $commentEmail = $post[7]; $userId = 0; if ($commentEmail == '') { if ($commentAuthor == 'ВАШ НИК') { $commentEmail = 'ВАШ EMAIL'; $userId = 1; // id вашего пользователя в WP } else { $commentEmail = 'noemail@site.ru'; // email по-умолчанию } } $commentMessage = $post[10]; // тут получаем id комментария - родителя $commentParent = $post[13]; if ($commentParent != 0) { $commentParent = $comments[$commentParent]; } $n++; $data = array( 'comment_post_ID' => $commentId, 'comment_author' => $commentAuthor, 'comment_author_email' => $commentEmail, 'comment_content' => $commentMessage, 'comment_type' => '', 'comment_parent' => $commentParent, 'user_id' => $userId, 'comment_date' => $commentDate, 'comment_approved' => 1, ); $id = wp_insert_comment($data); // при добавлении комментария записываем соответствие его id в uCoz id-шнику в WP $comments[$commentOldId] = $id; } } echo $n; }
Думаю, его особо объяснять не нужно.
Важным вопросом при переносе сайта с движка на движок является сохранение структуры url. Лично я решил, что поскольку записей в блоге у меня не так много, можно не сохранять полностью структуру (она в uCoz мне и так не нравится), а сделать переадресацию со старых страниц на новые. Лучше всего для поисковиков, кончено, оставить старые адреса, но редирект им тоже подойдёт.
Нужно просто дописать в .htaccess файл соответствующие правила 301 редиректа, пример:
Redirect 301 /index/0-2 /about-me
Это не проблема, если адресов не очень много. Если у вас переносится большой портал — написание таких правил можно автоматизировать, или нужно будет придумать как сохранить структуру.
Прописывать редирект чисто в .htaccess для крупных сайтов плохой вариант — чем больше редиректов, тем заметнее это будет грузить сервер. Можно сделать иначе: через дополнительное поле добавлять к каждому материалу на WP id от материала на uCoz. Затем поставить на странице 404 от WP свой обработчик (ибо старые адреса с uCoz будут выводить на 404 ошибку на WP) и если url совпадает со структурой url на uCoz — мы из адреса достаём id и ищем соответствующую этому id запись, на которую делаем 301 редирект средствами PHP.
Как связаться с автором статьи? Не отвечает на письма!!!
Уже ответил вам. К сожалению, почту я смотрю не моментально.
Спасибо!!!
Ответил Вам на почту!!!!!!!
А что меньше будет грузить сервер — редирект через PHP или htaccess? У меня на сайте где-то 2500 страниц.
Если у вас нет много трафика — не стоит об этом думать.
Но сам факт прописывания 2.5 тысяч правил редиректа в htaccess, мне кажется, фиговым решением. Ведь регурярным выражением сделать это не получится.
все решил проблему, а как быть с переносом непосредственно созданных страниц?
Всё аналогично.
С точки зрения uCoz, материалы модуля страницы сайта пишутся в файл site.txt
С точки зрения WordPress — страницы это стандартный тип записей, «page». И перенос данных в него практически ничем не отличается.
Так все же можете подсказать, что нужно поменять в функции, чтобы перенести страницы?
Я ведь уже подсказал. Просто копированием кода из поста тут не обойтись, его нужно дописывать под конкретно ваш сайт. В статье только образец, который стоит использовать.
Так что чтобы правильно перенести материалы, нужны некоторые знания как PHP, так и WordPress.
Если у вас их нет — вы можете обратиться ко мне и я перенесу ваш сайт.
вроде получилось, но почему то все записи задвоило мне
Подскажите пожалуйста, куда собственно код вставлять? я делал отдельный php файл в директории с сайтом, и вызывал его в браузерной строке, но ничего не происходит
Самый простой и не очень правильный вариант — подключить файл с любого шаблона. Тогда код в нём сможет работать и будет видеть функции от WP.
Вы пишите о добавлении времени публикации addtime, я так понимаю нужно добавлять еще конвертацию Unix. Если не сложно можете описать что нужно добавить в post_time
В модуле publ дата только в формате 1400658881 epoch, можно ли добавить вывод как в блоге или новостях? или как это значение преобразовать в формат WP. Еще раз спасибо за инструкцию
Сорри за спам. но удалось разобраться, чтобы полностью указать время добавления
‘post_date’ => isset($post[5]) ? date(«Y-m-d H:i:s», $post[5]) : »,
Да, в разных модулях дата представлена по-разному. Два варианта — как в посте, когда есть три поля на число, месяц и год, и второй — когда время timestamp.
Во втором случае достаточно сделать date(‘Y-m-d G:i:s’, $post[5]), как вы и написали.
update_post_meta( $post_id, ‘post_views_count’, $post[16] ); — это я так понимаю счетчик просмотра постов. почему-то после экспорта все равно выходит 0 просмотров. что может быть не так? спасибо! инструкция просто огонь ))
Проверьте что в переменной $post[16]. Для разных модулей — разный номер поля, в котором хранится кол-во просмотров.
спасибо! статья помогла перенести пользователей.
Здравствуйте, подскажите пожалуйста, если у меня на юкоз сайте имеется тиц и пр, после переноса на WP есть ли возможность сохранить эти показатели?
Добрый день!
Эти показатели актуальны в первую очередь для домена. Если домен останется с вами (то есть если это ваш домен, а не юкоза типа site.ucoz.ru), то всё будет в порядке.
Объясните плиз, что делает выражение «/[^\\\]\n/m», три обратных слеша смущают, что это?
‘/[^\\\]\n/m’ это регулярное выражение
три обратных слеша из-за особого смысла \ в строках и регулярных выражениях.
В строках \ экранирование символа. Т.е. чтобы в строку поставить кавычку, и она воспринималась кавычкой, а не концом строки — нужно написать \’. Чтобы написать сам слеш, так же нужно перед ним другой — получается \\
В регулярных выражениях получается та же фигня, ибо символ обратного слеша имеет специальный смысл.
Что добавляет ещё один обратный слеш в конструкцию.
Вообще регулярных выражений нужно стараться избегать, проблем с ними море.
но там же три слеша. получается, экранируем сам обратный слеш , а после этого еще и ]? Что представляет собой шаблон /[^\\\]\n/m не могу догнать…
Я вспомнил.
[^\\\] — отрицание символа \, вероятно квадратные скобки тут не нужны, будет работать и без них.
\n — перенос строки как раз.
В бекапе 1 строка — 1 запись (1 комментарий к примеру) с кучей полей.
Если текст комментария содержит перенос строки, то перед переносом стоит \
Таким образом чтобы разделить файл на массив комментариев, нужно делить его по переносу строки, перед которым нет \.
Да, возможно объяснение выше неверно, ибо я сам уже плохо помню и редко использую регулярки.
В любом случае — суть в разбитии входной переменной на массив из подстрок.
Входная переменная имеет множество подстрок, разделённых переносом строки (символом \n)
Очень классная статья. СПАСИБО.
Вроде получается по-тихоньку готовлюсь к переезду. Сложный проект, пришлось сначала 240 категорий через mysql импортировать, теперь с записями разбираюсь, вот, кстати, код для дат из unix времени в каталоге файлов, если надо кому:
‘post_date’ => date(«Y-m-d H:i:s», $post[5]),
Категории нужно было не вручную, а автоматически переносить. С помощью функции wp_insert_term().
И не нужно ничего загружать прямо в базу, в WP реализованы все нужные функции.
Даты: выше в коде у меня было написано тоже самое:
$commentDate = date(‘Y-m-d G:i:s’, $post[4]);
О, не заметил, комментарии я не переношу, поэтому не смотрел. У меня теперь другая проблема. В описании материалов есть «невидимые» переводы строк /r/n, если их оставить, то код работает неправильно, так как работает по строкам, если его заменить на видимый /r/n, то вордпресс добавляет только rn, если заменить на BR, то глюки в некоторых местах, может есть какое-то решение?
Когда я столкнулся с этой проблемой — я стал разбивать регуляркой, в которой указано количество полей информации в одной строке. Хотя мне почему-то кажется это плохим решением.
Мне это сложно, пока решил заменить \r\n на !—perenos—, а потом в базе данных замену сделать на \r\n.
Заменять можно не в базе, а прямо перед wp_insert_post.
При такой замене заменятся же все \r\n, а не только те переносы строк, что в описаниях материалов.
В материалах они закоментированы косой чертой, получается так можно их искать \\\r\n
Да, можно и так
Кстати, аналогично нужно будет поступить с символами | в полях, описывающих прикреплённые изображения/файлы.
А можно подробнее как вызвать функцию?
Добавил код в functions.php
Добавил ?php getBlog(); ? в шаблон записей формата «Ссылка»
Открыл такую запись, ничего не произошло.
Вы указали путь к файлу бек-апа модуля?
Не очень понятно про редирект. Это для каждой страницы такое прописывать?
Например, старая страница была
http://www.site.ru/index/blog_mir_bez_granic/0-240
А новая
http://www.site.ru/blog_mir_bez_granic/
Да, либо для каждой отдельно, либо по общему правилу — там ведь поддерживаются регулярные выражения.
Добрый день , занимаетесь переносом сайтов с ucoz на wordpress ?
Добрый день
Да, занимаюсь. На странице контактов есть способы связи со мной.
А возможно воспользоваться Вашей помощью для переноса сайта с ucoz на WP ? Разумеется не бесплатно.
Да, конечно, мои контакты тут
ухты ухты, а я и не знал, что есть офф инфа о значении полей. я их начинал реверс инженирингом выведывать, но так до конца и не довел свою задумку…
Нужно было просто погуглить получше)