Configuring Purchase Count Display for 1C-Bitrix
A purchase counter on a product card is a social proof tool. "Bought 847 times" works better than any discount banner. In Bitrix, this data exists in the database but is not displayed anywhere by default — it needs to be extracted from the order tables and wired up to the template.
Where Purchase Data Is Stored
Each order line item is recorded in the b_sale_basket table. Key fields:
-
PRODUCT_ID— info block element ID -
QUANTITY— quantity of units in the order -
ORDER_ID— link to the order
The b_sale_order table contains order statuses. To count real purchases (not abandoned carts), filtering by status is required: the STATUS_ID field in b_sale_order. Typically orders with statuses 'N', 'P', 'F' are counted — depending on the store's configuration.
Query for Counting
Direct SQL to get the purchase count for a specific product:
SELECT SUM(b.QUANTITY) AS total_purchased
FROM b_sale_basket b
INNER JOIN b_sale_order o ON b.ORDER_ID = o.ID
WHERE b.PRODUCT_ID = :product_id
AND o.CANCELED = 'N'
AND o.STATUS_ID IN ('N', 'P', 'F');
Querying b_sale_basket via API: CSaleBasket::GetList() with a filter by PRODUCT_ID, but this method does not filter by order status — you need to join manually or use a direct query via $DB->Query().
Caching the Counter
Computing purchases on every product card view is a bad idea for a high-traffic store. Data is cached in b_iblock_element_prop via a custom PURCHASE_COUNT property of type "Number". An agent updates the values on schedule — hourly or daily:
CIBlockElement::SetPropertyValuesEx(
$elementId,
$iblockId,
['PURCHASE_COUNT' => $totalPurchased]
);
Alternatively — store the counter in b_catalog_element via a separate field, or in b_iblock_element via a UF field UF_PURCHASE_COUNT.
Display in the Template
In the bitrix:catalog.element component template (template.php), add the output:
$purchaseCount = (int)$arResult["PROPERTIES"]["PURCHASE_COUNT"]["VALUE"];
if ($purchaseCount > 0) {
echo '<span class="purchase-count">Purchased ' . $purchaseCount . ' times</span>';
}
For more flexible output (e.g., proper pluralization: "1 purchase", "5 purchases") a pluralization helper function is used.
Real-Time Option
If an up-to-date counter without agent delay is needed — data is loaded via an AJAX request when the card is opened. The component returns only the page structure, and the counter is fetched by a separate request to a controller that runs the SQL and returns JSON. This allows caching the main HTML content of the card independently of the counter.
| Catalog scale | Recommended update | Storage method |
|---|---|---|
| Up to 1,000 products | Every hour (agent) | Info block property |
| 1,000–10,000 products | Once per day | UF field |
| More than 10,000 products | AJAX on open | Direct SQL + Redis |
What Is Included in the Setup
- Analyzing order statuses and determining which statuses count as purchases
- Creating the
PURCHASE_COUNTUF property in the catalog info block - Writing an agent for periodic recalculation across all products
- Adding the counter display to the product card template
- Configuring correct pluralization for the number

