Я решил что сайт слишком уныл, поэтому попросил нарисовать мне всяких животных, которых вы видите
10.07.2014

Перенос сайта с uCoz на WordPress

Перенос uCoz на WordPress

На днях я закончил перенос своего блога с 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.

Категория: CMS Wordpress Система uCoz Просмотров: 23179 42 комментария

Комментарии

42 комментария

Али 23.01.2017 в 20:09

А что меньше будет грузить сервер — редирект через PHP или htaccess? У меня на сайте где-то 2500 страниц.

z17 24.01.2017 в 15:04

Если у вас нет много трафика — не стоит об этом думать.

Но сам факт прописывания 2.5 тысяч правил редиректа в htaccess, мне кажется, фиговым решением. Ведь регурярным выражением сделать это не получится.

Сергей 04.12.2016 в 12:53

все решил проблему, а как быть с переносом непосредственно созданных страниц?

z17 05.12.2016 в 02:33

Всё аналогично.
С точки зрения uCoz, материалы модуля страницы сайта пишутся в файл site.txt

С точки зрения WordPress — страницы это стандартный тип записей, «page». И перенос данных в него практически ничем не отличается.

Сергей 05.12.2016 в 19:01

Так все же можете подсказать, что нужно поменять в функции, чтобы перенести страницы?

z17 06.12.2016 в 03:03

Я ведь уже подсказал. Просто копированием кода из поста тут не обойтись, его нужно дописывать под конкретно ваш сайт. В статье только образец, который стоит использовать.
Так что чтобы правильно перенести материалы, нужны некоторые знания как PHP, так и WordPress.
Если у вас их нет — вы можете обратиться ко мне и я перенесу ваш сайт.

Сергей 04.12.2016 в 12:11

вроде получилось, но почему то все записи задвоило мне

Сергей 04.12.2016 в 11:49

Подскажите пожалуйста, куда собственно код вставлять? я делал отдельный php файл в директории с сайтом, и вызывал его в браузерной строке, но ничего не происходит

z17 05.12.2016 в 02:31

Самый простой и не очень правильный вариант — подключить файл с любого шаблона. Тогда код в нём сможет работать и будет видеть функции от WP.

gloomya 12.04.2016 в 20:38

Вы пишите о добавлении времени публикации addtime, я так понимаю нужно добавлять еще конвертацию Unix. Если не сложно можете описать что нужно добавить в post_time

gloomya 12.04.2016 в 22:35

В модуле publ дата только в формате 1400658881 epoch, можно ли добавить вывод как в блоге или новостях? или как это значение преобразовать в формат WP. Еще раз спасибо за инструкцию

gloomya 12.04.2016 в 22:52

Сорри за спам. но удалось разобраться, чтобы полностью указать время добавления
‘post_date’ => isset($post[5]) ? date(«Y-m-d H:i:s», $post[5]) : »,

z17 13.04.2016 в 01:25

Да, в разных модулях дата представлена по-разному. Два варианта — как в посте, когда есть три поля на число, месяц и год, и второй — когда время timestamp.
Во втором случае достаточно сделать date(‘Y-m-d G:i:s’, $post[5]), как вы и написали.

gloomya 28.03.2016 в 17:25

update_post_meta( $post_id, ‘post_views_count’, $post[16] ); — это я так понимаю счетчик просмотра постов. почему-то после экспорта все равно выходит 0 просмотров. что может быть не так? спасибо! инструкция просто огонь ))

z17 29.03.2016 в 04:33

Проверьте что в переменной $post[16]. Для разных модулей — разный номер поля, в котором хранится кол-во просмотров.

Misha 01.09.2015 в 09:34

спасибо! статья помогла перенести пользователей.

Dmitry 06.08.2015 в 13:43

Здравствуйте, подскажите пожалуйста, если у меня на юкоз сайте имеется тиц и пр, после переноса на WP есть ли возможность сохранить эти показатели?

z17 06.08.2015 в 21:35

Добрый день!

Эти показатели актуальны в первую очередь для домена. Если домен останется с вами (то есть если это ваш домен, а не юкоза типа site.ucoz.ru), то всё будет в порядке.

LEX 21.05.2015 в 23:53

Объясните плиз, что делает выражение «/[^\\\]\n/m», три обратных слеша смущают, что это?

z17 22.05.2015 в 00:18

‘/[^\\\]\n/m’ это регулярное выражение

три обратных слеша из-за особого смысла \ в строках и регулярных выражениях.
В строках \ экранирование символа. Т.е. чтобы в строку поставить кавычку, и она воспринималась кавычкой, а не концом строки — нужно написать \’. Чтобы написать сам слеш, так же нужно перед ним другой — получается \\
В регулярных выражениях получается та же фигня, ибо символ обратного слеша имеет специальный смысл.
Что добавляет ещё один обратный слеш в конструкцию.

Вообще регулярных выражений нужно стараться избегать, проблем с ними море.

LEX 22.05.2015 в 08:21

но там же три слеша. получается, экранируем сам обратный слеш , а после этого еще и ]? Что представляет собой шаблон /[^\\\]\n/m не могу догнать…

z17 23.05.2015 в 00:28

Я вспомнил.
[^\\\] — отрицание символа \, вероятно квадратные скобки тут не нужны, будет работать и без них.
\n — перенос строки как раз.

В бекапе 1 строка — 1 запись (1 комментарий к примеру) с кучей полей.
Если текст комментария содержит перенос строки, то перед переносом стоит \

Таким образом чтобы разделить файл на массив комментариев, нужно делить его по переносу строки, перед которым нет \.

z17 22.05.2015 в 00:24

Да, возможно объяснение выше неверно, ибо я сам уже плохо помню и редко использую регулярки.

В любом случае — суть в разбитии входной переменной на массив из подстрок.
Входная переменная имеет множество подстрок, разделённых переносом строки (символом \n)

Максим 06.04.2015 в 01:42

Очень классная статья. СПАСИБО.

Ильдар Хакимов 08.12.2014 в 04:34

Вроде получается по-тихоньку готовлюсь к переезду. Сложный проект, пришлось сначала 240 категорий через mysql импортировать, теперь с записями разбираюсь, вот, кстати, код для дат из unix времени в каталоге файлов, если надо кому:

‘post_date’ => date(«Y-m-d H:i:s», $post[5]),

z17 08.12.2014 в 04:53

Категории нужно было не вручную, а автоматически переносить. С помощью функции wp_insert_term().
И не нужно ничего загружать прямо в базу, в WP реализованы все нужные функции.

Даты: выше в коде у меня было написано тоже самое:
$commentDate = date(‘Y-m-d G:i:s’, $post[4]);

Ильдар Хакимов 08.12.2014 в 19:38

О, не заметил, комментарии я не переношу, поэтому не смотрел. У меня теперь другая проблема. В описании материалов есть «невидимые» переводы строк /r/n, если их оставить, то код работает неправильно, так как работает по строкам, если его заменить на видимый /r/n, то вордпресс добавляет только rn, если заменить на BR, то глюки в некоторых местах, может есть какое-то решение?

z17 08.12.2014 в 22:10

Когда я столкнулся с этой проблемой — я стал разбивать регуляркой, в которой указано количество полей информации в одной строке. Хотя мне почему-то кажется это плохим решением.

Ильдар Хакимов 09.12.2014 в 00:29

Мне это сложно, пока решил заменить \r\n на !—perenos—, а потом в базе данных замену сделать на \r\n.

z17 09.12.2014 в 01:04

Заменять можно не в базе, а прямо перед wp_insert_post.

При такой замене заменятся же все \r\n, а не только те переносы строк, что в описаниях материалов.

Ильдар Хакимов 09.12.2014 в 03:14

В материалах они закоментированы косой чертой, получается так можно их искать \\\r\n

z17 09.12.2014 в 03:17

Да, можно и так

Кстати, аналогично нужно будет поступить с символами | в полях, описывающих прикреплённые изображения/файлы.

Ильдар Хакимов 19.10.2014 в 02:32

А можно подробнее как вызвать функцию?

Добавил код в functions.php

Добавил ?php getBlog(); ? в шаблон записей формата «Ссылка»

Открыл такую запись, ничего не произошло.

z17 20.10.2014 в 01:35

Вы указали путь к файлу бек-апа модуля?

Виктория 03.10.2014 в 11:42

Не очень понятно про редирект. Это для каждой страницы такое прописывать?

Например, старая страница была
http://www.site.ru/index/blog_mir_bez_granic/0-240

А новая
http://www.site.ru/blog_mir_bez_granic/

z17 03.10.2014 в 11:52

Да, либо для каждой отдельно, либо по общему правилу — там ведь поддерживаются регулярные выражения.

Сергей 01.10.2014 в 07:04

Добрый день , занимаетесь переносом сайтов с ucoz на wordpress ?

z17 01.10.2014 в 11:14

Добрый день
Да, занимаюсь. На странице контактов есть способы связи со мной.

Евгений 06.09.2014 в 00:22

А возможно воспользоваться Вашей помощью для переноса сайта с ucoz на WP ? Разумеется не бесплатно.

z17 06.09.2014 в 16:22

Да, конечно, мои контакты тут

Sleepwalker 07.08.2014 в 22:16

ухты ухты, а я и не знал, что есть офф инфа о значении полей. я их начинал реверс инженирингом выведывать, но так до конца и не довел свою задумку…

z17 08.08.2014 в 01:57

Нужно было просто погуглить получше)

Добавить комментарий