Setting up the display of the number of product purchases in 1C-Bitrix

Our company is engaged in the development, support and maintenance of Bitrix and Bitrix24 solutions of any complexity. From simple one-page sites to complex online stores, CRM systems with 1C and telephony integration. The experience of developers is confirmed by certificates from the vendor.
Our competencies:
Development stages

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_COUNT UF 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