sulu / product-bundle
Sulu Product Bundle
Requires
- php: >=5.4
- doctrine/orm: 2.5.*
- jackalope/jackalope-doctrine-dbal: ~1.2.0
- jackalope/jackalope-jackrabbit: ~1.2.0
- oro/doctrine-extensions: 1.0.*
- sulu/sulu: ~1.3
- sulu/validation-bundle: ~0.1
- symfony-cmf/routing-bundle: 1.2.*
- willdurand/hateoas-bundle: >=0.3
Requires (Dev)
- evenement/evenement: 2.0.0 as 1.0.0
- phpunit/phpunit: ~4.0.0
- sensio/framework-extra-bundle: ~3.0
- sulu/sulu: ~1.4
- symfony-cmf/testing: ~1.2
- symfony/monolog-bundle: 2.4.*
- symfony/symfony: 2.8.*
- zendframework/zendsearch: @dev
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- 3.0.x-dev
- 0.17.x-dev
- 0.17.6
- 0.17.5
- 0.17.4
- 0.17.3
- 0.17.2
- 0.17.1
- 0.17.0
- 0.16.7
- 0.16.6
- 0.16.5
- 0.16.4
- 0.16.3
- 0.16.2
- 0.16.1
- 0.16.0
- 0.15.2
- 0.15.1
- 0.15.0
- 0.14.0
- 0.13.1
- 0.13.0
- 0.12.6
- 0.12.5
- 0.12.4
- 0.12.3
- 0.12.2
- 0.12.1
- 0.12.0
- 0.11.0
- 0.10.7
- 0.10.6
- 0.10.5
- 0.10.4
- 0.10.3
- 0.10.2
- 0.10.1
- 0.9.9
- 0.9.8
- 0.9.7
- 0.9.6
- 0.9.5
- 0.9.4
- 0.9.3
- 0.9.2
- 0.9.1
- 0.9.0
- 0.8.17
- 0.8.16
- 0.8.15
- 0.8.14
- 0.8.13
- 0.8.12
- 0.8.11
- 0.8.10
- 0.8.9
- 0.8.8
- 0.8.7
- 0.8.6
- 0.8.5
- 0.8.4
- 0.8.3
- 0.8.2
- 0.8.1
- 0.8.0
- 0.7.1
- 0.7
- 0.6.10
- 0.6.9
- 0.6.8
- 0.6.7
- 0.6.6
- 0.6.5
- 0.6.4
- 0.6.3
- 0.6.2
- 0.6.1
- 0.6
- 0.5.2
- 0.5.1
- 0.5.0
- 0.4.4
- 0.4.3
- 0.4.2
- 0.4.1
- 0.4.0
- 0.3.2
- 0.3.1
- 0.2.1
- 0.2.0
- 0.1.0
- 0.0.7
- 0.0.6
- 0.0.5
- 0.0.4
- 0.0.3
- 0.0.2
- 0.0.1
This package is auto-updated.
Last update: 2026-09-21 16:21:47 UTC
README
Product route
The route field of a product lives in the product_details form and in the product_variant
overlay, not in the product template. Its field type and its params are configured once for the
whole project, so a form does not repeat them:
sulu_product: route: type: route # default, e.g. "page_tree_route" for a route below a page params: route_schema: "/products/{implode('-', object)}" # default
params takes any key the configured field type understands and forwards it to the field as-is;
route_schema is the one the route field reads to generate the URL out of the fields tagged
sulu.rlp.part. A param configured here wins over the same param declared in the form XML. Both
forms get the same type and the same params.
route_schema defaults to the value above, so a product URL starts with /products/ without any
configuration. A project overrides that key or adds params of its own, and the default stays for
every key the project does not set.
The same field is added invisibly to every product template, because RoutableDataMapper of the
content package reads the route property off the template metadata. A template declaring its own
url property keeps it and only receives the configured type and params.
Variant URLs
A variant owns its route: the URL field is mandatory on the variant overlay, so every variant carries an address of its own. A product with variants owns none, it is reached through its variants, which is why the field is hidden for that type and the route guard drops one that reaches such a product programmatically.
Variant publishing
A variant is published on its own, from the variants tab of its product: select variants in the list and use "Publishing" in the toolbar, which needs the live permission. Publish skips variants without content in the current locale and variants already published without changes, unpublish only acts on published ones. The list marks unpublished variants and variants shown in a fallback locale, the same way the article list does.
A variant renders its product's content, so it is only live together with its product: publishing a variant is refused while its product is not published in that locale, and unpublishing the product or removing its translation unpublishes its variants there. Publishing the product leaves its variants as they are, and saving a variant does not mark its product as changed.
The action calls POST /admin/api/products/{parentId}/variants/{id}?action=publish (or
unpublish), which answers 409 when the transition is not available, for example unpublishing
a variant that was never published or publishing one whose product is not published. The list
shows the reason for each variant it could not change.
Variant attributes
A family attribute with the "variant" toggle is held by the product that carries the article: a variant, or a product without variants. A product with variants holds only the shared attributes, a variant only the variant attributes. The details form, its schema and the required check follow the product type.
Product in the website
A variant is a page of its own route but has no content of its own: a dimension content enhancer
resolves it with the parent's template, excerpt and SEO data, so content and extension are the
parent's content tab. Its product namespace carries:
product: the parent, withproduct.title, the master data (code,status, ...),product.attributes(its own values),product.associationsandproduct.variants. A product with variants owns no route, so it has noproduct.url.product.currentVariant: the variant itself:title,url,code, ...,attributes(the variant's own values),associations.product.variants: every published variant of the parent withtitle,url,code,statusandposition. A project adds properties, which are merged into these defaults:
sulu_product: variants: properties: image: product.image
A product without variants resolves as itself, with product.url and without variants or
currentVariant. A variant resolved as a reference (a product selection) resolves as itself.
To show a variant's attributes together with its product's, merge them in the template; the variant's value wins on the same attribute:
{% set attributes = sulu_product_merge_attributes(product.attributes, product.currentVariant.attributes|default({})) %}
{% set groups = attributes|sulu_product_attribute_groups %}
To render a single attribute value outside those groups, for example an option value in a variant
switcher, format it with sulu_product_format_attribute_value:
{{ attributeValue|sulu_product_format_attribute_value }}
Association form overrides
The bundle generates a product_associations form with one field per configured
sulu_product.association_types key. A project overrides that form by shipping its own form
XML using the same product_associations key in a directory registered under
sulu_admin.forms.directories — the Sulu skeleton registers config/forms by default.
Rules for the declared fields:
- The field name must be
associations/<type>, where<type>is a configuredsulu_product.association_typeskey. - Only the type
product_selectionis allowed — no other field type maps to product associations. - A
propertiescollection param declares which target properties resolve, in addition to the always-resolvedtitle,url,code,externalIdentifier,status,productFamily,position,imageandshortDescription. The last two are template fields, so a project whoseproduct_details.xmldrops them resolves without them instead of failing. - Declared fields are never regenerated or relabeled, so add
<meta><title>yourself. - Invalid fields fail
cache:warmup.
<!-- <project>/config/forms/product_associations.xml --> <form xmlns="http://schemas.sulu.io/template/template"> <key>product_associations</key> <properties> <property name="associations/alternative" type="product_selection"> <params> <param name="properties" type="collection"> <param name="image" value="image"/> <param name="code" value="code"/> </param> </params> </property> </properties> </form>
Types the project does not declare keep their generated field, label and layout.