From 4ad3be252322992c15fa9098e44b12a82757abd6 Mon Sep 17 00:00:00 2001 From: Michael Telgmann Date: Wed, 30 Sep 2026 16:57:56 +0200 Subject: [PATCH 1/3] feat: Add documentation for the new tab feature for plugin configs --- .../plugins/apps/lifecycle/configuration.md | 27 +++ .../add-plugin-configuration.md | 57 +++++- .../use-plugin-configuration.md | 167 ++++++++++++++++++ guides/upgrades-migrations/index.md | 2 + 4 files changed, 252 insertions(+), 1 deletion(-) diff --git a/guides/plugins/apps/lifecycle/configuration.md b/guides/plugins/apps/lifecycle/configuration.md index 878fc63149..2e57dc7f41 100644 --- a/guides/plugins/apps/lifecycle/configuration.md +++ b/guides/plugins/apps/lifecycle/configuration.md @@ -29,6 +29,33 @@ For development purposes you can use the Administration component to configure p If an app configuration value changes cached Storefront output, mark the corresponding `` or `` with `cache-relevant="true"` in the `config.xml`. See [Cache relevant fields](../../plugins/plugin-fundamentals/add-plugin-configuration.md#cache-relevant-fields) for details. +## Grouping configuration cards into tabs + +Starting with Shopware 6.7.16.0, apps can also group configuration cards into tabs without enabling a feature flag. + +For example, put this content inside the `` element of your app's `Resources/config/config.xml`: + +```xml + + connection + Connection + Verbindung + + API settings + + apiToken + + + + +``` + +Cards outside explicit tabs appear in **General**, and tab navigation is shown only when the configuration has more than one tab. + +The example's stored key is still `DemoApp.config.apiToken`, without the tab name. + +See [Tabs in your configuration](../../plugins/plugin-fundamentals/add-plugin-configuration.md#tabs-in-your-configuration) for a complete XML example and [Reading the configuration form schema](../../plugins/plugin-fundamentals/use-plugin-configuration.md#reading-the-configuration-form-schema) for the Admin API response structure. + ## Reading the configuration values The configuration values are saved as part of the `SystemConfig` and you can use the key `{appName}.config.{fieldName}` to identify the values. There are two possibilities to access the configuration values from your app. If you need those values on your app-backend server, you can read them over the API. If you need the configuration values in your Storefront twig templates you can use the `systemConfig()`-twig function. diff --git a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md index 008bbb27d3..6e3f2cd228 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md @@ -46,7 +46,9 @@ As you now know how to create configurations, you can start to fill it with life The `config.xml` follows a simple syntax. You can organize the content in `` elements. -Every `config.xml` must contain at least one `` element with a `` and at least one `<input-field>`. See the minimum `config.xml` below: +Place cards directly inside `<config>` or, starting with Shopware 6.7.16.0, group them inside `<tab>` elements. + +The following minimum example contains one card with a title and an input field: ::: code-group @@ -68,6 +70,59 @@ Every `config.xml` must contain at least one `<card>` element with a `<title>` a Please make sure to specify the `xsi:noNamespaceSchemaLocation` as shown above and fetch the external resource into your IDE if possible. This enables auto-completion and suggestions for this XML file and will therefore help you to prevent issues and bugs. +### Tabs in your configuration + +::: info +Configuration tabs are available starting with Shopware 6.7.16.0 without a feature flag. +::: + +Use `<tab>` to group related cards, with `<name>` as the technical tab name and `<title>` as its displayed label. + +Translate tab titles with the `lang` attribute, just like card titles. + +The following example combines a card outside any tab with a named tab: + +```xml +<?xml version="1.0" encoding="UTF-8"?> +<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/shopware/shopware/trunk/src/Core/System/SystemConfig/Schema/config.xsd"> + <card> + <title>Basic settings + + enabled + + false + + + + + shipping + Shipping + Versand + + Delivery settings + + deliveryDays + + 3 + + + + +``` + +Cards outside explicit tabs are grouped into a first tab labeled **General**, followed by the explicit tabs in XML order. + +Add more `` elements inside a tab or more `` elements inside `` to organize larger forms. + +Tabs are optional, and existing configurations containing only root-level cards still work. + +The Administration displays the tab navigation only when the schema contains more than one tab. + +Tab and card names do not become part of stored configuration keys, so the fields above remain `SwagBasicExample.config.enabled` and `SwagBasicExample.config.deliveryDays`. + +For custom form consumers, see [Reading the configuration form schema](use-plugin-configuration.md#reading-the-configuration-form-schema). + ### Card Titles A `` `` is translatable, this is managed via the `lang` attribute. diff --git a/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md b/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md index e46b5da98d..23d70d9314 100644 --- a/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md +++ b/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md @@ -153,6 +153,8 @@ Set `salesChannelId` to `null` to apply the configuration to all Sales Channels, In the Administration, use `systemConfigApiService` (wraps system-config endpoints). +Use `getValues()` to read saved values and `getSchema()` to read the tabs, cards, and fields that define the configuration form. + ### Using injection in Vue components ```javascript @@ -202,6 +204,91 @@ async function getPluginConfig() { Your plugin needs the `system_config:read` permission to access this API endpoint. ::: +### Reading the configuration form schema + +Starting with Shopware 6.7.16.0, use `systemConfigApiService.getSchema(domain)` to load the form definition: + +```javascript +const systemConfigApiService = Shopware.Service('systemConfigApiService'); +const domain = 'SwagBasicExample.config'; +const schema = await systemConfigApiService.getSchema(domain); +const values = await systemConfigApiService.getValues(domain); + +for (const tab of schema) { + for (const card of tab.cards) { + for (const element of card.elements) { + const value = values[element.name] ?? element.config.defaultValue; + console.log(tab.name, card.title, element.name, value); + } + } +} +``` + +The schema is an array of tabs, each containing `cards`, whose `elements` contain the field definitions. + +Field names are fully qualified configuration keys, while labels, defaults, and component options are inside `element.config`. + +The schema endpoint supplies definitions; read saved values separately with `getValues()` as above. + +API clients can retrieve the same schema with this request: + +```http +GET /api/_action/system-config/get-schema?domain=SwagBasicExample.config +``` + +Both the schema endpoint and the values endpoint require the `system_config:read` privilege. + +A response excerpt for the [tab example](add-plugin-configuration.md#tabs-in-your-configuration) looks like this: + +```json +[ + { + "name": null, + "title": null, + "cards": [ + { + "title": { "en-GB": "Basic settings" }, + "elements": [ + { + "name": "SwagBasicExample.config.enabled", + "type": "bool", + "config": { + "label": { "en-GB": "Enable integration" }, + "defaultValue": false + }, + "value": null + } + ] + } + ] + }, + { + "name": "shipping", + "title": { "en-GB": "Shipping", "de-DE": "Versand" }, + "cards": [ + { + "title": { "en-GB": "Delivery settings" }, + "elements": [ + { + "name": "SwagBasicExample.config.deliveryDays", + "type": "int", + "config": { + "label": { "en-GB": "Delivery time in days" }, + "defaultValue": 3 + }, + "value": null + } + ] + } + ] + } +] +``` + +The tab with `name: null` and `title: null` represents root-level cards and is displayed as **General** when tab navigation is visible. + +Even configurations without explicit `<tab>` elements return a tab array containing their cards. + </Tab> <Tab title="Storefront"> @@ -250,3 +337,83 @@ export default class ExamplePlugin extends PluginBaseClass { </Tab> </Tabs> + +## Migrating custom configuration form consumers + +Starting with Shopware 6.7.16.0, migrate code that loads or modifies configuration form definitions to the tab structure before the legacy APIs are removed in Shopware 6.8. + +### Administration and API clients + +| Legacy API | Replacement | +| :----------------------------------------- | :------------------------------------------- | +| `systemConfigApiService.getConfig(domain)` | `systemConfigApiService.getSchema(domain)` | +| `GET /api/_action/system-config/schema` | `GET /api/_action/system-config/get-schema` | +| `sw-system-config` data property `config` | `sw-system-config` data property `schema` | +| Iteration over `config[].elements[]` | Iteration over `schema[].cards[].elements[]` | + +The legacy schema endpoint also requires `system_config:read`, so integrations that previously called it without that privilege must update their ACL role. + +Shopware 6.7 retains compatibility for the component's legacy `config` property and decorated `getConfig()` methods, but new customizations should use `schema` and `getSchema()`. + +For example, an override of `sw-system-config` can modify a field after the parent loads the schema: + +```javascript +Shopware.Component.override('sw-system-config', { + methods: { + async readConfig() { + await this.$super('readConfig'); + + for (const tab of this.schema) { + for (const card of tab.cards) { + const field = card.elements.find( + (element) => element.name === 'SwagBasicExample.config.deliveryDays', + ); + + if (field) { + field.config.disabled = true; + } + } + } + }, + }, +}); +``` + +### PHP configuration definitions + +Continue injecting `Shopware\Core\System\SystemConfig\Service\ConfigurationService` and replace its legacy getters: + +| Deprecated method | Replacement | +| :------------------------------------------------------------- | :---------------------------------------------------------------------- | +| `getConfiguration($domain, $context)` | `getSystemConfigDefinition($domain, $context)` | +| `getResolvedConfiguration($domain, $context, $salesChannelId)` | `getResolvedSystemConfigDefinition($domain, $context, $salesChannelId)` | + +The replacement methods return a list of `SystemConfigTab` DTOs containing `SystemConfigCard` and `SystemConfigElement` DTOs from the `Shopware\Core\System\SystemConfig\DTO` namespace. + +Access DTO properties and traverse tabs before cards, instead of reading the legacy array of cards. + +With an injected `$configurationService`, a Shopware `$context`, and an optional `$salesChannelId`, read resolved field values like this: + +```php +$tabs = $configurationService->getResolvedSystemConfigDefinition( + 'SwagBasicExample.config', + $context, + $salesChannelId, +); + +$values = []; + +foreach ($tabs as $tab) { + foreach ($tab->cards as $card) { + foreach ($card->elements as $element) { + $values[$element->name] = $element->value; + } + } +} +``` + +Use `getSystemConfigDefinition()` when you only need definitions, and `getResolvedSystemConfigDefinition()` when field values should include saved values for the selected sales channel with fallback to XML defaults. + +Field options remain available through `$element->config`, for example `$element->config['defaultValue']`. + +Reading saved values through `SystemConfigService::get()`, `systemConfigApiService.getValues()`, or the Twig `config()` function uses the same configuration keys as before. diff --git a/guides/upgrades-migrations/index.md b/guides/upgrades-migrations/index.md index 3deec6e3dd..a5d8f4df8b 100644 --- a/guides/upgrades-migrations/index.md +++ b/guides/upgrades-migrations/index.md @@ -65,6 +65,8 @@ To reduce long-term upgrade cost: * Keep database migrations idempotent. * Track deprecations continuously—do not batch them. +For custom system configuration forms, see [Migrating custom configuration form consumers](../plugins/plugins/plugin-fundamentals/use-plugin-configuration.md#migrating-custom-configuration-form-consumers) for the tab schema introduced in Shopware 6.7.16.0 and legacy APIs removed in Shopware 6.8. + The Shopware CLI upgrade wizard can also be useful when you maintain extensions: assemble the extensions in a representative Composer-managed test project, select the target Shopware version, and use the extension queue and generated report to identify updates, blockers, and items that need manual review. This does not replace testing the extension itself against the target Shopware version. ### Custom plugins From ca943378dce3b92e46fd1f9219ae1cf913415064 Mon Sep 17 00:00:00 2001 From: Michael Telgmann <m.telgmann@shopware.com> Date: Wed, 28 Oct 2026 17:54:35 +0100 Subject: [PATCH 2/3] rework LLM text --- .../plugins/apps/lifecycle/configuration.md | 50 +++++++------------ .../add-plugin-configuration.md | 2 +- guides/upgrades-migrations/index.md | 2 - 3 files changed, 18 insertions(+), 36 deletions(-) diff --git a/guides/plugins/apps/lifecycle/configuration.md b/guides/plugins/apps/lifecycle/configuration.md index 2e57dc7f41..7704012745 100644 --- a/guides/plugins/apps/lifecycle/configuration.md +++ b/guides/plugins/apps/lifecycle/configuration.md @@ -13,56 +13,39 @@ Configurations for apps adhere to the same schema as [Plugin Configurations](../ ## Overview -To offer configuration possibilities to your users you can provide a `config.xml` file that describes your configuration options. You can find detailed information about the possibilities and the structure of the `config.xml` in the according documentation page. To include a `config.xml` file in your app put it into the `Resources/config` folder: +To offer configuration possibilities to your users you can provide a `config.xml` file that describes your configuration options. +You can find detailed information about the possibilities and the structure of the `config.xml` in the according documentation page. +To include a `config.xml` file in your app put it into the `Resources/config` folder: ```text ... └── DemoApp └── Resources - └── config + └── config └── config.xml └── manifest.xml ``` The configuration page will be displayed in the Administration under `Extensions > My extensions`. +See [plugin documentation](../../plugins/plugin-fundamentals/add-plugin-configuration.md) for more details and examples. For development purposes you can use the Administration component to configure plugins to provide configuration for your app, therefore use the URL `{APP_URL}/admin#/sw/extension/config/{appName}`. -If an app configuration value changes cached Storefront output, mark the corresponding `<input-field>` or `<component>` with `cache-relevant="true"` in the `config.xml`. See [Cache relevant fields](../../plugins/plugin-fundamentals/add-plugin-configuration.md#cache-relevant-fields) for details. - -## Grouping configuration cards into tabs - -Starting with Shopware 6.7.16.0, apps can also group configuration cards into tabs without enabling a feature flag. - -For example, put this content inside the `<config>` element of your app's `Resources/config/config.xml`: - -```xml -<tab> - <name>connection</name> - <title>Connection - Verbindung - - API settings - - apiToken - - - - -``` - -Cards outside explicit tabs appear in **General**, and tab navigation is shown only when the configuration has more than one tab. - -The example's stored key is still `DemoApp.config.apiToken`, without the tab name. - -See [Tabs in your configuration](../../plugins/plugin-fundamentals/add-plugin-configuration.md#tabs-in-your-configuration) for a complete XML example and [Reading the configuration form schema](../../plugins/plugin-fundamentals/use-plugin-configuration.md#reading-the-configuration-form-schema) for the Admin API response structure. +If an app configuration value changes cached Storefront output, mark the corresponding `` or `` with `cache-relevant="true"` in the `config.xml`. +See [Cache relevant fields](../../plugins/plugin-fundamentals/add-plugin-configuration.md#cache-relevant-fields) for details. ## Reading the configuration values -The configuration values are saved as part of the `SystemConfig` and you can use the key `{appName}.config.{fieldName}` to identify the values. There are two possibilities to access the configuration values from your app. If you need those values on your app-backend server, you can read them over the API. If you need the configuration values in your Storefront twig templates you can use the `systemConfig()`-twig function. +The configuration values are saved as part of the `SystemConfig` and you can use the key `{appName}.config.{fieldName}` to identify the values. +There are two possibilities to access the configuration values from your app. +If you need those values on your app-backend server, you can read them over the API. +If you need the configuration values in your Storefront twig templates you can use the `systemConfig()`-twig function. ### Reading the config over the API -To access your apps configuration over the API make a GET request against the `/api/_action/system-config` route. You have to add the prefix for your configuration as the `domain` query parameter. Optionally you can provide a `SalesChannelId`, if you want to read the values for a specific SalesChannel, as the `salesChannelId` query param. The API call will return a JSON-Object containing all of your configuration values. A sample Request and Response may look like this. +To access your apps configuration over the API make a GET request against the `/api/_action/system-config` route. +You have to add the prefix for your configuration as the `domain` query parameter. +Optionally you can provide a `SalesChannelId`, if you want to read the values for a specific SalesChannel, as the `salesChannelId` query param. +The API call will return a JSON-Object containing all of your configuration values. A sample Request and Response may look like this. ```txt GET /api/_action/system-config?domain=DemoApp.config&salesChannelId=98432def39fc4624b33213a56b8c944d @@ -111,7 +94,8 @@ App scripts provide access to the [`config` service](../../../../resources/refer Note that app scripts were introduced in Shopware 6.4.8.0, and are not supported in previous versions. ::: -The `config` service provides an `app()` method, that can be used to access your app's configuration. When using this method you don't need to provide the `{appName}.config` prefix and your app does not need any additional permissions. +The `config` service provides an `app()` method, that can be used to access your app's configuration. +When using this method you don't need to provide the `{appName}.config` prefix and your app does not need any additional permissions. ```twig {% set configValue = services.config.app('field1') %} diff --git a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md index 6e3f2cd228..3269867933 100644 --- a/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md +++ b/guides/plugins/plugins/plugin-fundamentals/add-plugin-configuration.md @@ -73,7 +73,7 @@ This enables auto-completion and suggestions for this XML file and will therefor ### Tabs in your configuration ::: info -Configuration tabs are available starting with Shopware 6.7.16.0 without a feature flag. +Configuration tabs are available starting with Shopware 6.7.16.0. ::: Use `` to group related cards, with `` as the technical tab name and `` as its displayed label. diff --git a/guides/upgrades-migrations/index.md b/guides/upgrades-migrations/index.md index a5d8f4df8b..3deec6e3dd 100644 --- a/guides/upgrades-migrations/index.md +++ b/guides/upgrades-migrations/index.md @@ -65,8 +65,6 @@ To reduce long-term upgrade cost: * Keep database migrations idempotent. * Track deprecations continuously—do not batch them. -For custom system configuration forms, see [Migrating custom configuration form consumers](../plugins/plugins/plugin-fundamentals/use-plugin-configuration.md#migrating-custom-configuration-form-consumers) for the tab schema introduced in Shopware 6.7.16.0 and legacy APIs removed in Shopware 6.8. - The Shopware CLI upgrade wizard can also be useful when you maintain extensions: assemble the extensions in a representative Composer-managed test project, select the target Shopware version, and use the extension queue and generated report to identify updates, blockers, and items that need manual review. This does not replace testing the extension itself against the target Shopware version. ### Custom plugins From e8ed3e592fb93273d3adfb003a81dc607f219300 Mon Sep 17 00:00:00 2001 From: Michael Telgmann <m.telgmann@shopware.com> Date: Wed, 28 Oct 2026 17:59:28 +0100 Subject: [PATCH 3/3] rework LLM text for plugin config --- .../use-plugin-configuration.md | 92 ++----------------- 1 file changed, 8 insertions(+), 84 deletions(-) diff --git a/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md b/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md index 23d70d9314..4b315dc98f 100644 --- a/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md +++ b/guides/plugins/plugins/plugin-fundamentals/use-plugin-configuration.md @@ -7,13 +7,14 @@ nav: # Use Plugin Configuration -The [Add a Plugin Configuration Guide](add-plugin-configuration.md) shows how to define configuration options in your plugins. This guide helps you to use them in your plugin, showing you how to read plugin configuration values in PHP, Administration JavaScript, and Storefront code. +The [Add a Plugin Configuration Guide](add-plugin-configuration.md) shows how to define configuration options in your plugins. +This guide helps you to use them in your plugin, showing you how to read plugin configuration values in PHP, Administration JavaScript, and Storefront code. ## Prerequisites - First, review the [Plugin Base Guide](../plugin-base-guide.md) - Then define a plugin configuration field in [Add plugin configuration](add-plugin-configuration.md) -- Get familiar with the [Listening to events](../framework/event/listening-to-events.md) guide, as in this example the configuration is read inside of a subscriber +- Get familiar with the [Listening to events](../framework/event/listening-to-events.md) guide, as in this example the configuration is read inside a subscriber The example plugin includes a subscriber that listens to the `product.loaded` event and is called every time a product is loaded. @@ -122,9 +123,12 @@ class MySubscriber implements EventSubscriberInterface The `SystemConfigService` is now available in your subscriber. -Use the `get` method to read configuration values. Calling `$this->systemConfigService->get('example')` would be ambiguous — multiple plugins could define a field with the same technical name. +Use the `get` method to read configuration values. +Calling `$this->systemConfigService->get('example')` would be ambiguous — multiple plugins could define a field with the same technical name. -To avoid conflicts, plugin configurations are always prefixed. By default, the pattern is the following: `<BundleName>.config.<configName>`. Thus, it would be `SwagBasicExample.config.example` here. +To avoid conflicts, plugin configurations are always prefixed. +By default, the pattern is the following: `<BundleName>.config.<configName>`. +Thus, it would be `SwagBasicExample.config.example` here. ```php // <plugin root>/src/Subscriber/MySubscriber.php @@ -337,83 +341,3 @@ export default class ExamplePlugin extends PluginBaseClass { </Tab> </Tabs> - -## Migrating custom configuration form consumers - -Starting with Shopware 6.7.16.0, migrate code that loads or modifies configuration form definitions to the tab structure before the legacy APIs are removed in Shopware 6.8. - -### Administration and API clients - -| Legacy API | Replacement | -| :----------------------------------------- | :------------------------------------------- | -| `systemConfigApiService.getConfig(domain)` | `systemConfigApiService.getSchema(domain)` | -| `GET /api/_action/system-config/schema` | `GET /api/_action/system-config/get-schema` | -| `sw-system-config` data property `config` | `sw-system-config` data property `schema` | -| Iteration over `config[].elements[]` | Iteration over `schema[].cards[].elements[]` | - -The legacy schema endpoint also requires `system_config:read`, so integrations that previously called it without that privilege must update their ACL role. - -Shopware 6.7 retains compatibility for the component's legacy `config` property and decorated `getConfig()` methods, but new customizations should use `schema` and `getSchema()`. - -For example, an override of `sw-system-config` can modify a field after the parent loads the schema: - -```javascript -Shopware.Component.override('sw-system-config', { - methods: { - async readConfig() { - await this.$super('readConfig'); - - for (const tab of this.schema) { - for (const card of tab.cards) { - const field = card.elements.find( - (element) => element.name === 'SwagBasicExample.config.deliveryDays', - ); - - if (field) { - field.config.disabled = true; - } - } - } - }, - }, -}); -``` - -### PHP configuration definitions - -Continue injecting `Shopware\Core\System\SystemConfig\Service\ConfigurationService` and replace its legacy getters: - -| Deprecated method | Replacement | -| :------------------------------------------------------------- | :---------------------------------------------------------------------- | -| `getConfiguration($domain, $context)` | `getSystemConfigDefinition($domain, $context)` | -| `getResolvedConfiguration($domain, $context, $salesChannelId)` | `getResolvedSystemConfigDefinition($domain, $context, $salesChannelId)` | - -The replacement methods return a list of `SystemConfigTab` DTOs containing `SystemConfigCard` and `SystemConfigElement` DTOs from the `Shopware\Core\System\SystemConfig\DTO` namespace. - -Access DTO properties and traverse tabs before cards, instead of reading the legacy array of cards. - -With an injected `$configurationService`, a Shopware `$context`, and an optional `$salesChannelId`, read resolved field values like this: - -```php -$tabs = $configurationService->getResolvedSystemConfigDefinition( - 'SwagBasicExample.config', - $context, - $salesChannelId, -); - -$values = []; - -foreach ($tabs as $tab) { - foreach ($tab->cards as $card) { - foreach ($card->elements as $element) { - $values[$element->name] = $element->value; - } - } -} -``` - -Use `getSystemConfigDefinition()` when you only need definitions, and `getResolvedSystemConfigDefinition()` when field values should include saved values for the selected sales channel with fallback to XML defaults. - -Field options remain available through `$element->config`, for example `$element->config['defaultValue']`. - -Reading saved values through `SystemConfigService::get()`, `systemConfigApiService.getValues()`, or the Twig `config()` function uses the same configuration keys as before.