В Cotonti механизм хуков работает так:
В нужном месте, где нужно "вклинить" или "повесить" свой код, - нужно прописать "крючок", то есть хук, на который будем вешать свой пользовательский код, а сделать это можно вызовом функции в нужном участке кода, например:
// Удаление товара предварительно - хук на который вешаем удаление переводов товара
foreach (cot_getextplugins('market.delete.first') as $pl) {
include $pl;
}
То есть при запуске файла MarketControlService.php
до хука
// Хук для дополнительных действий после удаления
foreach (cot_getextplugins('market.delete.done') as $pl) {
include $pl;
}система сама ищет файлы в папках плагинов, где в заголовке указано Hooks=market.delete.first.
Файл plugins/i18n4marketpro/i18n4marketpro.market.delete.first.php как раз содержит такой заголовок и удаляет переводы.
Затем продолжается выполнение кода и удаление товара.
В Cotonti хук — это способ для плагинов выполнить свой код в строго определённых местах ядра или модулей.
Разработчик модуля market разместил в методе MarketControlService::delete() вызов:
foreach (cot_getextplugins('market.delete.first') as $pl) {
include $pl;
}
Этот код ищет все файлы плагинов, у которых в самом начале есть секция:
/* ====================
[BEGIN_COT_EXT]
Hooks=market.delete.first
[END_COT_EXT]
==================== */
Когда плагин i18n4marketpro активен, Cotonti находит его файл
plugins/i18n4marketpro/i18n4marketpro.market.delete.first.php, и при заходе в delete() включает его содержимое через include.
Внутри этого файла выполняется удаление записей из таблицы cot_i18n4marketpro_pages:
if (Cot::$db->tableExists('cot_i18n4marketpro_pages')) {
Cot::$db->delete(Cot::$db->i18n4marketpro_pages, 'ipage_id = ?', $id);
}
Таким образом, до того как удалится сам товар, сначала удаляются его переводы.
Это решает проблему: внешний ключ fk_translation_market больше не блокирует удаление, и скрипт не проваливается в валидацию пустой формы.
Если плагин отключён, Cotonti игнорирует его хуки.cot_getextplugins('market.delete.first') не находит ни одного файла, цикл ничего не включает, переводы остаются в базе, и при попытке удалить товар база данных выдаёт ошибку «Cannot delete or update a parent row: a foreign key constraint fails».
Именно эта ошибка перехватывается catch (Throwable $e) и приводит к return false в delete().
А так как код market.edit.php после неудачного удаления продолжает выполняться, он запускает cot_market_validate() с пустыми данными, и пользователь видит ошибки «Код категории бла-бла пиндец» и т.д.
Кратко: хуки позволяют плагинам «вклиниваться» в процесс удаления товара или другой нужный разработчику.
Сейчас вызов хука в MarketControlService::delete() уже написан - теперь можно писать файлы в плагинах с заголовком Hooks=market.delete.first и быть уверенным в том, что логика куда в этих файлах будет выполняться при обращении к нашему крючку в MarketControlService.php.
написано в образовательных целях для контекста и картины в целом!
При работе, стремимся к тому, что бы придерживаться штатных хуков, и логики как в файле ниже:
<?php
/**
* [BEGIN_COT_EXT]
* Hooks=market.delete.done
* [END_COT_EXT]
*/
/**
* featuredtopicsmarket.market.delete.done.php - Delete links on product delete
*
* featuredtopicsmarket plugin for Cotonti 0.9.26, PHP 8.4+
* Filename: featuredtopicsmarket.market.delete.done.php
*
* Date: May 14Th, 2026
* @package featuredtopicsmarket
* @version 2.7.8
* @author webitproff
* @copyright Copyright (c) webitproff 2026 | https://github.com/webitproff
* @license BSD
*/
defined('COT_CODE') or die('Wrong URL');
require_once cot_incfile('featuredtopicsmarket', 'plug');
global $db, $db_featured_topics_market, $id;
if ($id > 0)
{
$db->delete($db_featured_topics_market, "rtm_from_id = ? OR rtm_to_id = ?", [$id, $id]);
}
/* просто как шпаргалка
global $db, $db_x, $id;
if ($id > 0) {
$table = $db_x . 'featured_topics_market';
$db->delete($table, "rtm_from_id = ? OR rtm_to_id = ?", [$id, $id]);
}
*/