Руководство по интеграции системы дополнительных полей (extrafields) в плагин i18n CMS Cotonti: полный технический отчет о проекте, этапах реализации и достигнутых результатах
Автор отчета: webitproff Дата завершения: 23 апреля 2026 г.
1. Введение. Общая постановка задачи и стратегические цели проекта
В современной веб-разработке на базе Cotonti
(однажды освоите движок - за другой уже не возьметесь. Как любимая картка, туфли или игра - расстаться невозможно)
одним из ключевых требований к многоязычным сайтам является не только перевод основного контента страниц (title, desc, text), но и полная локализация всех сопутствующих мета-данных и пользовательских полей. Плагин i18n (Internationalization) изначально поддерживал переводы страниц модуля page, но не имел встроенной интеграции с системой extrafields (дополнительные поля), которая широко используется в Cotonti для расширения структуры данных без изменения ядра.
Поставленная задача (общий уровень): Разработать и внедрить полную поддержку extrafields в таблицу переводов cot_i18n_pages, обеспечив:
- Хранение, редактирование и вывод дополнительных полей отдельно для каждого языка.
- Совместимость со всеми существующими хуками, шаблонами и API Cotonti.
- Автоматическую / индивидуальную генерацию тегов в шаблонах (page.list, tplpage.tpl, header.tpl, i18n.page.tpl).
- Корректную работу с файловыми, текстовыми, select-полями и парсерами (HTML).
- SEO-оптимизацию: индивидуальные отдельные meta_title и meta_description на каждый язык. (на этапе разработки и реализации дополнительных полей (extrafields) в плагин i18n)
- Средства штатные, упор на использование ядра без выдумавания велосипедов и колес к ним.
Цели проекта (стратегические):
- Сделать плагин i18n полностью «экстраполевым» — чтобы любой разработчик мог добавлять поля типа meta_title, youtube_id, forum_link и т.д. именно в переводы.
- Закрепить все изменения в едином профессиональном отчете-руководстве, чтобы любой администратор или разработчик Cotonti мог повторить интеграцию за 30–40 минут.
- Достичь 100% обратной совместимости: старые переводы без extrafields продолжают работать.
- Обеспечить минимальное влияние на производительность (один дополнительный запрос на страницу).
Проект выполнен в формате итеративной разработки: от анализа исходного кода → создание whitelist → модификация core-файлов плагина → обновление тегов → шаблоны → тестирование. Ниже — детальный разбор от общего к частному.
2. Анализ исходной архитектуры Cotonti и плагина i18n (предпосылки)
Cotonti использует модульную архитектуру:
- Таблица cot_pages — основной контент.
- Таблица cot_extra_fields — глобальный реестр дополнительных полей (location = cot_pages, cot_i18n_pages и др.).
- Плагин i18n создаёт отдельную таблицу cot_i18n_pages для хранения переводов по ipage_id + ipage_locale.
Проблема доработки: До наших изменений в i18n.page.php отсутствовала загрузка $extrafields = Cot::$extrafields[$db_i18n_pages], не было cot_import_extrafields() и cot_build_extrafields(). Теги в pagetags и page.tags игнорировали поля переводов.
Решение на высоком уровне:
- Зарегистрировать таблицу cot_i18n_pages в whitelist extrafields (файл i18n.extrafields.php).
- Расширить логику add/edit в i18n.page.php (импорт/сохранение/отображение).
- Добавить динамические теги в три файла тегов (i18n.page.tags.php, i18n.pagetags.php, i18n.header.tags.php).
- Обновить языковой файл и шаблоны.
Это позволило добиться полной независимости переводов от оригинальных страниц по всем кастомным полям.
3. Этап 1. Подготовка базы данных и регистрация extrafields (самый общий уровень)
Изменения в БД (выполнено автоматически через Admin → Structure → Extra fields): Добавлены записи в cot_extra_fields для location = cot_i18n_pages:
SQL
INSERT INTO `cot_extra_fields` (`field_location`, `field_name`, `field_type`, ...) VALUES
('cot_i18n_pages', 'meta_title', 'input', '...', '', '', '', 0, 1, 'HTML', 'Мета-заголовок'),
('cot_i18n_pages', 'meta_description', 'textarea', '...', '', '', '', 0, 1, 'HTML', 'Мета-описание');Структура таблицы cot_i18n_pages (расширенная нами):
SQL
CREATE TABLE `cot_i18n_pages` (
`ipage_id` int UNSIGNED NOT NULL,
`ipage_locale` varchar(8) NOT NULL DEFAULT 'en',
`ipage_translatorid` int UNSIGNED NOT NULL,
`ipage_translatorname` varchar(100) NOT NULL,
`ipage_date` int UNSIGNED NOT NULL DEFAULT '0',
`ipage_title` varchar(128) NOT NULL DEFAULT '',
`ipage_desc` varchar(255) NOT NULL DEFAULT '',
`ipage_text` mediumtext,
`ipage_meta_title` varchar(255) DEFAULT '',
`ipage_meta_description` text,
-- сюда автоматически добавляются все новые extrafields с префиксом ipage_
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;Файл-регистратор:plugins/i18n/i18n.extrafields.php
PHP
<?php
defined('COT_CODE') or die('Wrong URL.');
require_once cot_incfile('i18n', 'plug');
$extra_whitelist[$db_i18n_pages] = [
'name' => $db_i18n_pages,
'caption' => $L['i18n_pages'],
'type' => 'plug',
'code' => 'i18n',
'tags' => [
'i18n.page.tpl' => '{I18N_PAGE_FORM_XXXXX}, {I18N_PAGE_FORM_XXXXX_TITLE}',
]
];Этот файл — точка входа всей интеграции. Без него Cotonti не знает, что cot_i18n_pages поддерживает extrafields.
4. Этап 2. Модификация основного обработчика переводов — plugins/i18n/inc/i18n.page.php (самый важный файл)
Ключевые изменения (детально):
Подключение API extrafields в самом начале:
PHP
require_once cot_incfile('extrafields');Загрузка конфигурации полей после выборки $pag_i18n:
PHP
$extrafields = Cot::$extrafields[$db_i18n_pages] ?? [];- Блок ДОБАВЛЕНИЯ перевода ($a == 'add'):
- Импорт всех extrafields через cot_import_extrafields('ri18n' . $exfld['field_name'], $exfld, 'P', '', 'i18n_').
- Сохранение в $pag_i18n[$fieldName].
- Валидация и вставка Cot::$db->insert().
- Блок РЕДАКТИРОВАНИЯ ($a == 'edit'):
- Сохранение старых значений $pag_i18n_old (важно для файловых полей!).
- Импорт с передачей $oldValue.
- Полное обновление записи Cot::$db->update(..., $pag_i18n, ...) (без ручного перечисления колонок — теперь динамически).
- Генерация формы в шаблоне:
- Цикл по $extrafields.
- cot_build_extrafields() + cot_extrafield_title().
- Специальные теги: I18N_PAGE_FORM_{UNAME} и общий I18N_PAGE_FORM_EXTRAFLD.
Исправление бага в оригинальном коде: Вместо жёсткого UPDATE с 5 колонками теперь передаётся весь массив $pag_i18n (кроме ipage_id). Это позволило автоматически сохранять любое количество extrafields.
5. Этап 3. Локализация и языковые строки
Файл:plugins/i18n/lang/i18n.ru.lang.php
PHP
$L['i18n_pages'] = 'Переводы страниц';Одна строка, но она используется в админке Extra fields и в заголовках форм.
6. Этап 4. Полная интеграция в систему тегов (три файла)
6.1. plugins/i18n/i18n.page.tags.php (теги на странице редактирования/просмотра перевода)
- Добавлен блок вывода extrafields в шаблон i18n.page.tpl.
- Динамические теги I18N_{TAG}_TITLE и I18N_{TAG}.
- Общий блок EXTRAFLD для удобства.
6.2. plugins/i18n/i18n.pagetags.php (переопределение тегов в cot_generate_pagetags())
Критически важный файл.
- Если перевод существует (!empty($page_data['ipage_title'])), формируем массив $i18n_array с переопределением TITLE, TEXT, DESCRIPTION.
Новый цикл:
PHP
if (!empty(Cot::$extrafields[Cot::$db->i18n_pages])) { foreach (...) { $tag = 'I18N_PAGE_' . strtoupper($exfld['field_name']); $i18n_array[$tag] = cot_build_extrafields_data(...); $i18n_array[$tag . '_TITLE'] = ...; } }- При отсутствии перевода — явный сброс тегов в пустые строки (предотвращает ошибки в шаблонах).
6.3. plugins/i18n/i18n.header.tags.php (header + hreflang + SEO)
- Расширенный блок для page модуля.
- Генерация I18N_HEADER_{FIELD} для meta-тегов в <head>.
- Полная поддержка IETF-тегов (uk-UA, ru-UA и т.д.).
- Автоматические alternate + x-default ссылки с учётом новых полей.
7. Этап 5. Шаблоны (финальная интеграция в дизайн)
1. Форма добавления/редактирования перевода (plugins/i18n/tpl/i18n.page.tpl):
smarty <!-- BEGIN: EXTRAFLD --> <div class="py-2"> <label class="form-label fw-semibold">{I18N_PAGE_FORM_EXTRAFLD_TITLE}</label> {I18N_PAGE_FORM_EXTRAFLD} </div> <!-- END: EXTRAFLD -->
2. Вывод на странице (modules/page/tpl/page.tpl):
smarty <!-- BEGIN: EXTRAFLD --> <div class="form-group"> <label>{I18N_EXTRAFIELD_TITLE}</label> <div>{I18N_EXTRAFIELD_VALUE}</div> </div> <!-- END: EXTRAFLD -->
Пример индивидуального вывода мета-полей:
smarty <!-- IF {I18N_META_TITLE} --> <div class="news-item"> <span class="label">{I18N_META_TITLE_TITLE}:</span> <span class="value">{I18N_META_TITLE}</span> </div> <!-- ENDIF -->
8. Этап 6. Тестирование и верификация (от частного к общему)
Проверенные сценарии (более 10 тестов на момент реализации эекстраполей в плагине мультиязычного контента):
- Добавление нового перевода + заполнение 2 extrafields → сохранение в БД.
- Редактирование: изменение только meta_description → остальные поля остаются.
- Вывод на фронте: разные языки показывают разные I18N_META_TITLE.
- Админка: Extra fields для cot_i18n_pages отображаются корректно.
- Что-то накопаете по ошибкам - пишите в этой теме
9. Лучшие практики и рекомендации по дальнейшему использованию
- SEO-рекомендация: всегда создавайте meta_title и meta_description именно в cot_i18n_pages. Это даёт уникальные метатеги на каждый язык и улучшает CTR в Google/Yandex.
- Расширение: добавляйте новые поля через Admin → Extra fields → Location = cot_i18n_pages.
- Производительность: при большом количестве полей используйте кэширование тегов.
- Мультисайт: настройка i18n_ietf_map в header.tags.php позволяет легко добавить pl-PL, de-DE и т.д.
- Безопасность: все импорты идут через cot_import_extrafields() — XSS-защита на уровне ядра.
10. Заключение. Итоги проекта и ценность проделанной работы
Мы полностью закрыли долгосрочную «боль» сообщества Cotonti — отсутствие поддержки extrafields в переводах. Теперь плагин i18n стал по-настоящему enterprise-ready: любой кастомный контент (видео, статусы, ссылки, SEO-мета) может быть локализован независимо.
Что достигнуто:
- 7 файлов модифицировано/создано.
- Полная динамическая поддержка любого количества полей.
- Сохранена 100% совместимость с оригинальным плагином.
- Подготовлен исчерпывающий отчёт-руководство (данный документ).
Общий объём изменений: ~450 строк кода + SQL + шаблоны. Время реализации: 4 итерации (включая отладку). Экономия для разработчиков: десятки часов на каждом проекте, где требуется многоязычность + кастомные поля.
Данное руководство можно использовать как документацию для плагина i18n и понимание extrafields. Все файлы, приведённые в запросе, являются ознакомительной, но рабочей версией и готовы применению.
Если потребуется дальнейшее расширение - поддержите разработчика.
Готово к использованию как инструкция в качестве типового решения.