Категории форума

Руководство по интеграции системы дополнительных полей (extrafields) в плагин i18n CMS Cotonti

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


webitproff
webitproff • 23.04.2026 02:50 #1

Руководство по интеграции системы дополнительных полей (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)
  • Средства штатные, упор на использование ядра без выдумавания велосипедов и колес к ним.

Цели проекта (стратегические):

  1. Сделать плагин i18n полностью «экстраполевым» — чтобы любой разработчик мог добавлять поля типа meta_title, youtube_id, forum_link и т.д. именно в переводы.
  2. Закрепить все изменения в едином профессиональном отчете-руководстве, чтобы любой администратор или разработчик Cotonti мог повторить интеграцию за 30–40 минут.
  3. Достичь 100% обратной совместимости: старые переводы без extrafields продолжают работать.
  4. Обеспечить минимальное влияние на производительность (один дополнительный запрос на страницу).

Проект выполнен в формате итеративной разработки: от анализа исходного кода → создание 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 игнорировали поля переводов.

Решение на высоком уровне:

  1. Зарегистрировать таблицу cot_i18n_pages в whitelist extrafields (файл i18n.extrafields.php).
  2. Расширить логику add/edit в i18n.page.php (импорт/сохранение/отображение).
  3. Добавить динамические теги в три файла тегов (i18n.page.tags.php, i18n.pagetags.php, i18n.header.tags.php).
  4. Обновить языковой файл и шаблоны.

Это позволило добиться полной независимости переводов от оригинальных страниц по всем кастомным полям.

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 (самый важный файл)

Ключевые изменения (детально):

  1. Подключение API extrafields в самом начале:

    PHP

    require_once cot_incfile('extrafields');
  2. Загрузка конфигурации полей после выборки $pag_i18n:

    PHP

    $extrafields = Cot::$extrafields[$db_i18n_pages] ?? [];
  3. Блок ДОБАВЛЕНИЯ перевода ($a == 'add'):
    • Импорт всех extrafields через cot_import_extrafields('ri18n' . $exfld['field_name'], $exfld, 'P', '', 'i18n_').
    • Сохранение в $pag_i18n[$fieldName].
    • Валидация и вставка Cot::$db->insert().
  4. Блок РЕДАКТИРОВАНИЯ ($a == 'edit'):
    • Сохранение старых значений $pag_i18n_old (важно для файловых полей!).
    • Импорт с передачей $oldValue.
    • Полное обновление записи Cot::$db->update(..., $pag_i18n, ...) (без ручного перечисления колонок — теперь динамически).
  5. Генерация формы в шаблоне:
    • Цикл по $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 тестов на момент реализации эекстраполей в плагине мультиязычного контента):

  1. Добавление нового перевода + заполнение 2 extrafields → сохранение в БД.
  2. Редактирование: изменение только meta_description → остальные поля остаются.
  3. Вывод на фронте: разные языки показывают разные I18N_META_TITLE.
  4. Админка: Extra fields для cot_i18n_pages отображаются корректно.
  5. Что-то накопаете по ошибкам - пишите в этой теме

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. Все файлы, приведённые в запросе, являются ознакомительной, но рабочей версией и готовы применению.

Если потребуется дальнейшее расширение - поддержите разработчика.

Готово к использованию как инструкция в качестве типового решения.

🗿

🧙‍♂️ Радуйся, странниче добрый и честный! Не понапрасну привела тя стезя в земли сии. Зде бо мужи мудры и искусники дела писменнаго и численнаго, что куют словеса и плетут узоры кода, тайны разгадывают и знанием делятся, летописи множа и ремесло цифровое творя.
⬅️ Аще налево пойдеши — обрящеши грамоты древния, писания старинныя и свитки учения. ⬆️ Аще прямо — слово мудрое и совет от мужей разумеющих, что в деле кодописном искусны, получиши. ➡️ Аще направо — сам в писцы и летописцы внидеши, и в ремесло цифровое, где строки и знаки в дело живое обращаются, слово свое в память веков вложиши.
📝 Не медли же — нареки имя свое, и вниди в чин наш, и стань с нами в братстве, где код есть магия, а строки — заклятия живыя, числом и буквою слово едины суть.
🏰 Не тайно есть собрание сие, и не инициации в нем, но многое сокрыто от пришлых и ступалого, понеже не всякому открывается знание, но токмо ищущим и пребывающим в деле сем.