Миграция на Drupal и интеграции с 1С, CRM и почтой без потери SEO

Переезд сайта на Drupal: коробки с контентом едут по конвейеру из старого покосившегося здания в новое современное здание с символом-каплей

Когда сайт стоит переносить, а когда дешевле собрать заново

Меня зовут Евгений Семёнов, я технический директор ITfresh — мы занимаемся IT-аутсорсингом для московских компаний до пятидесяти рабочих мест, держим собственные серверы в дата-центре МТС и уже больше пятнадцати лет разгребаем чужие сайты вместе с инфраструктурой. Это третья статья серии про Drupal: в первой был разбор самой CMS, во второй — регламент развёртывания в продакшен. Сегодня — самая дорогая и самая недооценённая часть любого проекта: переезд существующего сайта и его встраивание в контур компании.

Первый вопрос, который я задаю клиенту, принёсшему «переведите нас на Drupal», — не «с чего переезжаем», а «сколько у вас контента и насколько он структурирован». Потому что миграция — это не про технологию, а про объём. Наш рабочий критерий выглядит так:

  • До 30–50 страниц (визитка, несколько услуг, контакты, десяток новостей). Переносим руками: редактор открывает старую страницу, копирует текст в новую, правит вёрстку. Один человек за день-два. Писать для такого объёма автоматизацию — выбрасывать деньги: отладка конвейера займёт больше, чем ручной перенос.
  • От нескольких сотен однотипных записей — карточки врачей, практик юрфирмы, товаров, объектов недвижимости, статей базы знаний. Здесь руками уже нельзя: человек на третьей сотне начинает ошибаться, а любая правка структуры («давайте добавим поле „стаж“») означает повторный проход по всему массиву. Только Migrate API, только воспроизводимый конвейер.
  • Между ними — серая зона, где решает структура. Сто страниц с произвольной вёрсткой дешевле перенести руками, чем сто карточек с десятью полями каждая — машиной.

Отдельный случай, который мы в 2026 году встречаем всё ещё регулярно, — старые сайты на Drupal 7. Семёрка официально закончилась 5 января 2025 года, обновлений безопасности для неё нет, и для таких сайтов вопрос «переносить или нет» не стоит: переносить обязательно. Хорошая новость в том, что это единственный сценарий, под который в ядре есть штатный путь: модули migrate_drupal и migrate_upgrade умеют прочитать базу семёрки напрямую и разложить её по сущностям Drupal 11. Плохая новость — штатный путь закрывает типовые узлы, таксономии и пользователей, а всё, что на старом сайте было накручено кастомными модулями и Views с хитрой логикой, всё равно придётся переписывать.

И последний критерий, про который стесняются говорить подрядчики: иногда переносить нечего. Если сайт клиента — это десять страниц маркетингового текста пятилетней давности, который всё равно будет переписан, то «миграция» сводится к редиректам со старых URL. Честнее назвать это новым сайтом, а не переездом, и не выставлять счёт за Migrate API.

Migrate API: конвейер source → process → destination

Главное, что нужно понять про перенос в Drupal: здесь нет кнопки «Импортировать CSV». Вместо неё — декларативная модель, в которой каждая миграция описывается YAML-файлом из трёх частей. Поначалу это раздражает («зачем писать конфиг, если в WordPress плагин импорта работал из коробки»), но ровно эта модель и позволяет переносить тысячи записей предсказуемо.

Схема конвейера Migrate API: источники данных слева, блок обработки и маппинга полей в центре, типы контента Drupal справа, сверху прямая стрелка импорта, снизу пунктирная стрелка отката
Три стадии миграции: источник, обработка, назначение — и обратный ход отката

Разберём анатомию на типовой задаче — перенос каталога услуг из WordPress в тип содержимого «Услуга» на Drupal 11.

  • Source (источник) — откуда берём данные. Это может быть прямое подключение к базе WordPress, экспорт WXR, CSV-выгрузка, JSON по HTTP, база Drupal 7. Плагин источника отвечает за одно: выдать поток строк с уникальным идентификатором каждой. Мы в большинстве WP-проектов выгружаем контент в CSV заранее подготовленным SQL-запросом — так источник «замораживается», и миграцию можно гонять на стенде, не трогая боевой WordPress.
  • Process (обработка) — как каждое поле источника превращается в поле назначения. Это цепочки плагинов: подставить значение по умолчанию, заменить подстроку, найти связанную сущность из другой миграции, перевести статус «publish» в «1». Здесь же живёт вся грязная работа: вычищение шорткодов, перекладка картинок в сущности Media, нормализация телефонов.
  • Destination (назначение) — куда кладём. Обычно это «узел такого-то типа», но может быть термин таксономии, пользователь, файл, сущность Media. Drupal сам ведёт таблицу соответствий «id в источнике → id в назначении», и именно она делает возможным откат и повторный запуск.

Так выглядит рабочий план миграции услуг, сокращённый до сути (реальный файл длиннее на десяток полей):

id: wp_services
label: 'Каталог услуг из WordPress'
migration_group: wp_site
source:
  plugin: csv
  path: 'private://migrate/services.csv'
  ids: [wp_id]
  track_changes: true
process:
  title: post_title
  'body/value':
    -
      plugin: callback
      callable: '\Drupal\itf_migrate\Cleanup::stripShortcodes'
      source: post_content
    -
      plugin: str_replace
      search: 'https://old-site.ru/wp-content/uploads/'
      replace: '/sites/default/files/legacy/'
  'body/format':
    plugin: default_value
    default_value: basic_html
  field_category:
    plugin: migration_lookup
    migration: wp_categories
    source: category_id
  field_image:
    plugin: migration_lookup
    migration: wp_media
    source: thumbnail_id
  field_price:
    plugin: callback
    callable: intval
    source: acf_price
  status:
    plugin: static_map
    source: post_status
    map:
      publish: 1
      draft: 0
    default_value: 0
  uid:
    plugin: default_value
    default_value: 1
destination:
  plugin: 'entity:node'
  default_bundle: service
migration_dependencies:
  required:
    - wp_categories
    - wp_media

Обратите внимание на зависимости: услуги ссылаются на рубрики и картинки, поэтому сначала должны отработать миграции wp_categories и wp_media. Плагин migration_lookup берёт идентификатор из WordPress и по таблице соответствий находит уже созданный термин или Media. Это и есть ответ на вопрос «как сохранить связи между сущностями» — они восстанавливаются автоматически, если миграции выстроены в правильном порядке. Набор плагинов из ядра закрывает процентов восемьдесят задач, остальное добирают migrate_plus (источник по HTTP, парсеры JSON и XML, дополнительные трансформации) и migrate_tools (команды drush и интерфейс в админке).

drush migrate:import и migrate:rollback — миграция как итеративный процесс

Вот ради чего стоило писать YAML. После того как план лежит в конфигурации, весь цикл выглядит так:

# Состояние всех миграций группы: сколько строк в источнике, сколько перенесено
drush migrate:status --group=wp_site

# Прогон одной миграции с учётом зависимостей
drush migrate:import wp_services --execute-dependencies

# Что-то не так? Откатываем — удаляются только созданные этой миграцией узлы
drush migrate:rollback wp_services

# Правим YAML, перечитываем конфигурацию, запускаем заново
drush cim -y && drush migrate:import wp_services

# Источник изменился, нужно подтянуть только новое и изменённое
drush migrate:import wp_services --update

На практике первый прогон никогда не бывает удачным. В третьей сотне карточек найдётся описание с незакрытым тегом, в пятой — цена «от 5 000 р.» вместо числа, в седьмой — картинка, которой нет на диске. Без отката каждую такую находку пришлось бы чистить руками в базе, а потом бояться повторного запуска из-за дублей. С откатом цикл «увидели проблему → поправили плагин → откатили → перезапустили» занимает минуты, и мы делаем его десятки раз, пока migrate:status не покажет ноль ошибок. Именно поэтому я называю Migrate API главным аргументом за Drupal в проектах со структурированным контентом: он превращает миграцию из разового героического подвига в повторяемую процедуру.

Пишите миграции так, чтобы их можно было запустить на боевом сайте в ночь запуска за один проход. Если конвейер отлажен на стенде, финальный перенос — это свежая выгрузка из старого сайта плюс migrate:import, и окно простоя измеряется минутами, а не сутками.

Перенос с WordPress: что ломается всегда и в каком порядке мы работаем

WordPress — самый частый донор в наших проектах миграции, и за годы у нас накопился список вещей, которые ломаются в каждом втором переезде. Дело не в том, что WordPress плохой: у двух систем разная модель данных, и наивное «перенести как есть» не работает по определению.

Что в WordPressЧто ломается при переносеЧто делаем
Рубрики и меткиВ WP рубрики иерархические, метки — плоские, и обе навешаны на один тип «запись». В Drupal таксономия привязана к полям типа содержимого, и «рубрика услуги» и «рубрика новости» — разные словариСтроим словарь соответствий: какая рубрика WP в какой словарь Drupal попадает. Лишние метки (у типового сайта их сотни, половина с одной записью) сливаем или отбрасываем
Шорткоды [gallery], [button], [contact-form-7]Без плагина-обработчика превращаются в квадратные скобки посреди текстаИнвентаризируем все шорткоды запросом по базе. Галереи и кнопки разбираем плагином callback в HTML или в ссылки на Media, формы заменяем на Webform, остальное вырезаем
Поля ACF / Pods / кастомные мета-поляЛежат в wp_postmeta в виде «ключ-значение», часто сериализованные массивы PHP. Автоматически не маппятся ни во чтоЯвный маппинг каждого поля в поле Drupal. Сериализованные значения десериализуем своим плагином обработки. Это самая трудоёмкая часть инвентаризации
Блоки Gutenberg и билдеры (Elementor, WPBakery)Контент перемешан с разметкой билдера: комментарии-маркеры, вложенные div с inline-стилями, JSON в атрибутахЧестно предупреждаем клиента: из билдера переносится текст и картинки, а не оформление. Страницы-лендинги собираем заново в Drupal Canvas или Layout Builder
Картинки в wp-content/uploadsВставлены абсолютными URL в тело текста, плюс десять размеров-копий на каждуюПереносим только оригиналы в сущности Media отдельной миграцией, в теле текста заменяем пути, размеры генерирует Drupal через image styles
КомментарииЧаще всего на корпоративном сайте там спамНе переносим, если клиент не настаивает. Экономим день работы
Меню и виджетыЖивут в настройках темы, а не в контентеСобираем руками — их мало, и они всё равно меняются при редизайне

Порядок работ у нас за годы устоялся, и нарушать его я не советую:

  1. Инвентаризация контента в таблицу. Не на глаз, а запросами по базе: сколько записей каждого типа, какие мета-поля реально заполнены (а не просто объявлены в ACF), какие шорткоды встречаются и сколько раз, сколько картинок и какого объёма. Результат — таблица, которую подписывает клиент. Это защита обеих сторон: потом не будет разговора «а где наши отзывы», если отзывы в таблице не значились.
  2. Словарь соответствий. Для каждого типа записи WP — тип содержимого Drupal, для каждого поля — поле, для каждого словаря — словарь. Здесь же фиксируем, что выбрасываем. Этот документ напрямую превращается в секции process в YAML.
  3. Пробная миграция на стенде. Поднимаем Drupal 11 на стейджинге, заливаем выгрузку, гоняем конвейер до нуля ошибок, отдаём клиенту смотреть. Правки на этой стадии — дёшево, после запуска — дорого.
  4. Заморозка контента на старом сайте и финальный прогон. За день-два до запуска просим клиента не править старый сайт, делаем финальную выгрузку и переносим дельту.

Пользователи и пароли: переносим учётки, а не хеши

Технически хеши паролей WordPress можно перенести: есть contrib-модуль, который учит Drupal проверять пароль по старому алгоритму и при первом удачном входе перехешировать его в свой формат. Мы этим путём почти не пользуемся, и вот почему. На корпоративном сайте пользователей обычно мало — редакторы и администраторы, — и у половины из них пароли трёхлетней давности, которые давно пора менять. Миграция — хороший повод это сделать. Поэтому наш стандарт: переносим учётки с ролями и e-mail, пароли не переносим, а в день запуска рассылаем письмо «сайт переехал, задайте новый пароль по ссылке». Исключение — сайты с личными кабинетами на тысячи клиентов: там принудительный сброс вызовет волну обращений в поддержку, и хеши мы переносим, предварительно прогнав аудит на слабые пароли.

SEO при миграции: карта редиректов — половина проекта

Если бы меня попросили назвать одну причину, по которой бизнес жалеет о переезде сайта, я бы не задумываясь сказал: потерянный поисковый трафик. И в девяти случаях из десяти теряют его не потому, что Drupal «хуже для SEO», а потому, что редиректы решили «сделать потом».

URL-структура при миграции меняется почти всегда. WordPress жил на /uslugi/lechenie-kariesa/, новый сайт — на /services/lechenie-kariesa, без завершающего слеша и с другим разделом. Для поисковика это два разных адреса: старый начинает отдавать 404, накопленные за годы ссылки и позиции по нему обнуляются, новый стартует с нуля. Единственный способ передать вес — постоянный редирект 301 со старого адреса на новый, и для каждой страницы он должен быть готов в момент запуска, а не через неделю.

Как мы это делаем:

  1. Выгружаем полный список URL старого сайта — из карты сайта, из базы, из логов веб-сервера за последние месяцы (там всплывают адреса, о которых никто не помнил, но по которым ходят люди) и из отчётов Яндекс Вебмастера и Search Console.
  2. Для каждого старого URL определяем новый. Для контента, который идёт через Migrate, это делается в самом конвейере: старый путь переносится в поле, а после генерации нового алиаса модулем pathauto пара «старый → новый» записывается в модуль redirect отдельной миграцией. Для ручного контента — таблица, которую заполняет редактор.
  3. Страницы, которым нет аналога, сводим на ближайший раздел, а не на главную: редирект всего подряд на главную поисковики справедливо считают мягким 404.
  4. Перед запуском прогоняем скриптом весь старый список по стенду и проверяем, что каждый адрес отдаёт ровно один 301 на существующую страницу. Цепочки редиректов и петли — отдельный пункт проверки.

Обязательный SEO-комплект Drupal, без которого мы сайт не сдаём: pathauto (человекочитаемые адреса по шаблонам), metatag (title, description, Open Graph, canonical), simple_sitemap (карта сайта с автоматической регенерацией), redirect (редиректы и, в его составе, журнал 404). Все четыре — contrib с покрытием Security Team, ставятся через Composer.

composer require drupal/pathauto drupal/metatag drupal/simple_sitemap drupal/redirect
drush en pathauto metatag simple_sitemap redirect -y
drush cr

После запуска начинается контроль. Первые две недели я смотрю журнал 404 модуля Redirect ежедневно: туда попадают адреса, которые мы пропустили, и их можно тут же превратить в редирект прямо из админки. Параллельно — Search Console и Вебмастер: отдаём новую карту сайта, следим за количеством проиндексированных страниц и ошибками сканирования. Просадка позиций на две-четыре недели при смене URL-структуры нормальна; если через полтора месяца трафик не вернулся к прежнему уровню — где-то дыра в карте редиректов.

Из практики: клиент, который до нас перенёс сайт силами фрилансера без карты редиректов, потерял за два месяца порядка половины органического трафика, а восстановление после того, как мы построили редиректы задним числом, заняло почти полгода. Редиректы — не «доделаем после запуска». Это та самая половина проекта, которую нельзя отложить.

Интеграция с 1С: каталог и цены без ручной синхронизации

Типовой запрос нашей аудитории звучит одинаково в клинике, в юрфирме и у оптовика: «Прайс на сайте должен совпадать с прайсом в 1С, и чтобы никто ничего руками не перебивал». Запрос разумный, и Drupal его закрывает, но я обязан сказать прямо: готового коннектора уровня «поставил модуль, ввёл адрес базы, всё заработало», как это устроено в экосистеме Битрикса, для Drupal нет. Интеграция с 1С — это всегда небольшая разработка, и её нужно закладывать в бюджет отдельной строкой.

Хаб-схема интеграций: сайт на Drupal в центре, вокруг учётная система с потоком цен, CRM с потоком заявок, почтовый сервер и мобильное приложение с потоком данных через API
Сайт как узел контура компании: цены из учётной системы, заявки в CRM, уведомления в почту, контент — в приложение

Хорошая новость — разработка небольшая, потому что у нас уже есть Migrate API. Два рабочих варианта, которые мы применяем:

Вариант 1: OData из 1С по расписанию → Migrate с track_changes

Современные конфигурации 1С умеют отдавать справочники и регистры по стандартному REST-интерфейсу OData — его включают на стороне публикации базы. Со стороны Drupal конвейер выглядит как обычная миграция, только источник — не CSV, а HTTP-запрос плагином url из migrate_plus с JSON-парсером. Ключевой флаг — track_changes: true: Drupal хранит хеш каждой строки источника и при повторном запуске обновляет только те узлы, у которых данные в 1С реально изменились. Без этого флага ночная синхронизация десяти тысяч позиций переписывала бы всё подряд и сбрасывала дату изменения у каждой карточки.

id: onec_services
label: 'Услуги и цены из 1С (OData)'
source:
  plugin: url
  data_fetcher_plugin: http
  data_parser_plugin: json
  urls:
    - 'https://1c.example.ru/base/odata/standard.odata/Catalog_Номенклатура?$format=json'
  authentication:
    plugin: basic
    username: odata_reader
    password: '***'
  item_selector: value
  track_changes: true
  ids:
    Ref_Key:
      type: string
  fields:
    - name: Ref_Key
      selector: Ref_Key
    - name: Description
      selector: Description
    - name: Price
      selector: Цена
process:
  title: Description
  field_price: Price
  field_1c_guid: Ref_Key
destination:
  plugin: 'entity:node'
  default_bundle: service

Запуск — по cron: drush migrate:import onec_services --update раз в час или раз в ночь, в зависимости от того, как часто меняются цены. Полное описание изменений остаётся в таблице миграции, откат работает так же, как при переезде. Этот вариант мы выбираем для каталогов от сотен до нескольких тысяч позиций, когда 1С опубликована в интернете или доступна по VPN с сервера сайта.

Вариант 2: 1С сама отправляет JSON на REST-эндпоинт Drupal

Если 1С стоит в закрытой сети и наружу её публиковать нельзя (частая ситуация у клиентов, где базу обслуживает сторонний франчайзи), направление разворачиваем: в 1С пишется небольшая обработка, которая по регламентному заданию собирает изменившиеся позиции и POST-запросом отправляет JSON на наш эндпоинт. На стороне Drupal это кастомный модуль с одним маршрутом, проверкой токена в заголовке и простой логикой «найти узел по GUID из 1С → обновить или создать». Код — порядка сотни строк, плюс тесты. Вариант дороже первого на разработку в 1С, но снимает вопросы безопасности: сайт не имеет доступа в учётную систему, только учётная система к сайту.

Что выбирать по объёму. При сотне позиций оба варианта избыточны — честно скажу, что дешевле обновлять прайс раз в месяц вручную через импорт CSV в админке, если цены меняются редко. От нескольких сотен до нескольких тысяч — вариант с OData и расписанием. На десятках тысяч позиций с остатками по складам, которые меняются каждые несколько минут, ночной полный прогон уже не годится: нужен второй вариант с отправкой только дельты, очередью на стороне Drupal и обработкой пакетами, чтобы не класть сайт в момент синхронизации. Это уже полноценный проект, и его масштаб нужно понимать до подписания договора.

Общее правило для обоих вариантов: главный ключ — GUID элемента из 1С, сохранённый в отдельном поле узла. Не название, не артикул, не код — их в 1С переименовывают и дублируют. Только GUID даёт надёжное соответствие «позиция в учёте ↔ карточка на сайте» на годы вперёд.

Формы и CRM: заявки не должны жить в почте

Вторая типовая интеграция — заявки с сайта. Картина «у нас форма отправляет письмо на info@, а менеджер по утрам разбирает почту» знакома каждому, и она плоха не эстетически, а экономически: письма теряются в спаме, заявки дублируются, никто не знает, сколько обращений пришло за месяц и сколько из них довели до сделки.

В Drupal формы — это модуль webform, и я не преувеличу, сказав, что он закрывает процентов девяносто пять задач без строчки кода: многошаговые формы, загрузка файлов, условная логика (показать поле «номер договора», если выбрано «действующий клиент»), черновики, ограничение по количеству отправок, экспорт в CSV. Все отправки хранятся в базе сайта — это уже само по себе даёт журнал обращений, даже если CRM пока нет.

Отправка заявки во внешние системы делается обработчиками (handlers) формы. У одной формы их может быть несколько, и они отрабатывают параллельно: один шлёт письмо менеджеру, второй — подтверждение клиенту, третий делает HTTP-запрос в CRM. Штатный обработчик «Remote post» умеет отправить данные формы POST-запросом на произвольный URL с маппингом полей, и для простых CRM этого достаточно.

Наша типовая связка выглядит так: Webform → вебхук → CRM клиента. В практике это чаще всего Planfix, Битрикс24 или amoCRM, у всех трёх есть REST-интерфейс для создания лида. Три вещи, которые мы делаем всегда:

  • Телефон как ключ дедупликации. Перед созданием лида ищем в CRM контакт с таким же номером, нормализованным до одного формата. Нашли — добавляем обращение к существующему контакту, не нашли — создаём. Без этого через полгода в CRM будет пять карточек одного клиента, который звонил с разных форм.
  • Промежуточный слой, а не прямой вызов. Для Planfix и Битрикс24 штатного «Remote post» мало: нужен токен, нужна правильная структура полей, нужна обработка ошибок. Поэтому у нас небольшой свой обработчик Webform, который умеет повторить запрос, если CRM ответила ошибкой, и записать неудачу в журнал. Заявка не должна пропасть из-за пятиминутного простоя CRM.
  • Почта остаётся как резерв. Письмо менеджеру отправляется всегда, даже если заявка ушла в CRM: это страховка и привычный для людей канал. Для отправки используем внешний SMTP-сервер, а не mail() с веб-сервера — иначе письма улетают в спам.

Антиспам без капчи: Antibot + Honeypot

Открытая форма на сайте начинает собирать спам через неделю после запуска. Классический ответ — капча — убивает конверсию: каждый лишний клик на форме заявки стоит процентов обращений, а для пожилой аудитории клиники «выберите все светофоры» превращается в непреодолимый барьер. Мы ставим два модуля, которые работают незаметно для человека: honeypot добавляет в форму скрытое поле, которое заполняют только боты, и проверяет минимальное время заполнения (человек не отправляет форму через секунду после загрузки); antibot требует, чтобы форма была отправлена через JavaScript, что отсекает примитивные скрипты. Вдвоём они убирают процентов девяносто пять мусора. Для оставшихся пяти — ограничение по количеству отправок с одного IP в Webform и, если совсем невмоготу, капча только на той форме, которую атакуют, а не на всём сайте.

Headless и JSON:API: зачем это малому бизнесу — и почему обычно незачем

Раз в несколько месяцев ко мне приходит запрос «хотим headless на Drupal с фронтом на React, как у больших». Давайте разберёмся, что это даёт и сколько стоит, потому что тема модная, а ответ для компании до пятидесяти рабочих мест чаще всего отрицательный.

Техническая сторона простая и честно хорошая. В ядре Drupal есть модуль jsonapi: включили — и весь контент сайта доступен по REST в стандартизированном формате. Каждый тип содержимого, каждая таксономия, каждая сущность Media получает свой адрес вроде /jsonapi/node/service, с фильтрацией, сортировкой, постраничной выдачей и вложенными связями. Никакого кода: права доступа управляются теми же ролями, что и для сайта. Для разработчика мобильного приложения это готовый бэкенд контента.

drush en jsonapi -y
# Опубликованные услуги с ценой, отсортированные по названию, первые 20
curl -s 'https://site.ru/jsonapi/node/service?filter[status]=1&sort=title&page[limit]=20&fields[node--service]=title,field_price'

Где это действительно полезно нашим клиентам:

  • Мобильное приложение клиники: список врачей, услуг и акций берётся с сайта, а не дублируется в отдельной админке приложения. Контент-менеджер правит в одном месте.
  • Инфоэкраны в офисе или на ресепшене: простая страница на телевизоре, которая раз в минуту забирает через JSON:API список новостей или расписание и показывает его. Пара дней работы.
  • Обмен с партнёрскими площадками: агрегатор или маркетплейс забирает каталог без ручных выгрузок.

А теперь про full-headless, когда Drupal только хранит контент, а весь сайт рендерит отдельное приложение на React, Next.js или аналоге. Что теряется: вся встроенная работа Drupal с отображением — темы, Layout Builder, Drupal Canvas с живым превью, штатные метатеги, карта сайта, предпросмотр перед публикацией, формы Webform, кэширование страниц. Всё это нужно либо написать заново на фронте, либо прикрутить через дополнительные слои. Что приобретается: скорость интерфейса на уровне приложения и свобода фронтенд-разработчика. По нашему опыту, бюджет такого проекта выходит в два-три раза выше, чем у классического сайта на той же CMS, а сопровождение требует двух разных специалистов вместо одного. Для корпоративного сайта, который посещают несколько тысяч человек в месяц и главная функция которого — рассказать об услугах и принять заявку, это переплата за модность.

Разумная середина, которую мы рекомендуем, — гибрид: Drupal рендерит сайт сам, как обычная CMS, со всеми своими удобствами, а jsonapi включён параллельно для приложения, экранов или партнёров. Один бэкенд, одна команда, один бюджет на сопровождение — и при этом дверь в мобильные сценарии открыта, когда они понадобятся.

Если включили JSON:API «на будущее», сразу ограничьте его: по умолчанию он отдаёт всё, на что у анонимного пользователя есть права чтения, включая списки пользователей с их именами. Оставьте доступ только к нужным типам содержимого и проверьте, что закрытые сущности не светятся.

Смета и сроки: из чего складывается миграция

Закончу тем, о чём клиенты спрашивают в первую очередь, а я намеренно отложил до конца, потому что без понимания предыдущих разделов цифры смысла не имеют. Типовой проект переноса корпоративного сайта с интеграциями у нас раскладывается по этапам в довольно стабильной пропорции. Возьмём для наглядности условный проект в двести часов: сайт на WordPress с тремя сотнями карточек услуг, десятком лендингов, прайсом из 1С и заявками в CRM.

ЭтапДоляЧасы (условно)Что внутриРезультат этапа
Инвентаризация и проектирование10%20Запросы по базе старого сайта, таблица контента, словарь соответствий, структура типов содержимого, список URLПодписанная таблица «что переносим, что выбрасываем»
Стенд и миграции40%80Развёртывание Drupal 11, типы содержимого и поля, YAML-планы, плагины обработки, итерации до нуля ошибок, тема и лендингиСайт на стейджинге с полным контентом
Редиректы и SEO15%30Карта старых и новых URL, миграция редиректов, Pathauto, Metatag, карта сайта, проверка скриптом, настройка Вебмастера и Search ConsoleНоль битых старых адресов на стенде
Интеграции25%50Конвейер OData из 1С с track_changes или REST-эндпоинт, Webform с обработчиком в CRM, дедупликация, SMTP, антиспамЦены синхронизируются, заявки в CRM, письма доходят
Приёмка и запуск10%20Проверка клиентом, правки, заморозка контента, финальный прогон, переключение DNS, дежурство первой недели, контроль 404Сайт на боевом домене, журнал 404 пустеет

Пропорции меняются от проекта к проекту — у сайта без 1С доля интеграций падает до десяти процентов, у сайта на Drupal 7 с кастомными модулями доля стенда и миграций может перевалить за половину. Но если в смете подрядчика какого-то из этих этапов нет вовсе, это повод задать вопросы.

Маркеры того, что миграцию считают «на глазок», по которым я сам оцениваю чужие коммерческие предложения:

  • В смете нет этапа инвентаризации, а цена названа до того, как кто-то заглянул в базу старого сайта.
  • Редиректы не выделены отдельной строкой или упомянуты как «настроим при запуске».
  • Интеграция с 1С оценена в один-два дня «через готовый модуль». Модуля нет; либо подрядчик не делал этого раньше, либо закладывает доработку в скрытую маржу.
  • Срок назван без привязки к объёму контента: «любой сайт за три недели».
  • Нет упоминания стенда: значит, миграцию планируют делать сразу на боевом домене.
  • Отсутствует этап приёмки и дежурства после запуска — первые две недели дают больше правок, чем весь стенд.

И чек-лист вопросов, которые стоит задать подрядчику до подписания договора. Ответы на них отличают команду, которая делала миграции, от команды, которая прочитала документацию:

  1. Как вы будете переносить контент — руками, Migrate API или своими скриптами? Покажете пример YAML-плана с прошлого проекта?
  2. Что произойдёт, если после первого прогона мы найдём ошибку в трёхстах карточках? Сколько стоит повторный прогон?
  3. Кто составляет таблицу инвентаризации контента и когда мы её подписываем?
  4. Как вы соберёте список всех URL старого сайта и как проверите, что каждый отдаёт 301 перед запуском?
  5. Что именно из 1С будет синхронизироваться, в какую сторону, как часто и что будет ключом соответствия?
  6. Куда попадает заявка с формы, если CRM недоступна в момент отправки?
  7. На какой ветке Drupal вы разворачиваете сайт и что будет с ним в декабре, когда выйдет Drupal 12? Кто и за чей счёт обновляет?
  8. Где будет жить стенд, и получим ли мы к нему доступ до запуска?
  9. Как будет организовано дежурство в первые две недели после переключения и кто смотрит журнал 404?
  10. Что мы получим на руки в конце: репозиторий с конфигурацией (drush cex), планами миграций и документацией — или только работающий сайт на вашем хостинге?

Если на большинство вопросов звучат внятные ответы — перед вами люди, которые уже наступали на грабли из этой статьи. Если нет — вы оплатите их обучение.

Мы в ITfresh берём миграции на Drupal вместе с интеграциями в контур компании — 1С, CRM, почта, мобильные сценарии — и сопровождаем сайт дальше на собственных серверах в дата-центре МТС. Обсудить ваш переезд можно в Telegram @ITfresh_Boss или по телефону +7 903 729-62-41: разберём старый сайт, прикинем объём и честно скажем, переносить его или собирать заново.

Перенесём ваш сайт на Drupal и свяжем его с 1С и CRM

ITfresh — IT-аутсорсинг для компаний до 50 рабочих мест в Москве. Миграция через Migrate API без потери SEO, синхронизация цен с 1С, заявки из Webform в CRM, сопровождение на собственных серверах в дата-центре МТС. 15+ лет опыта. Telegram: @ITfresh_Boss, тел. +7 903 729-62-41.

📞 Связаться с нами
#Drupal #Migrate API #миграция сайта #WordPress #интеграция 1С #Webform #JSON:API #SEO
Комментарии 0

Оставить комментарий

загрузка...

Подпишитесь на рассылку ITfresh

Раз в неделю — практические гайды для руководителя IT и сисадмина: безопасность, 1С, миграции, резервные копии, лайфхаки из реальных проектов.

Письмо придёт в течение минутыНе нашли его во «Входящих» — загляните в папку «Спам» или «Промоакции» и нажмите «Не спам». Так все следующие выпуски будут приходить прямо в основную почту.
Реквизиты оператора персональных данных

ООО «АЙТИ-ФРЕШ», ИНН 7719418495, КПП 771901001. Юридический адрес: 105523, г. Москва, Щёлковское шоссе, д. 92, корп. 7. Контакт: info@itfresh.ru, +7 903 729-62-41. Оператор обрабатывает e-mail подписчика в целях рассылки информационных и рекламных материалов до момента отзыва согласия.