Skip to main content

CustomFields

This documentation concerns the correct way to add custom fields to entities.

Important note

Custom fields should NEVER be added to the shop manually. This is incredibly important as we had issues before with this. If custom fields are added manually, it will severely hinder Go-Lives.

Plugin Base Class

Generally, we need to use the different lifecycle events of the plugin system. Custom fields should be added in the "install" method:

Example
<?php

declare(strict_types=1);

namespace Econsor\Shopware\Example;

use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;

final class Example extends Plugin
{
public function install(InstallContext $installContext): void
{
parent::install($installContext);
// Add custom fields
}

public function uninstall(UninstallContext $uninstallContext): void
{
parent::uninstall($uninstallContext);

if ($uninstallContext->keepUserData()) {
// remove custom fields
}
}
}

We will handle this via a dedicated service. This is also the way recommended by Shopware.

CustomFieldService

Let's say we want to add custom fields to the product entity called is_special_product".

Base class

Copy paste this base class into your plugin
final class CustomFieldsInstaller
{
private const CUSTOM_FIELDSET_NAME = ''; // TODO: Add field name here.

private const CUSTOM_FIELDSET = [
// TODO: Add field definition here.
];

public function __construct(
private readonly EntityRepository $customFieldSetRepository,
private readonly EntityRepository $customFieldSetRelationRepository
) {
}

public function install(Context $context): void
{
$this->customFieldSetRepository->upsert([
self::CUSTOM_FIELDSET
], $context);
}

public function addRelations(Context $context): void
{
$this->customFieldSetRelationRepository->upsert(array_map(fn (string $customFieldSetId): array => [
'customFieldSetId' => $customFieldSetId,
'entityName' => '',
], $this->getCustomFieldSetIds($context)), $context);
}

/**
* @return string[]
*/
private function getCustomFieldSetIds(Context $context): array
{
$criteria = new Criteria();

$criteria->addFilter(new EqualsFilter('name', self::CUSTOM_FIELDSET_NAME));

return $this->customFieldSetRepository->searchIds($criteria, $context)->getIds();
}
}

Base variables

Next, fill out the CUSTOM_FIELDSET_NAME constant. Since we want to add a custom field to the product entity, let's call it econsor_product_customfields.

Then, in the addRelations method, define product as the entityname index in the array.

Fieldset array

Now, we look at the CUSTOM_FIELDSET constant. This is the array that defines the custom fieldset. Let's define the set first:

private const CUSTOM_FIELDSET = [
'name' => self::CUSTOM_FIELDSET_NAME,
'config' => [
'label' => [
'en-GB' => 'Econsor Product Configuration',
'de-DE' => 'Econsor Produktkonfiguration',
Defaults::LANGUAGE_SYSTEM => 'Product Configuration'
]
],
'customFields' => []
];

The next step is to define the custom fields themselves. We only have one field here, so it is relatively easy:

'customFields' => [
[
'name' => 'is_special_product',
'type' => CustomFieldTypes::BOOL,
'config' => [
'label' => [
'en-GB' => 'Is special Product',
'de-DE' => 'Ist Spezial Produkt',
Defaults::LANGUAGE_SYSTEM => 'Is special Product'
],
'customFieldPosition' => 1
]
]
]
Finding the correct configuration

If you are ever unsure about any of the variables in this array, what you can do is add the custom field manually to your docker instance and then look in the database.

The table custom_field contains all the information you need.

Make sure you convert the JSON object in the config column to an array before you can use it!

Also don't use static types here, use the constants from the CustomFieldTypes Class.

Implementing the service into your plugin

Add the service and the relevant injection to your plugin's services.xml:

<service id="Econsor\Shopware\Example\Service\CustomFieldsInstaller">
<argument type="service" id="custom_field_set.repository"/>
<argument type="service" id="custom_field_set_relation.repository"/>
</service>

Then fill out the methods in your plugin class:

<?php

declare(strict_types=1);

namespace Econsor\Shopware\Example;

use Shopware\Core\Framework\Plugin;
use Shopware\Core\Framework\Plugin\Context\InstallContext;
use Shopware\Core\Framework\Plugin\Context\UninstallContext;
use Econsor\Shopware\Example\Service\CustomFieldsInstaller;

class Example extends Plugin
{
public function install(InstallContext $installContext): void
{
parent::install($installContext);

$this->getCustomFieldsInstaller()->install($installContext->getContext());
}

public function uninstall(UninstallContext $uninstallContext): void
{
parent::uninstall($uninstallContext);

if ($uninstallContext->keepUserData()) {
// remove custom fields
}
}

public function activate(ActivateContext $activateContext): void
{
$this->getCustomFieldsInstaller()->addRelations($activateContext->getContext());
}

private function getCustomFieldsInstaller(): CustomFieldsInstaller
{
if ($this->container->has(CustomFieldsInstaller::class)) {
return $this->container->get(CustomFieldsInstaller::class);
}

return new CustomFieldsInstaller(
$this->container->get('custom_field_set.repository'),
$this->container->get('custom_field_set_relation.repository')
);
}
}