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:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What would happen if you added a tab before the sentence to increase indentation (the sentence is subordinate to the bullet above)?

Same applies to code snippet and the following sentence, and other occurrences of the same issue 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 the [`ProductVariantInterface::getDiscriminatorAttributes()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-Values-ProductVariantInterface.html#method_getDiscriminatorAttributes) method.

``` 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 the [`ProductServiceInterface::findVariants()`](/api/php_api/php_api_reference/classes/Ibexa-Contracts-ProductCatalog-ProductServiceInterface.html#method_findVariants) method.
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 the [`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