Когда заказывают переделать сайты с «историей», приходится перетаскивать имеющиеся публикации на новый сайт. Хочу поделиться некоторыми моментами, связанными с программированием такого рода задач в Drupal.
Вот типовые операции, которые возникают при переносе статьи:
- Загрузка картинки(-нок) в специальные поля публикации, экспорт картинок из текста статьи;
- сохранение старого url;
- сохранение текста и тизера статьи;
- создание и сохранение объекта публикации (node);
- заполнение каких то дополнительных полей.
Когда у вас 15-20 статей, то данные операции производятся вручную. А вот когда число статей переваливает за сотню, то время ручной работы сравнивается с временем создания скрипта для переноса. А если вы создаёте такие скрипты регулярно, то порогом может стать необходимость скопировать всего 40-50 статей. Вообще, я предпочитаю, чтобы переносом занимались «специально обученные люди». :)
Что я хочу получить от программы?
Я задаю url переносимой с сайта-донора статьи, жму «ОК» и получаю статью уже на сайте под Drupal. Картинки в процессе переноса тоже копируются в папку пользовательских файлов нового сайта.
Что отличает разные источники друг от друга?
Каждый сайт имеет уникальную верстку и набор атрибутов публикаций. Поэтому вам нужно определить, что вы сможете легко извлечь из HTML кода, опираясь на характерные фрагменты шаблона. Т.е. вначале надо изучить как выглядит статья в шаблоне сайта-донора.
К примеру, заголовок статьи обрамлен тегом H1, а тело статьи находится внутри <div class=»content»>…</div>.
С H1 проблем, как правило, не возникает. А вот текст публикации может содержать случайные вкрапления <div></div>, содержать ошибки HTML, не закрытые теги и т.п. Надежнее использовать какой либо идущий за текстом сегмент шаблона, чем выискивать закрывающий </div>, соответствующий открывающему <div class=»content»>.
Следующая задача — выяснить, что является минимальным набором атрибутов статьи, и как от этого меняется структура шаблона.
Конкретный пример
Я писал экспорт для новостей с сайта delovoymir2003.ru. Общее количество — 124 новости ясно сигнализировало, что вручную ими заниматься не стоит.
Это пример типичной статьи. Видны такие атрибуты, как — заголовок, дата публикации, изображение, текст статьи.
Максимальный вариант также мог содержать — тизер статьи (сжатое изложение), а сама статься могла содержать изображения.
Инструменты для разбора HTML
HTML — это частный случай XML, но ошибки шаблона и отклонения от спецификации не дают использовать для разбора HTML какие либо XML парсеры. Я давно разработал и использую набор утилит для парсинга HTML текстов. Когда логика работы формулируется примерно так:
- извлечь текст, обрамленный указанными скалярами,
- перейти к следующему образцу в тексте,
- извлечь строковое значение, если оно есть в указанном словаре
и т.д, то этот класс помогает сократить код. Читайте про него в отдельной статье, здесь разбирать и приводить его код не буду.
Загрузка картинки(-нок) в специальные поля публикации.
Если у вас есть image поле в сохраняемой публикации (node), то ваша задача состоит в том, чтобы перейти от url картинки к объекту друпала — file, соответствующему этой картинке. Нужно вам это или нет — зависит от конструкции публикации, тип которой вы используете для приема статьи при импорте.
К примеру, вы переносите карточки товаров или новости, в которых есть картинка-обложка. В описанных случаях вы наверняка добавите в публикацию поле для загрузки изображения.
Эта операция будет содержать довольно много рутинных проверок и логики. Подробно я изложил этот процесс в статье — грузим картинку в поле image в Drupal.
Сохранение старого url статьи.
Чтобы поисковые машины не растерялись, надо сохранить прежний url статьи. В бесконечной веренице определений полей объекта node, синоним страницы задаётся вот так:
1 2 3 4 5 6 7 8 9 10 11 12 |
//дербаним урл статьи $site = parse_url($_POST['url']); $node = new stdClass(); ... $node->path = array( 'pathauto' => 0, //идущий в начале адреса слэш нужно удалить 'alias' => substr($site['path'], 1) ); //сохраняем статью node_save($node); |
Сохранение текста и тизера публикации.
Если вам удалось извлечь из источника короткое описание статьи, то я покажу как его сохранить в поле body. Это поле имеет тип «Полный и краткий текст», т.е. может хранить два текста.
1 2 3 4 5 6 7 8 |
$node = new stdClass(); ... $node->body = array('und' => array(0 => array( 'value' => "Полный текст статьи", 'summary' => "Краткое описание, тизер статьи", 'format' => 'full_html', ))); node_save($node); |
Заполнение дополнительных полей публикации.
Чтобы вам не пришлось сшивать из кусочков, я приведу более развернутый пример (только без поля типа image). Описание объекта публикации я уже разбирал ранее, если хотите ещё более полное описание, можете прежде с ним ознакомиться.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
$node = new stdClass(); $node->uid = $user->uid; //автор $node->title = "Заголовок статьи"; $node->status = 1; //статус - статья опубликована $node->type = 'article'; //тип статьи $node->language = 'ru'; //язык $node->created = $dtm; //дата создания UNIX_TIMESTAMP //текст статьи и её тизер $node->body = array('und' => array(0 => array( 'value' => $text_full, 'summary' => $text_intro, 'format' => 'full_html', ))); //дополнительно текстовое поле //сначала язык (und), потом индекс (0), потом - значение //индекс используется, когда поле содержит много значений $node->field_lenta = array('und' => array(0 => array( 'value' => 'news' ))); //синоним адреса $node->path = array( 'pathauto' => 0, 'alias' => substr($site['path'], 1) ); //сохранить объект node_save($node); |
Если собрать все элементы пазла получится несколько сотен строк на PHP. Большая часть из них — это утилиты и функции с постоянным кодом. Написав экспорт статей под drupal один раз, вы будете заимствовать 90% кода в следующий раз.