| name | extends-form |
| description | Expose a custom field in an existing Sylius admin form (Product, Taxon, Channel, …) via a Symfony FormTypeExtension, Twig hook and translation |
| argument-hint | [TargetModel] [FieldName] |
| allowed-tools | AskUserQuestion, Bash, Read, Edit, Write, Glob, Grep |
Extend a Sylius admin form
Ask the user if not provided:
Prerequisites:
- The field must exist on the entity. Run
/sylius-plugin:extends-model first for a Sylius core entity, or add the column on your own resource.
- For an entity-autocomplete field type, run
/sylius-plugin:add-autocomplete first so {Related}AutocompleteType exists.
1. Identify the target FormType
vendor/bin/console sylius:debug:resource sylius.{target_model_snake}
The classes.form row in the output is the FormType FQCN used by the admin. Use it directly as the use statement and as the getExtendedTypes() return. Without an argument, the command lists every resource alias.
2. Create the FormTypeExtension
src/Form/Extension/{TargetModel}/{TargetModel}TypeExtension.php:
<?php
declare(strict_types=1);
namespace $SYLIUS_NAMESPACE\Form\Extension\{TargetModel};
use {TargetFormFqcn};
use Symfony\Component\Form\AbstractTypeExtension;
use Symfony\Component\Form\Extension\Core\Type\{FieldType};
use Symfony\Component\Form\FormBuilderInterface;
final class {TargetModel}TypeExtension extends AbstractTypeExtension
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('{field_name}', {FieldType}::class, [
'label' => '${SYLIUS_PREFIX}.form.{target_model_snake}.{field_name}',
'required' => {required},
]);
}
public static function getExtendedTypes(): iterable
{
return [{TargetModel}Type::class];
}
}
3. Register the service
Add to config/services.yaml:
services:
${SYLIUS_PREFIX}.form.extension.{target_model_snake}_type:
class: $SYLIUS_NAMESPACE\Form\Extension\{TargetModel}\{TargetModel}TypeExtension
tags:
- { name: form.type_extension }
4. Create the Twig template
templates/admin/{target_model_snake}/form/sections/{section}/{field_name}.html.twig:
{{ form_row(hookable_metadata.context.form.{field_name}) }}
5. Register the Twig hooks (split by action)
One file per action under config/twig_hooks/admin/{target_model_snake}/ at the plugin root. Loaded via the plugin's config/config.yaml (add - { resource: "twig_hooks/**/*.yaml" } to its imports if not already there).
If files already exist for this target (from a previous extends-form run), add the new entry under the existing hook key — do not overwrite.
config/twig_hooks/admin/{target_model_snake}/create.yaml:
sylius_twig_hooks:
hooks:
'sylius_admin.{target_model_snake}.create.content.form.sections.{section}':
{field_name}:
template: '${SYLIUS_TEMPLATE_NS}admin/{target_model_snake}/form/sections/{section}/{field_name}.html.twig'
priority: -100
config/twig_hooks/admin/{target_model_snake}/update.yaml — same content, replace .create. with .update..
A negative priority places the field at the bottom of the section without renumbering existing entries.
6. Add the translation
Get the project's default locale:
vendor/bin/console debug:container --parameter=kernel.default_locale
Add to translations/messages.{locale}.yaml:
${SYLIUS_PREFIX}:
form:
{target_model_snake}:
{field_name}: '{Field label}'
7. Clear cache
vendor/bin/console cache:clear
8. Verify
Next steps
- Extending a Sylius core entity with a column →
/sylius-plugin:extends-model (typical paired workflow: extend the entity, then expose the field here)
- Using an autocomplete type as the field →
/sylius-plugin:add-autocomplete
- Displaying the new field in the admin grid →
/sylius-plugin:extends-grid