| name | ocmod-writing |
| description | Практическое руководство по написанию OCMOD XML с учётом однострочного поиска и особенностей OpenCart. |
OCMOD — как писать корректные XML-патчи
Цель: дать краткие, проверяемые правила и примеры для создания OCMOD-файлов, которые надёжно применяются в OpenCart.
- Коротко о формате
<modification>
<name>...</name>
<code>unique_code</code>
<version>1.0</version>
<author>Author</author>
<file path="catalog/.../file.php">
<operation>
<search><![CDATA[...]]></search>
<add position="replace|before|after"><![CDATA[...]]></add>
</operation>
</file>
</modification>
- Однострочный поиск — ключевое ограничение
- OpenCart OCMOD выполняет поиск по строкам: содержимое
<search> должно соответствовать одной строке в исходном файле. Это значит:
- Не пытайтесь искать многострочные фрагменты в
<search> — они не сработают.
- Если целевой код может быть в одной строке с разным количеством пробелов, используйте регулярные выражения (см. пункт 3) или пишите поиск с учётом возможных пробелов.
- Регулярные выражения
- Если нужен гибкий поиск, используйте
regex="true" в элементе <search> (если платформа поддерживает):
<search regex="true"><![CDATA[\$this->response->setOutput\(\$this->load->view\('product/product', \$data\)\);]]></search>
- При использовании regex:
- Экранируйте слэши и специальные символы.
- Для пробелов используйте
\s+ или \s*.
- Ограничьте регулярное выражение так, чтобы оно оставалось однострочным.
- CDATA и вставляемый код
- Оборачивайте код в
<![CDATA[ ... ]]>, чтобы не ломать XML-структуру при наличии символов <, & и т.п.
- Пример вставки:
<add position="after"><![CDATA[
// Дополнительный вызов логирования
$this->log->write('product view');
]]></add>
- Позиции вставки
position="before" — вставляет перед найденной строкой.
position="after" — вставляет после найденной строки.
position="replace" — заменяет найденную строку полностью.
- Практические рекомендации
- Сначала найдите точную строку в исходном файле (или минимально-уникальную часть строки) и копируйте её в
<search>.
- Если строка генерируется сборщиком/минифицирована (всё в одной строке), используйте regex с
\s* и жёсткими якорями, например ^ и $.
- Для PHP-кода используйте контекстные вызовы (например, строка с
$this->response->setOutput(...)), а не части выражения.
- Добавляйте
<![CDATA[]]> вокруг вставляемого PHP/HTML.
- Тестируйте OCMOD локально: положите XML в
dev-modules/<имя_модуля>/upload/system/ или system/ и выполните установку через админку или ocm install, затем Refresh модификаций.
- Проверка и откат
- Обновите Modifications → Refresh и очистите кеш шаблонов/кэша.
- При ошибках удалите OCMOD через админку и восстановите файлы из репозитория (или пересоздайте). Держите резервную копию изменяемых файлов.
- Метаданные и уникальность
- Поле
<code> должно быть уникальным для модификации — это облегчает поиск и откат.
- Используйте префикс:
автор_название_модуля. Избегайте коротких имён вроде test или fix.
- Всегда указывайте
<version> и <link> — это помогает при поддержке через время.
- Стратегия поиска и атрибуты
<search>
- Уникальность: ищите максимально специфичный фрагмент, а не
<?php или </div>.
- Атрибут
index: если нужная строка встречается несколько раз, используйте <search index="2"> (отсчёт с нуля).
- Атрибут
trim="true": всегда добавляйте — пробелы/табуляция в начале/конце строки не будут ломать поиск.
- Минимум кода в поиске: чем длиннее строка поиска, тем выше шанс, что другой модуль её изменит и поиск провалится.
- Стратегия вставки (
<add>)
- Предпочитайте
position="before" или position="after" вместо position="replace" — полная замена является главной причиной конфликтов.
- Если вставляете много кода, вынесите логику в отдельный контроллер или helper-метод, а в OCMOD лишь вызовите его одной строкой.
- Порядок применения и зависимости
- Модификаторы применяются в алфавитном порядке по
<code>. Если ваш модуль зависит от другого, убедитесь, что ваш <code> идёт позже.
- Если проект использует и VQMod, и OCMOD: VQMod применяется первым, OCMOD работает уже с его результатом — учитывайте это при поиске строк.
- Чек-лист безопасного разработчика
- После каждого «Refresh» модификаций заглядывайте во вкладку Logs в админке. Надпись
NOT FOUND! означает, что модификатор не применился.
- Никогда не редактируйте файлы в
system/storage/modification/ — они исчезнут после следующего «Refresh».
- Если правку можно реализовать через Events (события) OpenCart 3 — используйте события. OCMOD — крайняя мера для мест, где события не предусмотрены.
- Пример идеальной операции
<operation error="skip">
<search trim="true"><![CDATA[$data['footer'] = $this->load->controller('common/footer');]]></search>
<add position="after"><![CDATA[$data['my_custom_var'] = 'Hello World';]]></add>
</operation>
- Частые ошибки и как их избежать
- Поиск не сработал из-за пробелов/табуляции — используйте
trim="true" или \s в regex.
- Поиск не сработал, потому что строка была объединена в одну после минификации — используйте regex или поместите поиск в месте, где код гарантированно имеет стабильный вид.
- Не уникальная строка поиска — добавьте
index="N" для выбора нужного вхождения.
- Использован
position="replace", конфликтующий с другим модулем — переходите на before/after.
- Забыл CDATA — XML сломается при вставке
<?php или <.
- Неправильный regex — «роняет» генерацию кэша модификаторов; всегда тестируйте локально.
- Слишком длинная строка поиска — другой модуль изменил её, и ваш патч не нашёл совпадений.
- Примеры
- Простой replace (однострочный поиск):
<file path="catalog/controller/product/product.php">
<operation>
<search><![CDATA[$this->response->setOutput($this->load->view('product/product', $data));]]></search>
<add position="replace"><![CDATA[// модифицированный вывод
$this->response->setOutput($this->load->view('product/product', $data));
]]></add>
</operation>
</file>
- Regex-пример с гибкими пробелами:
<file path="catalog/controller/checkout/checkout.php">
<operation>
<search regex="true"><![CDATA[\$this->session->data\['order_id'\];]]></search>
<add position="after"><![CDATA[
// логирование номера заказа
$this->log->write('Order: ' . $this->session->data['order_id']);
]]></add>
</operation>
</file>
- Размещение и установка
- OCMOD можно хранить в модуле:
dev-modules/<имя_модуля>/upload/system/<имя>.ocmod.xml или положить в system/.
- После развертывания выполните
ocm install (если доступна) или загрузите XML через админку и выполните Refresh модификаций.
Если хотите, добавлю шаблон OCMOD XML-файла в репозиторий или генератор шаблонов для модулей.