Новая страница продукта Back Office, представленная в версии {{< minver v="8.1.0" >}}, удалила несколько хуков, которые ранее были доступны на странице. Полный список удаленных хуков:
displayAdminProductsCombinationBottomdisplayAdminProductsSeoStepBottomdisplayAdminProductsShippingStepBottomdisplayAdminProductsQuantitiesStepBottomdisplayAdminProductsMainStepLeftColumnBottomdisplayAdminProductsMainStepLeftColumnMiddledisplayAdminProductsMainStepRightColumnBottomdisplayAdminProductsOptionsStepTopdisplayAdminProductsOptionsStepBottomdisplayAdminProductsPriceStepBottom
Единственный хук displayAdminProduct*, который не был удален, это:
displayAdminProductsExtra
{{% notice info %}}
Хотя этот хук (displayAdminProductsExtra) сохранен для обеспечения обратной совместимости, его не рекомендуется использовать в новых модулях.
{{% /notice %}}
В этом руководстве мы узнаем, как расширить страницу продукта, добавив на нее пользовательские поля, как старыми, так и новыми способами.
Наконец, мы узнаем, как добавить новую вкладку на страницу продукта, что возможно для новой страницы продукта, начиная с PrestaShop 8.1.
Добавить пользовательское поле, до {{< minver v="8.1.0" >}}
Пользовательское поле, до {{< minver v="8.1.0" >}}, добавлялось путем привязки к одному из хуков displayAdminProducts<Location>.
Например, чтобы добавить пользовательское поле на вкладке SEO, вам нужно было создать модуль с таким содержимым:
demooldhooks.php:
declare(strict_types=1);
use Symfony\Component\Form\Extension\Core\Type\TextType;
class DemoOldHooks extends Module
{
public function __construct()
{
// [...]
}
/**
* @return bool
*/
public function install()
{
return parent::install() && $this->registerHook(['displayAdminProductsSeoStepBottom']);
}
public function hookDisplayAdminProductsSeoStepBottom($params)
{
$productId = $params['id_product'];
$formFactory = $this->get('form.factory');
$twig = $this->get('twig');
$product = new Product($productId);
$form = $formFactory
->createNamedBuilder('seo_special_field', TextType::class, "")
->getForm();
$template = '@Modules/demooldhooks/views/templates/seo_special_field.html.twig';
return $twig->render($template, [
'seo_special_field' => $form->createView()
]);
}
}
views/templates/seo_special_field.html.twig:
<h3>SEO Специальное поле</h3>
{{ form_widget(seo_special_field) }}
До {{< minver v="8.1.0" >}}, это создавало:

Начиная с {{< minver v="8.1.0" >}}, это поле не будет отображаться, так как хук (displayAdminProductsSeoStepBottom) больше не доступен.
Добавить пользовательское поле, начиная с {{< minver v="8.1.0" >}}
Для того чтобы сделать то же самое, начиная с {{< minver v="8.1.0" >}}, мы будем использовать хук actionProductFormBuilderModifier и модифицировать FormBuilder продукта.
Сначала создайте модуль с файлом composer.json, [как указано здесь]({{< relref "/8/modules/concepts/composer" >}}).
demonewhooks.php:
declare(strict_types=1);
use DemoNewHooks\Form\Modifier\ProductFormModifier;
class DemoNewHooks extends Module
{
public function __construct()
{
// [...]
}
/**
* @return bool
*/
public function install()
{
return parent::install() && $this->registerHook(['actionProductFormBuilderModifier']);
}
/**
* Modify product form builder
*
* @param array $params
*/
public function hookActionProductFormBuilderModifier(array $params): void
{
/** @var ProductFormModifier $productFormModifier */
$productFormModifier = $this->get(ProductFormModifier::class);
$productId = (int) $params['id'];
$productFormModifier->modify($productId, $params['form_builder']);
}
}
config/services.yml:
services:
DemoNewHooks\Form\Modifier\ProductFormModifier:
autowire: true
public: true
arguments:
$formBuilderModifier: '@form.form_builder_modifier'
src/Form/Modifier/ProductFormModifier.php:
declare(strict_types=1);
namespace DemoNewHooks\Form\Modifier;
use PrestaShopBundle\Form\FormBuilderModifier;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
final class ProductFormModifier
{
/**
* @var FormBuilderModifier
*/
private $formBuilderModifier;
/**
* @param FormBuilderModifier $formBuilderModifier
*/
public function __construct(
FormBuilderModifier $formBuilderModifier
) {
$this->formBuilderModifier = $formBuilderModifier;
}
/**
* @param int|null $productId
* @param FormBuilderInterface $productFormBuilder
*/
public function modify(
int $productId,
FormBuilderInterface $productFormBuilder
): void {
$seoTabFormBuilder = $productFormBuilder->get('seo');
$this->formBuilderModifier->addAfter(
$seoTabFormBuilder, // вкладка
'tags', // input/form после/перед которым вставлять
'demo_module_custom_field', // имя вашего поля
TextType::class, // тип вашего поля
[
'label' => 'SEO Специальное поле', // можно удалить метку, если она не нужна, передав 'label' => false
'label_attr' => [ // кастомизация метки с любыми HTML атрибутами
'title' => 'h2',
'class' => 'text-info',
],
'attr' => [
'placeholder' => 'SEO Специальное поле',
],
'data' => "",
'empty_data' => '',
'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig',
]
);
}
}
Этот модуль использует модификатор строителя форм (FormBuilderModifier) и добавляет поле TextType в форму вкладки SEO после существующего элемента формы tags.
FormBuilderModifier привязан к actionProductFormBuilderModifier.
Эти изменения создают следующий результат:

{{% notice note %}} Новый способ добавления пользовательских полей на страницу продукта позволяет более точно позиционировать их. Теперь можно разместить свои поля/формы именно там, где вам нужно. {{% /notice %}}
Шпаргалка по старым/новым хукам / новым хукам
Хук: actionProductFormBuilderModifier
- Хук: [
action<Object>FormBuilderModifier]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}})
| Старый хук | Расположение на странице | Вкладка формы | Вставлено |
|---|---|---|---|
displayAdminProductsSeoStepBottom |
Низ вкладки SEO | seo |
после tags |
displayAdminProductsCombinationBottom |
Низ вкладки Комбинации | combinations |
после availability |
displayAdminProductsShippingStepBottom |
Низ вкладки Доставка | shipping |
после carriers |
displayAdminProductsQuantitiesStepBottom |
Низ вкладки Количества | stock |
после low_stock_threshold |
displayAdminProductsMainStepLeftColumnBottom |
Вкладка Основные настройки, под связанными продуктами | description |
после related_products |
displayAdminProductsMainStepLeftColumnMiddle |
Вкладка Основные настройки, под описанием | description |
после description |
displayAdminProductsMainStepRightColumnBottom |
Вкладка Основные настройки, под созданием категории | description |
после categories |
displayAdminProductsOptionsStepTop |
Верх вкладки Опции | options |
перед visibility |
displayAdminProductsOptionsStepBottom |
Низ вкладки Опции | options |
после product_suppliers |
displayAdminProductsPriceStepBottom |
Низ вкладки Цены | pricing |
после priority_management |
Детали типа формы: EditProductFormType
Расширить подформу
Можно также расширить подформы, например, чтобы добавить новый input на каждую комбинацию продукта:
- Привязаться к хуку actionProductCombinationFormBuilderModifier ([
action<Object>FormBuilderModifier]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}}))
/**
* Хук, модифицирующий структуру формы комбинации.
*
* @param array $params
*/
public function hookActionCombinationFormFormBuilderModifier(array $params): void
{
/** @var CombinationFormModifier $productFormModifier */
$productFormModifier = $this->get(CombinationFormModifier::class);
$combinationId = isset($params['id']) ? new CombinationId((int) $params['id']) : null;
$productFormModifier->modify($combinationId, $params['form_builder']);
}
src/Form/Modifier/CombinationFormModifier.php:
// [...]
class CombinationFormModifier
{
// [...]
/**
* @param CombinationId|null $combinationId
* @param FormBuilderInterface $combinationFormBuilder
*/
public function modify(
?CombinationId $combinationId,
FormBuilderInterface $combinationFormBuilder
): void {
$idValue = $combinationId ? $combinationId->getValue() : null;
$customCombination = new CustomCombination($idValue);
$this->addCustomField($customCombination, $combinationFormBuilder);
}
/**
* @param CustomCombination $customCombination
* @param FormBuilderInterface $combinationFormBuilder
*
* @see demoproductform::hook
*/
private function addCustomField(CustomCombination $customCombination, FormBuilderInterface $combinationFormBuilder): void
{
$this->formBuilderModifier->addAfter(
$combinationFormBuilder,
'references',
'demo_module_custom_field',
TextType::class,
[
'label' => $this->translator->trans('Демо пользовательское поле', [], 'Modules.Demoproductform.Admin'),
'label_attr' => [
'title' => 'h2',
'class' => 'text-info',
],
'attr' => [
'placeholder' => $this->translator->trans('Ваш пример текста здесь', [], 'Modules.Demoproductform.Admin'),
],
'data' => $customCombination->custom_field,
'empty_data' => '',
'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig',
]
);
}
}
Этот пример добавит input TextType на каждую Комбинацию продукта.
Полный рабочий пример и реализация доступны в репозитории example-module.
Добавить пользовательскую вкладку на страницу продукта
{{< minver v="8.1.0" >}} представила новую функцию: пользовательские вкладки на странице продукта.
Полный рабочий пример реализации доступен в репозитории example-module.
- Вы можете расширить строитель формы продукта с помощью хука
actionProductFormBuilderModifierи созданного модификатора:
demonewhooks.php:
declare(strict_types=1);
use DemoNewHooks\Form\Modifier\ProductFormModifier;
class DemoNewHooks extends Module
{
public function __construct()
{
// [...]
}
/**
* @return bool
*/
public function install()
{
return parent::install() && $this->registerHook(['actionProductFormBuilderModifier']);
}
/**
* Modify product form builder
*
* @param array $params
*/
public function hookActionProductFormBuilderModifier(array $params): void
{
/** @var ProductFormModifier $productFormModifier */
$productFormModifier = $this->get(ProductFormModifier::class);
$productId = (int) $params['id'];
$productFormModifier->modify($productId, $params['form_builder']);
}
}
config/services.yml:
services:
DemoNewHooks\Form\Modifier\ProductFormModifier:
autowire: true
public: true
arguments:
$formBuilderModifier: '@form.form_builder_modifier'
src/Form/Modifier/ProductFormModifier.php:
declare(strict_types=1);
namespace DemoNewHooks\Form\Modifier;
use PrestaShopBundle\Form\FormBuilderModifier;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
final class ProductFormModifier
{
/**
* @var FormBuilderModifier
*/
private $formBuilderModifier;
/**
* @param FormBuilderModifier $formBuilderModifier
*/
public function __construct(
FormBuilderModifier $formBuilderModifier
) {
$this->formBuilderModifier = $formBuilderModifier;
}
/**
* @param int|null $productId
* @param FormBuilderInterface $productFormBuilder
*/
public function modify(
int $productId,
FormBuilderInterface $productFormBuilder
): void {
$seoTabFormBuilder = $productFormBuilder->get('seo');
$this->formBuilderModifier->addAfter(
$seoTabFormBuilder, // вкладка
'tags', // элемент формы, после/перед которым нужно вставить
'demo_module_custom_field', // ваше имя поля
TextType::class, // ваш тип поля
[
'label' => 'SEO Специальное поле', // можно убрать метку, передав 'label' => false
'label_attr' => [ // настройка метки с любым HTML атрибутом
'title' => 'h2',
'class' => 'text-info',
],
'attr' => [
'placeholder' => 'SEO Специальное поле',
],
// это просто пример, в реальном сценарии может быть класс провайдера данных для более сложных случаев
'data' => "",
'empty_data' => '',
'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig',
]
);
}
}
Этот модуль использует модификатор формы (FormBuilderModifier), добавляя поле типа TextType в форму вкладки SEO, после существующего элемента формы tags.
FormBuilderModifier подключен к actionProductFormBuilderModifier.
Эти изменения приводят к следующему:

{{% notice note %}} Этот новый способ добавления пользовательских полей на страницу продукта позволяет более точно позиционировать их. Теперь вы можете размещать свои поля и формы именно там, где хотите. {{% /notice %}}
Шпаргалка по старым/новым хукам
Хук: actionProductFormBuilderModifier
- Хук: [
action<Object>FormBuilderModifier]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}})
| Старый хук | Расположение на странице | Вкладка формы | Вставлено после |
|---|---|---|---|
displayAdminProductsSeoStepBottom |
Внизу вкладки SEO | seo |
после tags |
displayAdminProductsCombinationBottom |
Внизу вкладки Комбинации | combinations |
после availability |
displayAdminProductsShippingStepBottom |
Внизу вкладки Доставка | shipping |
после carriers |
displayAdminProductsQuantitiesStepBottom |
Внизу вкладки Количество | stock |
после low_stock_threshold |
displayAdminProductsMainStepLeftColumnBottom |
Вкладка основных настроек, под связанным продуктом | description |
после related_products |
displayAdminProductsMainStepLeftColumnMiddle |
Вкладка основных настроек, под описанием | description |
после description |
displayAdminProductsMainStepRightColumnBottom |
Вкладка основных настроек, под созданием категории | description |
после categories |
displayAdminProductsOptionsStepTop |
Вверху вкладки Опции | options |
перед visibility |
displayAdminProductsOptionsStepBottom |
Внизу вкладки Опции | options |
после product_suppliers |
displayAdminProductsPriceStepBottom |
Внизу вкладки Цены | pricing |
после priority_management |
Детали типа формы: EditProductFormType
Расширение подформы
Подформы также могут быть расширены, например, чтобы добавить новый ввод на каждую комбинацию продукта:
- Подключите к хуку actionProductCombinationFormBuilderModifier ([
action<Object>FormBuilderModifier]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionFormBuilderModifier" >}}))
/**
* Хук, который изменяет структуру формы комбинации.
*
* @param array $params
*/
public function hookActionCombinationFormFormBuilderModifier(array $params): void
{
/** @var CombinationFormModifier $productFormModifier */
$productFormModifier = $this->get(CombinationFormModifier::class);
$combinationId = isset($params['id']) ? new CombinationId((int) $params['id']) : null;
$productFormModifier->modify($combinationId, $params['form_builder']);
}
src/Form/Modifier/CombinationFormModifier.php:
// [...]
class CombinationFormModifier
{
// [...]
/**
* @param CombinationId|null $combinationId
* @param FormBuilderInterface $combinationFormBuilder
*/
public function modify(
?CombinationId $combinationId,
FormBuilderInterface $combinationFormBuilder
): void {
$idValue = $combinationId ? $combinationId->getValue() : null;
$customCombination = new CustomCombination($idValue);
$this->addCustomField($customCombination, $combinationFormBuilder);
}
/**
* @param CustomCombination $customCombination
* @param FormBuilderInterface $combinationFormBuilder
*
* @see demoproductform::hook
*/
private function addCustomField(CustomCombination $customCombination, FormBuilderInterface $combinationFormBuilder): void
{
$this->formBuilderModifier->addAfter(
$combinationFormBuilder,
'references',
'demo_module_custom_field',
TextType::class,
[
'label' => $this->translator->trans('Демонстрационное пользовательское поле', [], 'Modules.Demoproductform.Admin'),
'label_attr' => [
'title' => 'h2',
'class' => 'text-info',
],
'attr' => [
'placeholder' => $this->translator->trans('Ваш пример текста здесь', [], 'Modules.Demoproductform.Admin'),
],
'data' => $customCombination->custom_field,
'empty_data' => '',
'form_theme' => '@PrestaShop/Admin/TwigTemplateForm/prestashop_ui_kit_base.html.twig',
]
);
}
}
Этот пример добавит ввод типа TextType в каждую Комбинацию продукта Продукт. Полный рабочий пример и реализацию можно найти в нашем репозитории примеров модулей.
Добавление пользовательской вкладки на страницу продукта
{{< minver v="8.1.0" >}} представил новую функцию: пользовательские вкладки на странице продукта.
Полный рабочий пример реализации можно найти в нашем репозитории примеров модулей.
- Вы можете расширить конструктор формы продукта с помощью хука
actionProductFormBuilderModifierс созданным модификатором:
demonewhooks.php:
declare(strict_types=1);
use DemoNewHooks\Form\Modifier\ProductFormModifier;
class DemoNewHooks extends Module
{
public function __construct()
{
// [...]
}
/**
* @return bool
*/
public function install()
{
return parent::install() && $this->registerHook(['actionProductFormBuilderModifier']);
}
/**
* Изменить конструктор формы продукта
*
* @param array $params
*/
public function hookActionProductFormBuilderModifier(array $params): void
{
/** @var ProductFormModifier $productFormModifier */
$productFormModifier = $this->get(ProductFormModifier::class);
$productId = (int) $params['id'];
$productFormModifier->modify($productId, $params['form_builder']);
}
}
config/services.yml:
services:
DemoNewHooks\Form\Modifier\ProductFormModifier:
autowire: true
public: true
arguments:
$formBuilderModifier: '@form.form_builder_modifier'
src/Form/Modifier/ProductFormModifier.php:
declare(strict_types=1);
namespace DemoNewHooks\Form\Modifier;
use PrestaShopBundle\Form\FormBuilderModifier;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
final class ProductFormModifier
{
/**
* @var FormBuilderModifier
*/
private $formBuilderModifier;
/**
* @param FormBuilderModifier $formBuilderModifier
*/
public function __construct(
FormBuilderModifier $formBuilderModifier
) {
$this->formBuilderModifier = $formBuilderModifier;
}
/**
* @param int|null $productId
* @param FormBuilderInterface $productFormBuilder
*/
public function modify(
int $productId,
FormBuilderInterface $productFormBuilder
): void {
}
}
- Создайте новый тип для вашей пользовательской вкладки, например
CustomTabType, и добавьте вводMoneyTypeв эту вкладку:
src/Form/Type/CustomTabType.php:
declare(strict_types=1);
namespace PrestaShop\Module\DemoProductForm\Form\Type;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Translation\TranslatorInterface;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\PositiveOrZero;
use Symfony\Component\Validator\Constraints\Type;
class CustomTabType extends TranslatorAwareType
{
/**
* @var \Currency
*/
private $defaultCurrency;
/**
* @param TranslatorInterface $translator
* @param array $locales
* @param \Currency $defaultCurrency
*/
public function __construct(
TranslatorInterface $translator,
array $locales,
\Currency $defaultCurrency
) {
parent::__construct($translator, $locales);
$this->defaultCurrency = $defaultCurrency;
}
/**
* {@inheritDoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
parent::buildForm($builder, $options);
$builder
->add('custom_price', MoneyType::class, [
'label' => $this->trans('Моя пользовательская цена', 'Modules.Demoproductform.Admin'),
'label_tag_name' => 'h3',
'currency' => $this->defaultCurrency->iso_code,
'required' => false,
'constraints' => [
new NotBlank(),
new Type(['type' => 'float']),
new PositiveOrZero(),
],
])
;
}
/**
* {@inheritDoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
parent::configureOptions($resolver);
$resolver
->setDefaults([
'label' => $this->trans('Настройка', 'Modules.Demoproductform.Admin'),
])
;
}
}
Объявите вашу службу в вашем config.yml:
services:
DemoNewHooks\Form\Type\CustomTabType:
class: DemoNewHooks\Form\Type\CustomTabType
parent: 'form.type.translatable.aware'
public: true
arguments:
- '@=service("prestashop.adapter.data_provider.currency").getDefaultCurrency()'
tags:
- { name: form.type }
Добавьте оператор use в ваш ProductFormModifier:
use DemoNewHooks\Form\Type\CustomTabType;
Наконец, добавьте этот CustomTabType в переменную $productFormBuilder в вашем методе modify в ProductFormModifier:
/**
* @param int|null $productId
* @param FormBuilderInterface $productFormBuilder
*/
public function modify(
int $productId,
FormBuilderInterface $productFormBuilder
): void {
$idValue = $productId ? $productId->getValue() : null;
$customProduct = new CustomProduct($idValue);
$this->formBuilderModifier->addAfter(
$productFormBuilder,
'pricing',
'custom_tab',
CustomTabType::class,
[
'data' => [
'custom_price' => $customProduct->custom_price,
],
]
);
}
{{% notice note %}}
Любой тип, добавленный напрямую в $productFormBuilder (а не во вкладыш), будет считаться вкладкой.
{{% /notice %}}
Обратная совместимость для хука displayAdminProductsExtra
Пользовательский тип формы ExtraModulesType был добавлен в {{< minver v="8.1.0" >}}, чтобы обеспечить обратную совместимость для модулей, реализующих хук displayAdminProductsExtra.
Если модуль регистрируется в хуке displayAdminProductsExtra, на новой странице продукта будет добавлена пользовательская вкладка, обрабатываемая ExtraModulesType.
{{% notice info %}}
Хотя этот хук (displayAdminProductsExtra) сохранен для обратной совместимости, его не рекомендуется использовать для новых модулей.
{{% /notice %}}
public function hookDisplayAdminProductsExtra(array $params): string
{
$productId = $params['id_product'];
$customProduct = new CustomProduct($productId);
/** @var EngineInterface $twig */
$twig = $this->get('twig');
return $twig->render('@Modules/demoproductform/views/templates/admin/extra_module.html.twig', [
'customProduct' => $customProduct,
]);
}
Полный рабочий пример и реализация доступны в нашем репозитории примеров модулей.
Обработка данных, измененных FormBuilderModifier
Вам нужно реализовать соответствующий [actionAfterCreate<FormName>FormHandler]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionAfterCreateactionAfterUpdate<FormName>FormHandler]({{< relref "/8/modules/concepts/hooks/list-of-hooks/actionAfterUpdate
