Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
use Ibexa\Contracts\ProductCatalog\Local\LocalProductServiceInterface;
use Ibexa\Contracts\ProductCatalog\Local\Values\Product\ProductVariantCreateStruct;
use Ibexa\Contracts\ProductCatalog\ProductServiceInterface;
use Ibexa\Contracts\ProductCatalog\Values\Content\Query\Criterion\ProductCriterionAdapter;
use Ibexa\Contracts\ProductCatalog\Values\Product\ProductVariantQuery;
use Ibexa\Contracts\ProductCatalog\Values\Product\Query\Criterion;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
Expand Down Expand Up @@ -46,12 +48,24 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$productCode = $input->getArgument('productCode');
$product = $this->productService->getProduct($productCode);

// Get variants
$variantQuery = new ProductVariantQuery(0, 5);
// Get variants filtered by variant codes
$codeQuery = new ProductVariantQuery();
$codeQuery->setVariantCodes(['DESK-red', 'DESK-blue']);
$specificVariants = $this->productService->findProductVariants($product, $codeQuery)->getVariants();

$variants = $this->productService->findProductVariants($product, $variantQuery)->getVariants();
// Get variants with specific attributes
$combinedQuery = new ProductVariantQuery();
$combinedQuery->setAttributesCriterion(
new ProductCriterionAdapter(
new Criterion\LogicalAnd([
new Criterion\ColorAttribute('color', ['red', 'blue']),
new Criterion\IntegerAttribute('size', 42),
])
)
);
$filteredVariants = $this->productService->findProductVariants($product, $combinedQuery)->getVariants();

foreach ($variants as $variant) {
foreach ($specificVariants as $variant) {
$output->writeln($variant->getName());
$attributes = $variant->getDiscriminatorAttributes();
foreach ($attributes as $attribute) {
Expand All @@ -61,12 +75,30 @@ protected function execute(InputInterface $input, OutputInterface $output): int

// Create a variant
$variantCreateStructs = [
new ProductVariantCreateStruct(['color' => 'oak', 'frame_color' => 'white'], 'DESK1'),
new ProductVariantCreateStruct(['color' => 'white', 'frame_color' => 'black'], 'DESK2'),
new ProductVariantCreateStruct(['color' => 'oak', 'frame_color' => 'white'], 'DESK-red'),
new ProductVariantCreateStruct(['color' => 'white', 'frame_color' => 'black'], 'DESK-blue'),
];

$this->localProductService->createProductVariants($product, $variantCreateStructs);

// Search variants across all products
$query = new ProductVariantQuery();
$query->setVariantCodes(['DESK-red', 'DESK-blue']);
$variantList = $this->productService->findVariants($query);

foreach ($variantList->getVariants() as $variant) {
$output->writeln($variant->getName());
}

// Search variants with attribute criterion
$colorQuery = new ProductVariantQuery();
$colorQuery->setAttributesCriterion(
new ProductCriterionAdapter(
new Criterion\ColorAttribute('color', ['red'])
)
);
$redVariants = $this->productService->findVariants($colorQuery);

return self::SUCCESS;
}
}
48 changes: 41 additions & 7 deletions docs/pim/product_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,54 @@

### Product variants

You can access the variants of a product by using `ProductServiceInterface::findProductVariants()`.
#### Searching for variants of a specific product

Check notice on line 61 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L61

[Ibexa.ArticlesInHeadings] Avoid articles in headings.
Raw output
{"message": "[Ibexa.ArticlesInHeadings] Avoid articles in headings.", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 61, "column": 32}}}, "severity": "INFO"}

You can access the variants of a product by using the [`ProductServiceInterface::findProductVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findProductVariants) method.
The method takes the product object and a [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html) object as parameters.

A `ProductVariantQuery` lets you define the offset and limit of the variant query.
The default offset is 0, and limit is 25.
You can filter variants by:

Check notice on line 67 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L67

[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.
Raw output
{"message": "[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 67, "column": 1}}}, "severity": "INFO"}
- variant codes:

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 50, 54) =]]
```

Check notice on line 73 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L73

[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.
Raw output
{"message": "[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 73, "column": 1}}}, "severity": "INFO"}
- product criteria:

To use [Product Search Criteria](product_search_criteria.md) with [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html), wrap it with the [`ProductCriterionAdapter`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Content-Query-Criterion-ProductCriterionAdapter.html) class, as in the example below:

``` php hl_lines="4"
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 55, 66) =]]
```

From a variant ([`ProductVariantInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html)), you can access the attributes that are used to generate the variant by using [`ProductVariantInterface::getDiscriminatorAttributes()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html#method_getDiscriminatorAttributes).

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 49, 52) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 69, 73) =]]
```

From a variant ([`ProductVariantInterface`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html)), you can access the attributes that are used to generate the variant by using `ProductVariantInterface::getDiscriminatorAttributes()`.
#### Searching for variants across all products

To search for variants across all products, use [`ProductServiceInterface::findVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findVariants).
This method takes a [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html) object and returns variants regardless of their base product.

Unlike `findProductVariants()`, which requires a specific product object, `findVariants()` allows you to search the entire variant catalog.

You can filter variants by:

Check notice on line 96 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L96

[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.
Raw output
{"message": "[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 96, "column": 1}}}, "severity": "INFO"}
- variant codes:

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 53, 60) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 83, 87) =]]
```

Check notice on line 102 in docs/pim/product_api.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/pim/product_api.md#L102

[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.
Raw output
{"message": "[Ibexa.Lists] Verify list formatting: Full sentences should start with uppercase and end with a period. Sentence fragments should start with lowercase and have no period.", "location": {"path": "docs/pim/product_api.md", "range": {"start": {"line": 102, "column": 1}}}, "severity": "INFO"}
- product criteria:

To use [Product Search Criteria](product_search_criteria.md) with [`ProductVariantQuery`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Product-ProductVariantQuery.html), wrap it with the [`ProductCriterionAdapter`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-Content-Query-Criterion-ProductCriterionAdapter.html) class, as in the example below:

``` php hl_lines="4"
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 92, 100) =]]
```

#### Creating variants
Expand All @@ -81,7 +115,7 @@
`ProductVariantCreateStruct` specifies the attribute values and the code for the new variant.

``` php
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 62, 68) =]]
[[= include_file('code_samples/api/product_catalog/src/Command/ProductVariantCommand.php', 85, 91) =]]
```

### Product assets
Expand Down
9 changes: 9 additions & 0 deletions docs/release_notes/ibexa_dxp_v5.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ month_change: false

<div class="release-notes" markdown="1">

<!-- draft release notes -->
#### Improved product variant querying

Product variant querying now supports filtering by variant codes and product attribute criteria.

You can now use [`ProductServiceInterface::findVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findVariants) method to search for variants across all products, regardless of their base product.

For more information, see [Product API - Searching variants](product_api.md#searching-for-variants-across-all-products).

[[% set version = 'v5.0.5' %]]

[[= release_note_entry_begin("Ibexa DXP " + version, '2026-01-15', ['Headless', 'Experience', 'Commerce']) =]]
Expand Down
6 changes: 5 additions & 1 deletion docs/search/criteria_reference/product_search_criteria.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

# Product Search Criteria reference

Product Search Criteria are only supported by [Product Search (`ProductServiceInterface::findProduct`)](product_api.md#products).
Product Search Criteria are supported by [product and product variant search](product_api.md#products) with the following methods:

Check notice on line 8 in docs/search/criteria_reference/product_search_criteria.md

View workflow job for this annotation

GitHub Actions / vale

[vale] docs/search/criteria_reference/product_search_criteria.md#L8

[Ibexa.Passive] Try to avoid passive tense, when possible.
Raw output
{"message": "[Ibexa.Passive] Try to avoid passive tense, when possible.", "location": {"path": "docs/search/criteria_reference/product_search_criteria.md", "range": {"start": {"line": 8, "column": 25}}}, "severity": "INFO"}

- `ProductServiceInterface::findProducts()`
- `ProductServiceInterface::findProductVariants()`
- `ProductServiceInterface::findVariants()`

Search Criterion let you filter product by specific attributes, for example, color, availability, or price.

Expand Down
Loading